Repository: mattn/go-sqlite3
Pull request #900 (2021-01-02 03:07:17)

Export sqlite3_column_table_name
Will help fix https://github.com/rqlite/rqlite/issues/530

codecov-io: # [Codecov](https://codecov.io/gh/mattn/go-sqlite3/pull/900?src=pr&el=h1) Report
> Merging [#900](https://codecov.io/gh/mattn/go-sqlite3/pull/900?src=pr&el=desc) (4823017) into [master](https://codecov.io/gh/mattn/go-sqlite3/commit/3cbdae750e52afa881060732446298f98131e834?el=desc) (3cbdae7) will **increase** coverage by `0.03%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/mattn/go-sqlite3/pull/900/graphs/tree.svg?width=650&height=150&src=pr&token=iuTYvLwNp6)](https://codecov.io/gh/mattn/go-sqlite3/pull/900?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #900      +/-   ##
==========================================
+ Coverage   46.80%   46.84%   +0.03%     
==========================================
  Files          11       11              
  Lines        1457     1458       +1     
==========================================
+ Hits          682      683       +1     
  Misses        640      640              
  Partials      135      135              
```


| [Impacted Files](https://codecov.io/gh/mattn/go-sqlite3/pull/900?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [sqlite3.go](https://codecov.io/gh/mattn/go-sqlite3/pull/900/diff?src=pr&el=tree#diff-c3FsaXRlMy5nbw==) | `53.11% <100.00%> (+0.05%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/mattn/go-sqlite3/pull/900?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/mattn/go-sqlite3/pull/900?src=pr&el=footer). Last update [3cbdae7...4823017](https://codecov.io/gh/mattn/go-sqlite3/pull/900?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

otoolep: Any plans to merge this? Or do I need to proceed with my own fork?
otoolep: Still no plan to merge this into the master branch?

Patch:
diff --git a/.github/workflows/go.yaml b/.github/workflows/go.yaml
index 3ef6e38..1c86d2a 100644
--- a/.github/workflows/go.yaml
+++ b/.github/workflows/go.yaml
@@ -29,7 +29,7 @@ jobs:
 
       - name: Get Build Tools
         run: |
-          go get github.com/ory/go-acc
+          GO111MODULE=on go get github.com/ory/go-acc
 
       - name: Add $GOPATH/bin to $PATH
         run: |
@@ -83,7 +83,7 @@ jobs:
 
       - name: Get Build Tools
         run: |
-          go get -u github.com/ory/go-acc
+          GO111MODULE=on go get -u github.com/ory/go-acc
         shell: msys2 {0}
 
       - name: Add $GOPATH/bin to $PATH
diff --git a/_example/fuzz/fuzz_openexec.go b/_example/fuzz/fuzz_openexec.go
new file mode 100644
index 0000000..5326044
--- /dev/null
+++ b/_example/fuzz/fuzz_openexec.go
@@ -0,0 +1,30 @@
+package sqlite3_fuzz
+
+import (
+	"bytes"
+	"database/sql"
+	"io/ioutil"
+
+	_ "github.com/mattn/go-sqlite3"
+)
+
+func FuzzOpenExec(data []byte) int {
+	sep := bytes.IndexByte(data, 0)
+	if sep <= 0 {
+		return 0
+	}
+	err := ioutil.WriteFile("/tmp/fuzz.db", data[sep+1:], 0644)
+	if err != nil {
+		return 0
+	}
+	db, err := sql.Open("sqlite3", "/tmp/fuzz.db")
+	if err != nil {
+		return 0
+	}
+	defer db.Close()
+	_, err = db.Exec(string(data[:sep-1]))
+	if err != nil {
+		return 0
+	}
+	return 1
+}
diff --git a/sqlite3.go b/sqlite3.go
index 552a2ab..8d48faa 100644
--- a/sqlite3.go
+++ b/sqlite3.go
@@ -19,6 +19,7 @@ package sqlite3
 #cgo CFLAGS: -DSQLITE_OMIT_DEPRECATED
 #cgo CFLAGS: -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1
 #cgo CFLAGS: -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT
+#cgo CFLAGS: -DSQLITE_ENABLE_COLUMN_METADATA
 #cgo CFLAGS: -Wno-deprecated-declarations
 #cgo linux,!android CFLAGS: -DHAVE_PREAD64=1 -DHAVE_PWRITE64=1
 #ifndef USE_LIBSQLITE3
@@ -1676,7 +1677,7 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
 	//
 	// Because default is NORMAL this statement is always executed
 	if err := exec(fmt.Sprintf("PRAGMA synchronous = %s;", synchronousMode)); err != nil {
-		C.sqlite3_close_v2(db)
+		conn.Close()
 		return nil, err
 	}
 
@@ -2014,6 +2015,14 @@ func (s *SQLiteStmt) Readonly() bool {
 	return C.sqlite3_stmt_readonly(s.s) == 1
 }
 
+// ColumnTableName returns the table that is the origin of a particular result
+// column in a SELECT statement.
+//
+// See https://www.sqlite.org/c3ref/column_database_name.html
+func (s *SQLiteStmt) ColumnTableName(n int) string {
+        return C.GoString(C.sqlite3_column_table_name(s.s, C.int(n)))
+}
+
 // Close the rows.
 func (rc *SQLiteRows) Close() error {
 	rc.s.mu.Lock()


Test patch:
diff --git a/sqlite3_test.go b/sqlite3_test.go
index 878ec49..e74c35e 100644
--- a/sqlite3_test.go
+++ b/sqlite3_test.go
@@ -1604,6 +1604,40 @@ func TestDeclTypes(t *testing.T) {
 	}
 }
 
+func TestColumnTableName(t *testing.T) {
+        d := SQLiteDriver{}
+        conn, err := d.Open(":memory:")
+        if err != nil {
+                t.Fatal("failed to get database connection:", err)
+        }
+        defer conn.Close()
+        sqlite3conn := conn.(*SQLiteConn)
+
+        _, err = sqlite3conn.Exec(`CREATE TABLE foo (name string)`, nil)
+        if err != nil {
+                t.Fatal("Failed to create table:", err)
+        }
+        _, err = sqlite3conn.Exec(`CREATE TABLE bar (name string)`, nil)
+        if err != nil {
+                t.Fatal("Failed to create table:", err)
+        }
+
+        stmt, err := sqlite3conn.Prepare(`SELECT * FROM foo JOIN bar ON foo.name = bar.name`)
+        if err != nil {
+                t.Fatal(err)
+        }
+
+        if exp, got := "foo", stmt.(*SQLiteStmt).ColumnTableName(0); exp != got {
+                t.Fatalf("Incorrect table name returned expected: %s, got: %s", exp, got)
+        }
+        if exp, got := "bar", stmt.(*SQLiteStmt).ColumnTableName(1); exp != got {
+                t.Fatalf("Incorrect table name returned expected: %s, got: %s", exp, got)
+        }
+        if exp, got := "", stmt.(*SQLiteStmt).ColumnTableName(2); exp != got {
+                t.Fatalf("Incorrect table name returned expected: %s, got: %s", exp, got)
+        }
+}
+
 func TestPinger(t *testing.T) {
 	db, err := sql.Open("sqlite3", ":memory:")
 	if err != nil {