You've already forked woodpecker
							
							
				mirror of
				https://github.com/woodpecker-ci/woodpecker.git
				synced 2025-10-30 23:27:39 +02:00 
			
		
		
		
	restart build will always fork; update sqlite
This commit is contained in:
		| @@ -93,12 +93,6 @@ pipeline: | ||||
|     when: | ||||
|       event: tag | ||||
|  | ||||
|   notify: | ||||
|     image: plugins/gitter | ||||
|     secrets: [ gitter_webhook ] | ||||
|     when: | ||||
|       status: [ success, failure ] | ||||
|  | ||||
| services: | ||||
|   postgres: | ||||
|     image: postgres:9.6 | ||||
|   | ||||
| @@ -114,17 +114,6 @@ func Load(mux *httptreemux.ContextMux, middleware ...gin.HandlerFunc) http.Handl | ||||
| 	e.POST("/hook", server.PostHook) | ||||
| 	e.POST("/api/hook", server.PostHook) | ||||
|  | ||||
| 	ws := e.Group("/ws") | ||||
| 	{ | ||||
| 		ws.GET("/feed", server.EventStream) | ||||
| 		ws.GET("/logs/:owner/:name/:build/:number", | ||||
| 			session.SetRepo(), | ||||
| 			session.SetPerm(), | ||||
| 			session.MustPull, | ||||
| 			server.LogStream, | ||||
| 		) | ||||
| 	} | ||||
|  | ||||
| 	sse := e.Group("/stream") | ||||
| 	{ | ||||
| 		sse.GET("/events", server.EventStreamSSE) | ||||
|   | ||||
| @@ -453,7 +453,6 @@ func PostBuild(c *gin.Context) { | ||||
|  | ||||
| 	remote_ := remote.FromContext(c) | ||||
| 	repo := session.Repo(c) | ||||
| 	fork := c.DefaultQuery("fork", "false") | ||||
|  | ||||
| 	num, err := strconv.Atoi(c.Param("number")) | ||||
| 	if err != nil { | ||||
| @@ -500,58 +499,28 @@ func PostBuild(c *gin.Context) { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// must not restart a running build | ||||
| 	if build.Status == model.StatusPending || build.Status == model.StatusRunning { | ||||
| 		c.String(409, "Cannot re-start a started build") | ||||
| 		return | ||||
| 	build.ID = 0 | ||||
| 	build.Number = 0 | ||||
| 	build.Parent = num | ||||
| 	build.Status = model.StatusPending | ||||
| 	build.Started = 0 | ||||
| 	build.Finished = 0 | ||||
| 	build.Enqueued = time.Now().UTC().Unix() | ||||
| 	build.Error = "" | ||||
| 	build.Deploy = c.DefaultQuery("deploy_to", build.Deploy) | ||||
|  | ||||
| 	event := c.DefaultQuery("event", build.Event) | ||||
| 	if event == model.EventPush || | ||||
| 		event == model.EventPull || | ||||
| 		event == model.EventTag || | ||||
| 		event == model.EventDeploy { | ||||
| 		build.Event = event | ||||
| 	} | ||||
|  | ||||
| 	// forking the build creates a duplicate of the build | ||||
| 	// and then executes. This retains prior build history. | ||||
| 	if forkit, _ := strconv.ParseBool(fork); forkit { | ||||
| 		build.ID = 0 | ||||
| 		build.Number = 0 | ||||
| 		build.Parent = num | ||||
| 		build.Status = model.StatusPending | ||||
| 		build.Started = 0 | ||||
| 		build.Finished = 0 | ||||
| 		build.Enqueued = time.Now().UTC().Unix() | ||||
| 		build.Error = "" | ||||
| 		build.Deploy = c.DefaultQuery("deploy_to", build.Deploy) | ||||
|  | ||||
| 		event := c.DefaultQuery("event", build.Event) | ||||
| 		if event == model.EventPush || | ||||
| 			event == model.EventPull || | ||||
| 			event == model.EventTag || | ||||
| 			event == model.EventDeploy { | ||||
| 			build.Event = event | ||||
| 		} | ||||
|  | ||||
| 		err = store.CreateBuild(c, build) | ||||
| 		if err != nil { | ||||
| 			c.String(500, err.Error()) | ||||
| 			return | ||||
| 		} | ||||
| 	} else { | ||||
| 		// todo move this to database tier | ||||
| 		// and wrap inside a transaction | ||||
| 		build.Status = model.StatusPending | ||||
| 		build.Started = 0 | ||||
| 		build.Finished = 0 | ||||
| 		build.Enqueued = time.Now().UTC().Unix() | ||||
| 		build.Error = "" | ||||
|  | ||||
| 		err = store.FromContext(c).ProcClear(build) | ||||
| 		if err != nil { | ||||
| 			c.AbortWithStatus(500) | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		err = store.UpdateBuild(c, build) | ||||
| 		if err != nil { | ||||
| 			c.AbortWithStatus(500) | ||||
| 			return | ||||
| 		} | ||||
| 	err = store.CreateBuild(c, build) | ||||
| 	if err != nil { | ||||
| 		c.String(500, err.Error()) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// Read query string parameters into buildParams, exclude reserved params | ||||
|   | ||||
							
								
								
									
										188
									
								
								server/stream.go
									
									
									
									
									
								
							
							
						
						
									
										188
									
								
								server/stream.go
									
									
									
									
									
								
							| @@ -16,196 +16,8 @@ import ( | ||||
|  | ||||
| 	"github.com/Sirupsen/logrus" | ||||
| 	"github.com/gin-gonic/gin" | ||||
| 	"github.com/gorilla/websocket" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	// Time allowed to write the file to the client. | ||||
| 	writeWait = 5 * time.Second | ||||
|  | ||||
| 	// Time allowed to read the next pong message from the client. | ||||
| 	pongWait = 60 * time.Second | ||||
|  | ||||
| 	// Send pings to client with this period. Must be less than pongWait. | ||||
| 	pingPeriod = 30 * time.Second | ||||
|  | ||||
| 	// upgrader defines the default behavior for upgrading the websocket. | ||||
| 	upgrader = websocket.Upgrader{ | ||||
| 		ReadBufferSize:  1024, | ||||
| 		WriteBufferSize: 1024, | ||||
| 		CheckOrigin: func(r *http.Request) bool { | ||||
| 			return true | ||||
| 		}, | ||||
| 	} | ||||
| ) | ||||
|  | ||||
| func reader(ws *websocket.Conn) { | ||||
| 	defer ws.Close() | ||||
| 	ws.SetReadLimit(512) | ||||
| 	ws.SetReadDeadline(time.Now().Add(pongWait)) | ||||
| 	ws.SetPongHandler(func(string) error { | ||||
| 		ws.SetReadDeadline(time.Now().Add(pongWait)) | ||||
| 		return nil | ||||
| 	}) | ||||
| 	for { | ||||
| 		_, _, err := ws.ReadMessage() | ||||
| 		if err != nil { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func LogStream(c *gin.Context) { | ||||
| 	repo := session.Repo(c) | ||||
| 	buildn, _ := strconv.Atoi(c.Param("build")) | ||||
| 	jobn, _ := strconv.Atoi(c.Param("number")) | ||||
|  | ||||
| 	build, err := store.GetBuildNumber(c, repo, buildn) | ||||
| 	if err != nil { | ||||
| 		logrus.Debugln("stream cannot get build number.", err) | ||||
| 		c.AbortWithError(404, err) | ||||
| 		return | ||||
| 	} | ||||
| 	proc, err := store.FromContext(c).ProcFind(build, jobn) | ||||
| 	if err != nil { | ||||
| 		logrus.Debugln("stream cannot get proc number.", err) | ||||
| 		c.AbortWithError(404, err) | ||||
| 		return | ||||
| 	} | ||||
| 	if proc.State != model.StatusRunning { | ||||
| 		logrus.Debugln("stream not found.") | ||||
| 		c.AbortWithStatus(404) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ws, err := upgrader.Upgrade(c.Writer, c.Request, nil) | ||||
| 	if err != nil { | ||||
| 		if _, ok := err.(websocket.HandshakeError); !ok { | ||||
| 			logrus.Errorf("Cannot upgrade websocket. %s", err) | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| 	logrus.Debugf("Successfull upgraded websocket") | ||||
|  | ||||
| 	ticker := time.NewTicker(pingPeriod) | ||||
| 	logc := make(chan []byte, 10) | ||||
|  | ||||
| 	ctx, cancel := context.WithCancel( | ||||
| 		context.Background(), | ||||
| 	) | ||||
| 	defer func() { | ||||
| 		cancel() | ||||
| 		ticker.Stop() | ||||
| 		close(logc) | ||||
| 		logrus.Debugf("Successfully closing websocket") | ||||
| 	}() | ||||
|  | ||||
| 	go func() { | ||||
| 		// TODO remove global variable | ||||
| 		Config.Services.Logs.Tail(ctx, fmt.Sprint(proc.ID), func(entries ...*logging.Entry) { | ||||
| 			for _, entry := range entries { | ||||
| 				select { | ||||
| 				case <-ctx.Done(): | ||||
| 					return | ||||
| 				default: | ||||
| 					logc <- entry.Data | ||||
| 				} | ||||
| 			} | ||||
| 		}) | ||||
| 		cancel() | ||||
| 	}() | ||||
|  | ||||
| 	go func() { | ||||
| 		for { | ||||
| 			select { | ||||
| 			case <-ctx.Done(): | ||||
| 				return | ||||
| 			case buf, ok := <-logc: | ||||
| 				if ok { | ||||
| 					ws.SetWriteDeadline(time.Now().Add(writeWait)) | ||||
| 					ws.WriteMessage(websocket.TextMessage, buf) | ||||
| 				} | ||||
| 			case <-ticker.C: | ||||
| 				err := ws.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(writeWait)) | ||||
| 				if err != nil { | ||||
| 					return | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	}() | ||||
| 	reader(ws) | ||||
| } | ||||
|  | ||||
| func EventStream(c *gin.Context) { | ||||
| 	ws, err := upgrader.Upgrade(c.Writer, c.Request, nil) | ||||
| 	if err != nil { | ||||
| 		if _, ok := err.(websocket.HandshakeError); !ok { | ||||
| 			logrus.Errorf("Cannot upgrade websocket. %s", err) | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| 	logrus.Debugf("Successfull upgraded websocket") | ||||
|  | ||||
| 	user := session.User(c) | ||||
| 	repo := map[string]bool{} | ||||
| 	if user != nil { | ||||
| 		repos, _ := store.FromContext(c).RepoList(user) | ||||
| 		for _, r := range repos { | ||||
| 			repo[r.FullName] = true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	ticker := time.NewTicker(pingPeriod) | ||||
| 	eventc := make(chan []byte, 10) | ||||
|  | ||||
| 	ctx, cancel := context.WithCancel( | ||||
| 		context.Background(), | ||||
| 	) | ||||
| 	defer func() { | ||||
| 		cancel() | ||||
| 		ticker.Stop() | ||||
| 		close(eventc) | ||||
| 		logrus.Debugf("Successfully closing websocket") | ||||
| 	}() | ||||
|  | ||||
| 	go func() { | ||||
| 		// TODO remove this from global config | ||||
| 		Config.Services.Pubsub.Subscribe(c, "topic/events", func(m pubsub.Message) { | ||||
| 			name := m.Labels["repo"] | ||||
| 			priv := m.Labels["private"] | ||||
| 			if repo[name] || priv == "false" { | ||||
| 				select { | ||||
| 				case <-ctx.Done(): | ||||
| 					return | ||||
| 				default: | ||||
| 					eventc <- m.Data | ||||
| 				} | ||||
| 			} | ||||
| 		}) | ||||
| 		cancel() | ||||
| 	}() | ||||
|  | ||||
| 	go func() { | ||||
| 		for { | ||||
| 			select { | ||||
| 			case <-ctx.Done(): | ||||
| 				return | ||||
| 			case buf, ok := <-eventc: | ||||
| 				if ok { | ||||
| 					ws.SetWriteDeadline(time.Now().Add(writeWait)) | ||||
| 					ws.WriteMessage(websocket.TextMessage, buf) | ||||
| 				} | ||||
| 			case <-ticker.C: | ||||
| 				err := ws.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(writeWait)) | ||||
| 				if err != nil { | ||||
| 					return | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	}() | ||||
| 	reader(ws) | ||||
| } | ||||
|  | ||||
| // | ||||
| // event source streaming for compatibility with quic and http2 | ||||
| // | ||||
|   | ||||
| @@ -122,32 +122,3 @@ func ToUser(c context.Context) (*model.User, bool) { | ||||
| type key int | ||||
|  | ||||
| const userKey key = 0 | ||||
|  | ||||
| // var partials = templ | ||||
| // var templ = ` | ||||
| // {{define "user"}} | ||||
| // <script> | ||||
| // 	{{ if .user }} | ||||
| // 	window.USER = {{ json .user }}; | ||||
| // 	{{ end }} | ||||
| // </script> | ||||
| // {{end}} | ||||
| // | ||||
| // {{define "csrf"}} | ||||
| // <script> | ||||
| // 	{{ if .csrf }}window.DRONE_CSRF = "{{ .csrf }}"{{ end }} | ||||
| // </script> | ||||
| // {{end}} | ||||
| // | ||||
| // {{define "version"}} | ||||
| // 	<meta name="version" content="{{ .version }}"> | ||||
| // {{end}} | ||||
| // ` | ||||
|  | ||||
| // var funcMap = template.FuncMap{"json": marshal} | ||||
| // | ||||
| // // marshal is a template helper function to render data as json. | ||||
| // func marshal(v interface{}) template.JS { | ||||
| // 	a, _ := json.Marshal(v) | ||||
| // 	return template.JS(a) | ||||
| // } | ||||
|   | ||||
							
								
								
									
										38
									
								
								vendor/github.com/mattn/go-sqlite3/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										38
									
								
								vendor/github.com/mattn/go-sqlite3/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,9 +1,10 @@ | ||||
| go-sqlite3 | ||||
| ========== | ||||
|  | ||||
| [](http://godoc.org/github.com/mattn/go-sqlite3) | ||||
| [](https://travis-ci.org/mattn/go-sqlite3) | ||||
| [](https://coveralls.io/r/mattn/go-sqlite3?branch=master) | ||||
| [](http://godoc.org/github.com/mattn/go-sqlite3) | ||||
| [](https://goreportcard.com/report/github.com/mattn/go-sqlite3) | ||||
|  | ||||
| Description | ||||
| ----------- | ||||
| @@ -16,11 +17,11 @@ Installation | ||||
| This package can be installed with the go get command: | ||||
|  | ||||
|     go get github.com/mattn/go-sqlite3 | ||||
|      | ||||
|  | ||||
| _go-sqlite3_ is *cgo* package. | ||||
| If you want to build your app using go-sqlite3, you need gcc. | ||||
| However, if you install _go-sqlite3_ with `go install github.com/mattn/go-sqlite3`, you don't need gcc to build your app anymore. | ||||
|      | ||||
|  | ||||
| Documentation | ||||
| ------------- | ||||
|  | ||||
| @@ -35,28 +36,49 @@ FAQ | ||||
|  | ||||
|     Use `go build --tags "libsqlite3 linux"` | ||||
|  | ||||
| * Want to build go-sqlite3 with libsqlite3 on OS X. | ||||
|  | ||||
|     Install sqlite3 from homebrew: `brew install sqlite3` | ||||
|  | ||||
|     Use `go build --tags "libsqlite3 darwin"` | ||||
|  | ||||
| * Want to build go-sqlite3 with icu extension. | ||||
|  | ||||
|    Use `go build --tags "icu"` | ||||
|  | ||||
|    Available extensions: `json1`, `fts5`, `icu` | ||||
|  | ||||
| * Can't build go-sqlite3 on windows 64bit. | ||||
|  | ||||
|     > Probably, you are using go 1.0, go1.0 has a problem when it comes to compiling/linking on windows 64bit.  | ||||
|     > See: https://github.com/mattn/go-sqlite3/issues/27 | ||||
|     > Probably, you are using go 1.0, go1.0 has a problem when it comes to compiling/linking on windows 64bit. | ||||
|     > See: [#27](https://github.com/mattn/go-sqlite3/issues/27) | ||||
|  | ||||
| * Getting insert error while query is opened. | ||||
|  | ||||
|     > You can pass some arguments into the connection string, for example, a URI. | ||||
|     > See: https://github.com/mattn/go-sqlite3/issues/39 | ||||
|     > See: [#39](https://github.com/mattn/go-sqlite3/issues/39) | ||||
|  | ||||
| * Do you want to cross compile? mingw on Linux or Mac? | ||||
|  | ||||
|     > See: https://github.com/mattn/go-sqlite3/issues/106 | ||||
|     > See: [#106](https://github.com/mattn/go-sqlite3/issues/106) | ||||
|     > See also: http://www.limitlessfx.com/cross-compile-golang-app-for-windows-from-linux.html | ||||
|  | ||||
| * Want to get time.Time with current locale | ||||
|  | ||||
|     Use `loc=auto` in SQLite3 filename schema like `file:foo.db?loc=auto`. | ||||
|     Use `_loc=auto` in SQLite3 filename schema like `file:foo.db?_loc=auto`. | ||||
|  | ||||
| * Can I use this in multiple routines concurrently? | ||||
|  | ||||
|     Yes for readonly. But, No for writable. See [#50](https://github.com/mattn/go-sqlite3/issues/50), [#51](https://github.com/mattn/go-sqlite3/issues/51), [#209](https://github.com/mattn/go-sqlite3/issues/209). | ||||
|  | ||||
| * Why is it racy if I use a `sql.Open("sqlite3", ":memory:")` database? | ||||
|  | ||||
|     Each connection to :memory: opens a brand new in-memory sql database, so if | ||||
|     the stdlib's sql engine happens to open another connection and you've only | ||||
|     specified ":memory:", that connection will see a brand new database. A | ||||
|     workaround is to use "file::memory:?mode=memory&cache=shared". Every | ||||
|     connection to this string will point to the same in-memory database. See | ||||
|     [#204](https://github.com/mattn/go-sqlite3/issues/204) for more info. | ||||
|  | ||||
| License | ||||
| ------- | ||||
|   | ||||
							
								
								
									
										27
									
								
								vendor/github.com/mattn/go-sqlite3/backup.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										27
									
								
								vendor/github.com/mattn/go-sqlite3/backup.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -6,7 +6,11 @@ | ||||
| package sqlite3 | ||||
|  | ||||
| /* | ||||
| #ifndef USE_LIBSQLITE3 | ||||
| #include <sqlite3-binding.h> | ||||
| #else | ||||
| #include <sqlite3.h> | ||||
| #endif | ||||
| #include <stdlib.h> | ||||
| */ | ||||
| import "C" | ||||
| @@ -15,10 +19,12 @@ import ( | ||||
| 	"unsafe" | ||||
| ) | ||||
|  | ||||
| // SQLiteBackup implement interface of Backup. | ||||
| type SQLiteBackup struct { | ||||
| 	b *C.sqlite3_backup | ||||
| } | ||||
|  | ||||
| // Backup make backup from src to dest. | ||||
| func (c *SQLiteConn) Backup(dest string, conn *SQLiteConn, src string) (*SQLiteBackup, error) { | ||||
| 	destptr := C.CString(dest) | ||||
| 	defer C.free(unsafe.Pointer(destptr)) | ||||
| @@ -33,10 +39,10 @@ func (c *SQLiteConn) Backup(dest string, conn *SQLiteConn, src string) (*SQLiteB | ||||
| 	return nil, c.lastError() | ||||
| } | ||||
|  | ||||
| // Backs up for one step. Calls the underlying `sqlite3_backup_step` function. | ||||
| // This function returns a boolean indicating if the backup is done and | ||||
| // an error signalling any other error. Done is returned if the underlying C | ||||
| // function returns SQLITE_DONE (Code 101) | ||||
| // Step to backs up for one step. Calls the underlying `sqlite3_backup_step` | ||||
| // function.  This function returns a boolean indicating if the backup is done | ||||
| // and an error signalling any other error. Done is returned if the underlying | ||||
| // C function returns SQLITE_DONE (Code 101) | ||||
| func (b *SQLiteBackup) Step(p int) (bool, error) { | ||||
| 	ret := C.sqlite3_backup_step(b.b, C.int(p)) | ||||
| 	if ret == C.SQLITE_DONE { | ||||
| @@ -47,24 +53,33 @@ func (b *SQLiteBackup) Step(p int) (bool, error) { | ||||
| 	return false, nil | ||||
| } | ||||
|  | ||||
| // Remaining return whether have the rest for backup. | ||||
| func (b *SQLiteBackup) Remaining() int { | ||||
| 	return int(C.sqlite3_backup_remaining(b.b)) | ||||
| } | ||||
|  | ||||
| // PageCount return count of pages. | ||||
| func (b *SQLiteBackup) PageCount() int { | ||||
| 	return int(C.sqlite3_backup_pagecount(b.b)) | ||||
| } | ||||
|  | ||||
| // Finish close backup. | ||||
| func (b *SQLiteBackup) Finish() error { | ||||
| 	return b.Close() | ||||
| } | ||||
|  | ||||
| // Close close backup. | ||||
| func (b *SQLiteBackup) Close() error { | ||||
| 	ret := C.sqlite3_backup_finish(b.b) | ||||
|  | ||||
| 	// sqlite3_backup_finish() never fails, it just returns the | ||||
| 	// error code from previous operations, so clean up before | ||||
| 	// checking and returning an error | ||||
| 	b.b = nil | ||||
| 	runtime.SetFinalizer(b, nil) | ||||
|  | ||||
| 	if ret != 0 { | ||||
| 		return Error{Code: ErrNo(ret)} | ||||
| 	} | ||||
| 	b.b = nil | ||||
| 	runtime.SetFinalizer(b, nil) | ||||
| 	return nil | ||||
| } | ||||
|   | ||||
							
								
								
									
										32
									
								
								vendor/github.com/mattn/go-sqlite3/callback.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										32
									
								
								vendor/github.com/mattn/go-sqlite3/callback.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -11,7 +11,11 @@ package sqlite3 | ||||
| // code for SQLite custom functions is in here. | ||||
|  | ||||
| /* | ||||
| #ifndef USE_LIBSQLITE3 | ||||
| #include <sqlite3-binding.h> | ||||
| #else | ||||
| #include <sqlite3.h> | ||||
| #endif | ||||
| #include <stdlib.h> | ||||
|  | ||||
| void _sqlite3_result_text(sqlite3_context* ctx, const char* s); | ||||
| @@ -36,8 +40,8 @@ func callbackTrampoline(ctx *C.sqlite3_context, argc int, argv **C.sqlite3_value | ||||
| } | ||||
|  | ||||
| //export stepTrampoline | ||||
| func stepTrampoline(ctx *C.sqlite3_context, argc int, argv **C.sqlite3_value) { | ||||
| 	args := (*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.sqlite3_value)(nil))]*C.sqlite3_value)(unsafe.Pointer(argv))[:argc:argc] | ||||
| func stepTrampoline(ctx *C.sqlite3_context, argc C.int, argv **C.sqlite3_value) { | ||||
| 	args := (*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.sqlite3_value)(nil))]*C.sqlite3_value)(unsafe.Pointer(argv))[:int(argc):int(argc)] | ||||
| 	ai := lookupHandle(uintptr(C.sqlite3_user_data(ctx))).(*aggInfo) | ||||
| 	ai.Step(ctx, args) | ||||
| } | ||||
| @@ -49,6 +53,30 @@ func doneTrampoline(ctx *C.sqlite3_context) { | ||||
| 	ai.Done(ctx) | ||||
| } | ||||
|  | ||||
| //export compareTrampoline | ||||
| func compareTrampoline(handlePtr uintptr, la C.int, a *C.char, lb C.int, b *C.char) C.int { | ||||
| 	cmp := lookupHandle(handlePtr).(func(string, string) int) | ||||
| 	return C.int(cmp(C.GoStringN(a, la), C.GoStringN(b, lb))) | ||||
| } | ||||
|  | ||||
| //export commitHookTrampoline | ||||
| func commitHookTrampoline(handle uintptr) int { | ||||
| 	callback := lookupHandle(handle).(func() int) | ||||
| 	return callback() | ||||
| } | ||||
|  | ||||
| //export rollbackHookTrampoline | ||||
| func rollbackHookTrampoline(handle uintptr) { | ||||
| 	callback := lookupHandle(handle).(func()) | ||||
| 	callback() | ||||
| } | ||||
|  | ||||
| //export updateHookTrampoline | ||||
| func updateHookTrampoline(handle uintptr, op int, db *C.char, table *C.char, rowid int64) { | ||||
| 	callback := lookupHandle(handle).(func(int, string, string, int64)) | ||||
| 	callback(op, C.GoString(db), C.GoString(table), rowid) | ||||
| } | ||||
|  | ||||
| // Use handles to avoid passing Go pointers to C. | ||||
|  | ||||
| type handleVal struct { | ||||
|   | ||||
							
								
								
									
										186041
									
								
								vendor/github.com/mattn/go-sqlite3/code/sqlite3-binding.c
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										186041
									
								
								vendor/github.com/mattn/go-sqlite3/code/sqlite3-binding.c
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										8630
									
								
								vendor/github.com/mattn/go-sqlite3/code/sqlite3-binding.h
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										8630
									
								
								vendor/github.com/mattn/go-sqlite3/code/sqlite3-binding.h
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2
									
								
								vendor/github.com/mattn/go-sqlite3/doc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/mattn/go-sqlite3/doc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -102,7 +102,7 @@ call RegisterFunction from ConnectHook. | ||||
| 	sql.Register("sqlite3_with_go_func", | ||||
| 			&sqlite3.SQLiteDriver{ | ||||
| 					ConnectHook: func(conn *sqlite3.SQLiteConn) error { | ||||
| 						return conn.RegisterFunc("regex", regex, true) | ||||
| 						return conn.RegisterFunc("regexp", regex, true) | ||||
| 					}, | ||||
| 			}) | ||||
|  | ||||
|   | ||||
							
								
								
									
										9
									
								
								vendor/github.com/mattn/go-sqlite3/error.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								vendor/github.com/mattn/go-sqlite3/error.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -7,12 +7,16 @@ package sqlite3 | ||||
|  | ||||
| import "C" | ||||
|  | ||||
| // ErrNo inherit errno. | ||||
| type ErrNo int | ||||
|  | ||||
| // ErrNoMask is mask code. | ||||
| const ErrNoMask C.int = 0xff | ||||
|  | ||||
| // ErrNoExtended is extended errno. | ||||
| type ErrNoExtended int | ||||
|  | ||||
| // Error implement sqlite error code. | ||||
| type Error struct { | ||||
| 	Code         ErrNo         /* The error code returned by SQLite */ | ||||
| 	ExtendedCode ErrNoExtended /* The extended error code returned by SQLite */ | ||||
| @@ -52,14 +56,17 @@ var ( | ||||
| 	ErrWarning    = ErrNo(28) /* Warnings from sqlite3_log() */ | ||||
| ) | ||||
|  | ||||
| // Error return error message from errno. | ||||
| func (err ErrNo) Error() string { | ||||
| 	return Error{Code: err}.Error() | ||||
| } | ||||
|  | ||||
| // Extend return extended errno. | ||||
| func (err ErrNo) Extend(by int) ErrNoExtended { | ||||
| 	return ErrNoExtended(int(err) | (by << 8)) | ||||
| } | ||||
|  | ||||
| // Error return error message that is extended code. | ||||
| func (err ErrNoExtended) Error() string { | ||||
| 	return Error{Code: ErrNo(C.int(err) & ErrNoMask), ExtendedCode: err}.Error() | ||||
| } | ||||
| @@ -121,7 +128,7 @@ var ( | ||||
| 	ErrConstraintTrigger      = ErrConstraint.Extend(7) | ||||
| 	ErrConstraintUnique       = ErrConstraint.Extend(8) | ||||
| 	ErrConstraintVTab         = ErrConstraint.Extend(9) | ||||
| 	ErrConstraintRowId        = ErrConstraint.Extend(10) | ||||
| 	ErrConstraintRowID        = ErrConstraint.Extend(10) | ||||
| 	ErrNoticeRecoverWAL       = ErrNotice.Extend(1) | ||||
| 	ErrNoticeRecoverRollback  = ErrNotice.Extend(2) | ||||
| 	ErrWarningAutoIndex       = ErrWarning.Extend(1) | ||||
|   | ||||
							
								
								
									
										201406
									
								
								vendor/github.com/mattn/go-sqlite3/sqlite3-binding.c
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										201406
									
								
								vendor/github.com/mattn/go-sqlite3/sqlite3-binding.c
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										10476
									
								
								vendor/github.com/mattn/go-sqlite3/sqlite3-binding.h
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										10476
									
								
								vendor/github.com/mattn/go-sqlite3/sqlite3-binding.h
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										614
									
								
								vendor/github.com/mattn/go-sqlite3/sqlite3.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										614
									
								
								vendor/github.com/mattn/go-sqlite3/sqlite3.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -7,9 +7,16 @@ package sqlite3 | ||||
|  | ||||
| /* | ||||
| #cgo CFLAGS: -std=gnu99 | ||||
| #cgo CFLAGS: -DSQLITE_ENABLE_RTREE -DSQLITE_THREADSAFE | ||||
| #cgo CFLAGS: -DSQLITE_ENABLE_RTREE -DSQLITE_THREADSAFE=1 | ||||
| #cgo CFLAGS: -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_FTS4_UNICODE61 | ||||
| #cgo CFLAGS: -DSQLITE_TRACE_SIZE_LIMIT=15 | ||||
| #cgo CFLAGS: -DSQLITE_DISABLE_INTRINSIC | ||||
| #cgo CFLAGS: -Wno-deprecated-declarations | ||||
| #ifndef USE_LIBSQLITE3 | ||||
| #include <sqlite3-binding.h> | ||||
| #else | ||||
| #include <sqlite3.h> | ||||
| #endif | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| @@ -25,6 +32,10 @@ package sqlite3 | ||||
| # define SQLITE_OPEN_FULLMUTEX 0 | ||||
| #endif | ||||
|  | ||||
| #ifndef SQLITE_DETERMINISTIC | ||||
| # define SQLITE_DETERMINISTIC 0 | ||||
| #endif | ||||
|  | ||||
| static int | ||||
| _sqlite3_open_v2(const char *filename, sqlite3 **ppDb, int flags, const char *zVfs) { | ||||
| #ifdef SQLITE_OPEN_URI | ||||
| @@ -89,8 +100,11 @@ int _sqlite3_create_function( | ||||
| } | ||||
|  | ||||
| void callbackTrampoline(sqlite3_context*, int, sqlite3_value**); | ||||
| void stepTrampoline(sqlite3_context*, int, sqlite3_value**); | ||||
| void doneTrampoline(sqlite3_context*); | ||||
|  | ||||
| int compareTrampoline(void*, int, char*, int, char*); | ||||
| int commitHookTrampoline(void*); | ||||
| void rollbackHookTrampoline(void*); | ||||
| void updateHookTrampoline(void*, int, char*, char*, sqlite3_int64); | ||||
| */ | ||||
| import "C" | ||||
| import ( | ||||
| @@ -104,14 +118,17 @@ import ( | ||||
| 	"runtime" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"time" | ||||
| 	"unsafe" | ||||
|  | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
|  | ||||
| // Timestamp formats understood by both this module and SQLite. | ||||
| // The first format in the slice will be used when saving time values | ||||
| // into the database. When parsing a string from a timestamp or | ||||
| // datetime column, the formats are tried in order. | ||||
| // SQLiteTimestampFormats is timestamp formats understood by both this module | ||||
| // and SQLite.  The first format in the slice will be used when saving time | ||||
| // values into the database. When parsing a string from a timestamp or datetime | ||||
| // column, the formats are tried in order. | ||||
| var SQLiteTimestampFormats = []string{ | ||||
| 	// By default, store timestamps with whatever timezone they come with. | ||||
| 	// When parsed, they will be returned with the same timezone. | ||||
| @@ -131,21 +148,28 @@ func init() { | ||||
| } | ||||
|  | ||||
| // Version returns SQLite library version information. | ||||
| func Version() (libVersion string, libVersionNumber int, sourceId string) { | ||||
| func Version() (libVersion string, libVersionNumber int, sourceID string) { | ||||
| 	libVersion = C.GoString(C.sqlite3_libversion()) | ||||
| 	libVersionNumber = int(C.sqlite3_libversion_number()) | ||||
| 	sourceId = C.GoString(C.sqlite3_sourceid()) | ||||
| 	return libVersion, libVersionNumber, sourceId | ||||
| 	sourceID = C.GoString(C.sqlite3_sourceid()) | ||||
| 	return libVersion, libVersionNumber, sourceID | ||||
| } | ||||
|  | ||||
| // Driver struct. | ||||
| const ( | ||||
| 	SQLITE_DELETE = C.SQLITE_DELETE | ||||
| 	SQLITE_INSERT = C.SQLITE_INSERT | ||||
| 	SQLITE_UPDATE = C.SQLITE_UPDATE | ||||
| ) | ||||
|  | ||||
| // SQLiteDriver implement sql.Driver. | ||||
| type SQLiteDriver struct { | ||||
| 	Extensions  []string | ||||
| 	ConnectHook func(*SQLiteConn) error | ||||
| } | ||||
|  | ||||
| // Conn struct. | ||||
| // SQLiteConn implement sql.Conn. | ||||
| type SQLiteConn struct { | ||||
| 	mu          sync.Mutex | ||||
| 	db          *C.sqlite3 | ||||
| 	loc         *time.Location | ||||
| 	txlock      string | ||||
| @@ -153,35 +177,36 @@ type SQLiteConn struct { | ||||
| 	aggregators []*aggInfo | ||||
| } | ||||
|  | ||||
| // Tx struct. | ||||
| // SQLiteTx implemen sql.Tx. | ||||
| type SQLiteTx struct { | ||||
| 	c *SQLiteConn | ||||
| } | ||||
|  | ||||
| // Stmt struct. | ||||
| // SQLiteStmt implement sql.Stmt. | ||||
| type SQLiteStmt struct { | ||||
| 	mu     sync.Mutex | ||||
| 	c      *SQLiteConn | ||||
| 	s      *C.sqlite3_stmt | ||||
| 	nv     int | ||||
| 	nn     []string | ||||
| 	t      string | ||||
| 	closed bool | ||||
| 	cls    bool | ||||
| } | ||||
|  | ||||
| // Result struct. | ||||
| // SQLiteResult implement sql.Result. | ||||
| type SQLiteResult struct { | ||||
| 	id      int64 | ||||
| 	changes int64 | ||||
| } | ||||
|  | ||||
| // Rows struct. | ||||
| // SQLiteRows implement sql.Rows. | ||||
| type SQLiteRows struct { | ||||
| 	s        *SQLiteStmt | ||||
| 	nc       int | ||||
| 	cols     []string | ||||
| 	decltype []string | ||||
| 	cls      bool | ||||
| 	closed   bool | ||||
| 	done     chan struct{} | ||||
| } | ||||
|  | ||||
| type functionInfo struct { | ||||
| @@ -287,16 +312,90 @@ func (ai *aggInfo) Done(ctx *C.sqlite3_context) { | ||||
|  | ||||
| // Commit transaction. | ||||
| func (tx *SQLiteTx) Commit() error { | ||||
| 	_, err := tx.c.exec("COMMIT") | ||||
| 	_, err := tx.c.exec(context.Background(), "COMMIT", nil) | ||||
| 	if err != nil && err.(Error).Code == C.SQLITE_BUSY { | ||||
| 		// sqlite3 will leave the transaction open in this scenario. | ||||
| 		// However, database/sql considers the transaction complete once we | ||||
| 		// return from Commit() - we must clean up to honour its semantics. | ||||
| 		tx.c.exec(context.Background(), "ROLLBACK", nil) | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // Rollback transaction. | ||||
| func (tx *SQLiteTx) Rollback() error { | ||||
| 	_, err := tx.c.exec("ROLLBACK") | ||||
| 	_, err := tx.c.exec(context.Background(), "ROLLBACK", nil) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // RegisterCollation makes a Go function available as a collation. | ||||
| // | ||||
| // cmp receives two UTF-8 strings, a and b. The result should be 0 if | ||||
| // a==b, -1 if a < b, and +1 if a > b. | ||||
| // | ||||
| // cmp must always return the same result given the same | ||||
| // inputs. Additionally, it must have the following properties for all | ||||
| // strings A, B and C: if A==B then B==A; if A==B and B==C then A==C; | ||||
| // if A<B then B>A; if A<B and B<C then A<C. | ||||
| // | ||||
| // If cmp does not obey these constraints, sqlite3's behavior is | ||||
| // undefined when the collation is used. | ||||
| func (c *SQLiteConn) RegisterCollation(name string, cmp func(string, string) int) error { | ||||
| 	handle := newHandle(c, cmp) | ||||
| 	cname := C.CString(name) | ||||
| 	defer C.free(unsafe.Pointer(cname)) | ||||
| 	rv := C.sqlite3_create_collation(c.db, cname, C.SQLITE_UTF8, unsafe.Pointer(handle), (*[0]byte)(unsafe.Pointer(C.compareTrampoline))) | ||||
| 	if rv != C.SQLITE_OK { | ||||
| 		return c.lastError() | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // RegisterCommitHook sets the commit hook for a connection. | ||||
| // | ||||
| // If the callback returns non-zero the transaction will become a rollback. | ||||
| // | ||||
| // If there is an existing commit hook for this connection, it will be | ||||
| // removed. If callback is nil the existing hook (if any) will be removed | ||||
| // without creating a new one. | ||||
| func (c *SQLiteConn) RegisterCommitHook(callback func() int) { | ||||
| 	if callback == nil { | ||||
| 		C.sqlite3_commit_hook(c.db, nil, nil) | ||||
| 	} else { | ||||
| 		C.sqlite3_commit_hook(c.db, (*[0]byte)(unsafe.Pointer(C.commitHookTrampoline)), unsafe.Pointer(newHandle(c, callback))) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // RegisterRollbackHook sets the rollback hook for a connection. | ||||
| // | ||||
| // If there is an existing rollback hook for this connection, it will be | ||||
| // removed. If callback is nil the existing hook (if any) will be removed | ||||
| // without creating a new one. | ||||
| func (c *SQLiteConn) RegisterRollbackHook(callback func()) { | ||||
| 	if callback == nil { | ||||
| 		C.sqlite3_rollback_hook(c.db, nil, nil) | ||||
| 	} else { | ||||
| 		C.sqlite3_rollback_hook(c.db, (*[0]byte)(unsafe.Pointer(C.rollbackHookTrampoline)), unsafe.Pointer(newHandle(c, callback))) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // RegisterUpdateHook sets the update hook for a connection. | ||||
| // | ||||
| // The parameters to the callback are the operation (one of the constants | ||||
| // SQLITE_INSERT, SQLITE_DELETE, or SQLITE_UPDATE), the database name, the | ||||
| // table name, and the rowid. | ||||
| // | ||||
| // If there is an existing update hook for this connection, it will be | ||||
| // removed. If callback is nil the existing hook (if any) will be removed | ||||
| // without creating a new one. | ||||
| func (c *SQLiteConn) RegisterUpdateHook(callback func(int, string, string, int64)) { | ||||
| 	if callback == nil { | ||||
| 		C.sqlite3_update_hook(c.db, nil, nil) | ||||
| 	} else { | ||||
| 		C.sqlite3_update_hook(c.db, (*[0]byte)(unsafe.Pointer(C.updateHookTrampoline)), unsafe.Pointer(newHandle(c, callback))) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // RegisterFunc makes a Go function available as a SQLite function. | ||||
| // | ||||
| // The Go function can have arguments of the following types: any | ||||
| @@ -367,136 +466,15 @@ func (c *SQLiteConn) RegisterFunc(name string, impl interface{}, pure bool) erro | ||||
| 	if pure { | ||||
| 		opts |= C.SQLITE_DETERMINISTIC | ||||
| 	} | ||||
| 	rv := C._sqlite3_create_function(c.db, cname, C.int(numArgs), C.int(opts), C.uintptr_t(newHandle(c, &fi)), (*[0]byte)(unsafe.Pointer(C.callbackTrampoline)), nil, nil) | ||||
| 	rv := sqlite3CreateFunction(c.db, cname, C.int(numArgs), C.int(opts), newHandle(c, &fi), C.callbackTrampoline, nil, nil) | ||||
| 	if rv != C.SQLITE_OK { | ||||
| 		return c.lastError() | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // RegisterAggregator makes a Go type available as a SQLite aggregation function. | ||||
| // | ||||
| // Because aggregation is incremental, it's implemented in Go with a | ||||
| // type that has 2 methods: func Step(values) accumulates one row of | ||||
| // data into the accumulator, and func Done() ret finalizes and | ||||
| // returns the aggregate value. "values" and "ret" may be any type | ||||
| // supported by RegisterFunc. | ||||
| // | ||||
| // RegisterAggregator takes as implementation a constructor function | ||||
| // that constructs an instance of the aggregator type each time an | ||||
| // aggregation begins. The constructor must return a pointer to a | ||||
| // type, or an interface that implements Step() and Done(). | ||||
| // | ||||
| // The constructor function and the Step/Done methods may optionally | ||||
| // return an error in addition to their other return values. | ||||
| // | ||||
| // See _example/go_custom_funcs for a detailed example. | ||||
| func (c *SQLiteConn) RegisterAggregator(name string, impl interface{}, pure bool) error { | ||||
| 	var ai aggInfo | ||||
| 	ai.constructor = reflect.ValueOf(impl) | ||||
| 	t := ai.constructor.Type() | ||||
| 	if t.Kind() != reflect.Func { | ||||
| 		return errors.New("non-function passed to RegisterAggregator") | ||||
| 	} | ||||
| 	if t.NumOut() != 1 && t.NumOut() != 2 { | ||||
| 		return errors.New("SQLite aggregator constructors must return 1 or 2 values") | ||||
| 	} | ||||
| 	if t.NumOut() == 2 && !t.Out(1).Implements(reflect.TypeOf((*error)(nil)).Elem()) { | ||||
| 		return errors.New("Second return value of SQLite function must be error") | ||||
| 	} | ||||
| 	if t.NumIn() != 0 { | ||||
| 		return errors.New("SQLite aggregator constructors must not have arguments") | ||||
| 	} | ||||
|  | ||||
| 	agg := t.Out(0) | ||||
| 	switch agg.Kind() { | ||||
| 	case reflect.Ptr, reflect.Interface: | ||||
| 	default: | ||||
| 		return errors.New("SQlite aggregator constructor must return a pointer object") | ||||
| 	} | ||||
| 	stepFn, found := agg.MethodByName("Step") | ||||
| 	if !found { | ||||
| 		return errors.New("SQlite aggregator doesn't have a Step() function") | ||||
| 	} | ||||
| 	step := stepFn.Type | ||||
| 	if step.NumOut() != 0 && step.NumOut() != 1 { | ||||
| 		return errors.New("SQlite aggregator Step() function must return 0 or 1 values") | ||||
| 	} | ||||
| 	if step.NumOut() == 1 && !step.Out(0).Implements(reflect.TypeOf((*error)(nil)).Elem()) { | ||||
| 		return errors.New("type of SQlite aggregator Step() return value must be error") | ||||
| 	} | ||||
|  | ||||
| 	stepNArgs := step.NumIn() | ||||
| 	start := 0 | ||||
| 	if agg.Kind() == reflect.Ptr { | ||||
| 		// Skip over the method receiver | ||||
| 		stepNArgs-- | ||||
| 		start++ | ||||
| 	} | ||||
| 	if step.IsVariadic() { | ||||
| 		stepNArgs-- | ||||
| 	} | ||||
| 	for i := start; i < start+stepNArgs; i++ { | ||||
| 		conv, err := callbackArg(step.In(i)) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		ai.stepArgConverters = append(ai.stepArgConverters, conv) | ||||
| 	} | ||||
| 	if step.IsVariadic() { | ||||
| 		conv, err := callbackArg(t.In(start + stepNArgs).Elem()) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		ai.stepVariadicConverter = conv | ||||
| 		// Pass -1 to sqlite so that it allows any number of | ||||
| 		// arguments. The call helper verifies that the minimum number | ||||
| 		// of arguments is present for variadic functions. | ||||
| 		stepNArgs = -1 | ||||
| 	} | ||||
|  | ||||
| 	doneFn, found := agg.MethodByName("Done") | ||||
| 	if !found { | ||||
| 		return errors.New("SQlite aggregator doesn't have a Done() function") | ||||
| 	} | ||||
| 	done := doneFn.Type | ||||
| 	doneNArgs := done.NumIn() | ||||
| 	if agg.Kind() == reflect.Ptr { | ||||
| 		// Skip over the method receiver | ||||
| 		doneNArgs-- | ||||
| 	} | ||||
| 	if doneNArgs != 0 { | ||||
| 		return errors.New("SQlite aggregator Done() function must have no arguments") | ||||
| 	} | ||||
| 	if done.NumOut() != 1 && done.NumOut() != 2 { | ||||
| 		return errors.New("SQLite aggregator Done() function must return 1 or 2 values") | ||||
| 	} | ||||
| 	if done.NumOut() == 2 && !done.Out(1).Implements(reflect.TypeOf((*error)(nil)).Elem()) { | ||||
| 		return errors.New("second return value of SQLite aggregator Done() function must be error") | ||||
| 	} | ||||
|  | ||||
| 	conv, err := callbackRet(done.Out(0)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	ai.doneRetConverter = conv | ||||
| 	ai.active = make(map[int64]reflect.Value) | ||||
| 	ai.next = 1 | ||||
|  | ||||
| 	// ai must outlast the database connection, or we'll have dangling pointers. | ||||
| 	c.aggregators = append(c.aggregators, &ai) | ||||
|  | ||||
| 	cname := C.CString(name) | ||||
| 	defer C.free(unsafe.Pointer(cname)) | ||||
| 	opts := C.SQLITE_UTF8 | ||||
| 	if pure { | ||||
| 		opts |= C.SQLITE_DETERMINISTIC | ||||
| 	} | ||||
| 	rv := C._sqlite3_create_function(c.db, cname, C.int(stepNArgs), C.int(opts), C.uintptr_t(newHandle(c, &ai)), nil, (*[0]byte)(unsafe.Pointer(C.stepTrampoline)), (*[0]byte)(unsafe.Pointer(C.doneTrampoline))) | ||||
| 	if rv != C.SQLITE_OK { | ||||
| 		return c.lastError() | ||||
| 	} | ||||
| 	return nil | ||||
| func sqlite3CreateFunction(db *C.sqlite3, zFunctionName *C.char, nArg C.int, eTextRep C.int, pApp uintptr, xFunc unsafe.Pointer, xStep unsafe.Pointer, xFinal unsafe.Pointer) C.int { | ||||
| 	return C._sqlite3_create_function(db, zFunctionName, nArg, eTextRep, C.uintptr_t(pApp), (*[0]byte)(unsafe.Pointer(xFunc)), (*[0]byte)(unsafe.Pointer(xStep)), (*[0]byte)(unsafe.Pointer(xFinal))) | ||||
| } | ||||
|  | ||||
| // AutoCommit return which currently auto commit or not. | ||||
| @@ -504,22 +482,38 @@ func (c *SQLiteConn) AutoCommit() bool { | ||||
| 	return int(C.sqlite3_get_autocommit(c.db)) != 0 | ||||
| } | ||||
|  | ||||
| func (c *SQLiteConn) lastError() Error { | ||||
| func (c *SQLiteConn) lastError() error { | ||||
| 	return lastError(c.db) | ||||
| } | ||||
|  | ||||
| func lastError(db *C.sqlite3) error { | ||||
| 	rv := C.sqlite3_errcode(db) | ||||
| 	if rv == C.SQLITE_OK { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return Error{ | ||||
| 		Code:         ErrNo(C.sqlite3_errcode(c.db)), | ||||
| 		ExtendedCode: ErrNoExtended(C.sqlite3_extended_errcode(c.db)), | ||||
| 		err:          C.GoString(C.sqlite3_errmsg(c.db)), | ||||
| 		Code:         ErrNo(rv), | ||||
| 		ExtendedCode: ErrNoExtended(C.sqlite3_extended_errcode(db)), | ||||
| 		err:          C.GoString(C.sqlite3_errmsg(db)), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Implements Execer | ||||
| // Exec implements Execer. | ||||
| func (c *SQLiteConn) Exec(query string, args []driver.Value) (driver.Result, error) { | ||||
| 	if len(args) == 0 { | ||||
| 		return c.exec(query) | ||||
| 	list := make([]namedValue, len(args)) | ||||
| 	for i, v := range args { | ||||
| 		list[i] = namedValue{ | ||||
| 			Ordinal: i + 1, | ||||
| 			Value:   v, | ||||
| 		} | ||||
| 	} | ||||
| 	return c.exec(context.Background(), query, list) | ||||
| } | ||||
|  | ||||
| func (c *SQLiteConn) exec(ctx context.Context, query string, args []namedValue) (driver.Result, error) { | ||||
| 	start := 0 | ||||
| 	for { | ||||
| 		s, err := c.Prepare(query) | ||||
| 		s, err := c.prepare(ctx, query) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| @@ -527,14 +521,19 @@ func (c *SQLiteConn) Exec(query string, args []driver.Value) (driver.Result, err | ||||
| 		if s.(*SQLiteStmt).s != nil { | ||||
| 			na := s.NumInput() | ||||
| 			if len(args) < na { | ||||
| 				return nil, fmt.Errorf("Not enough args to execute query. Expected %d, got %d.", na, len(args)) | ||||
| 				s.Close() | ||||
| 				return nil, fmt.Errorf("not enough args to execute query: want %d got %d", na, len(args)) | ||||
| 			} | ||||
| 			res, err = s.Exec(args[:na]) | ||||
| 			for i := 0; i < na; i++ { | ||||
| 				args[i].Ordinal -= start | ||||
| 			} | ||||
| 			res, err = s.(*SQLiteStmt).exec(ctx, args[:na]) | ||||
| 			if err != nil && err != driver.ErrSkip { | ||||
| 				s.Close() | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			args = args[na:] | ||||
| 			start += na | ||||
| 		} | ||||
| 		tail := s.(*SQLiteStmt).t | ||||
| 		s.Close() | ||||
| @@ -545,24 +544,46 @@ func (c *SQLiteConn) Exec(query string, args []driver.Value) (driver.Result, err | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Implements Queryer | ||||
| type namedValue struct { | ||||
| 	Name    string | ||||
| 	Ordinal int | ||||
| 	Value   driver.Value | ||||
| } | ||||
|  | ||||
| // Query implements Queryer. | ||||
| func (c *SQLiteConn) Query(query string, args []driver.Value) (driver.Rows, error) { | ||||
| 	list := make([]namedValue, len(args)) | ||||
| 	for i, v := range args { | ||||
| 		list[i] = namedValue{ | ||||
| 			Ordinal: i + 1, | ||||
| 			Value:   v, | ||||
| 		} | ||||
| 	} | ||||
| 	return c.query(context.Background(), query, list) | ||||
| } | ||||
|  | ||||
| func (c *SQLiteConn) query(ctx context.Context, query string, args []namedValue) (driver.Rows, error) { | ||||
| 	start := 0 | ||||
| 	for { | ||||
| 		s, err := c.Prepare(query) | ||||
| 		s, err := c.prepare(ctx, query) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		s.(*SQLiteStmt).cls = true | ||||
| 		na := s.NumInput() | ||||
| 		if len(args) < na { | ||||
| 			return nil, fmt.Errorf("Not enough args to execute query. Expected %d, got %d.", na, len(args)) | ||||
| 			return nil, fmt.Errorf("not enough args to execute query: want %d got %d", na, len(args)) | ||||
| 		} | ||||
| 		rows, err := s.Query(args[:na]) | ||||
| 		for i := 0; i < na; i++ { | ||||
| 			args[i].Ordinal -= start | ||||
| 		} | ||||
| 		rows, err := s.(*SQLiteStmt).query(ctx, args[:na]) | ||||
| 		if err != nil && err != driver.ErrSkip { | ||||
| 			s.Close() | ||||
| 			return nil, err | ||||
| 			return rows, err | ||||
| 		} | ||||
| 		args = args[na:] | ||||
| 		start += na | ||||
| 		tail := s.(*SQLiteStmt).t | ||||
| 		if tail == "" { | ||||
| 			return rows, nil | ||||
| @@ -573,21 +594,13 @@ func (c *SQLiteConn) Query(query string, args []driver.Value) (driver.Rows, erro | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (c *SQLiteConn) exec(cmd string) (driver.Result, error) { | ||||
| 	pcmd := C.CString(cmd) | ||||
| 	defer C.free(unsafe.Pointer(pcmd)) | ||||
|  | ||||
| 	var rowid, changes C.longlong | ||||
| 	rv := C._sqlite3_exec(c.db, pcmd, &rowid, &changes) | ||||
| 	if rv != C.SQLITE_OK { | ||||
| 		return nil, c.lastError() | ||||
| 	} | ||||
| 	return &SQLiteResult{int64(rowid), int64(changes)}, nil | ||||
| } | ||||
|  | ||||
| // Begin transaction. | ||||
| func (c *SQLiteConn) Begin() (driver.Tx, error) { | ||||
| 	if _, err := c.exec(c.txlock); err != nil { | ||||
| 	return c.begin(context.Background()) | ||||
| } | ||||
|  | ||||
| func (c *SQLiteConn) begin(ctx context.Context) (driver.Tx, error) { | ||||
| 	if _, err := c.exec(ctx, c.txlock, nil); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return &SQLiteTx{c}, nil | ||||
| @@ -611,6 +624,10 @@ func errorString(err Error) string { | ||||
| //   _txlock=XXX | ||||
| //     Specify locking behavior for transactions.  XXX can be "immediate", | ||||
| //     "deferred", "exclusive". | ||||
| //   _foreign_keys=X | ||||
| //     Enable or disable enforcement of foreign keys.  X can be 1 or 0. | ||||
| //   _recursive_triggers=X | ||||
| //     Enable or disable recursive triggers.  X can be 1 or 0. | ||||
| func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) { | ||||
| 	if C.sqlite3_threadsafe() == 0 { | ||||
| 		return nil, errors.New("sqlite library was not compiled for thread-safe operation") | ||||
| @@ -618,7 +635,9 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) { | ||||
|  | ||||
| 	var loc *time.Location | ||||
| 	txlock := "BEGIN" | ||||
| 	busy_timeout := 5000 | ||||
| 	busyTimeout := 5000 | ||||
| 	foreignKeys := -1 | ||||
| 	recursiveTriggers := -1 | ||||
| 	pos := strings.IndexRune(dsn, '?') | ||||
| 	if pos >= 1 { | ||||
| 		params, err := url.ParseQuery(dsn[pos+1:]) | ||||
| @@ -644,7 +663,7 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) { | ||||
| 			if err != nil { | ||||
| 				return nil, fmt.Errorf("Invalid _busy_timeout: %v: %v", val, err) | ||||
| 			} | ||||
| 			busy_timeout = int(iv) | ||||
| 			busyTimeout = int(iv) | ||||
| 		} | ||||
|  | ||||
| 		// _txlock | ||||
| @@ -661,6 +680,30 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) { | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// _foreign_keys | ||||
| 		if val := params.Get("_foreign_keys"); val != "" { | ||||
| 			switch val { | ||||
| 			case "1": | ||||
| 				foreignKeys = 1 | ||||
| 			case "0": | ||||
| 				foreignKeys = 0 | ||||
| 			default: | ||||
| 				return nil, fmt.Errorf("Invalid _foreign_keys: %v", val) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// _recursive_triggers | ||||
| 		if val := params.Get("_recursive_triggers"); val != "" { | ||||
| 			switch val { | ||||
| 			case "1": | ||||
| 				recursiveTriggers = 1 | ||||
| 			case "0": | ||||
| 				recursiveTriggers = 0 | ||||
| 			default: | ||||
| 				return nil, fmt.Errorf("Invalid _recursive_triggers: %v", val) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if !strings.HasPrefix(dsn, "file:") { | ||||
| 			dsn = dsn[:pos] | ||||
| 		} | ||||
| @@ -681,21 +724,56 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) { | ||||
| 		return nil, errors.New("sqlite succeeded without returning a database") | ||||
| 	} | ||||
|  | ||||
| 	rv = C.sqlite3_busy_timeout(db, C.int(busy_timeout)) | ||||
| 	rv = C.sqlite3_busy_timeout(db, C.int(busyTimeout)) | ||||
| 	if rv != C.SQLITE_OK { | ||||
| 		C.sqlite3_close_v2(db) | ||||
| 		return nil, Error{Code: ErrNo(rv)} | ||||
| 	} | ||||
|  | ||||
| 	exec := func(s string) error { | ||||
| 		cs := C.CString(s) | ||||
| 		rv := C.sqlite3_exec(db, cs, nil, nil, nil) | ||||
| 		C.free(unsafe.Pointer(cs)) | ||||
| 		if rv != C.SQLITE_OK { | ||||
| 			return lastError(db) | ||||
| 		} | ||||
| 		return nil | ||||
| 	} | ||||
| 	if foreignKeys == 0 { | ||||
| 		if err := exec("PRAGMA foreign_keys = OFF;"); err != nil { | ||||
| 			C.sqlite3_close_v2(db) | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} else if foreignKeys == 1 { | ||||
| 		if err := exec("PRAGMA foreign_keys = ON;"); err != nil { | ||||
| 			C.sqlite3_close_v2(db) | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 	if recursiveTriggers == 0 { | ||||
| 		if err := exec("PRAGMA recursive_triggers = OFF;"); err != nil { | ||||
| 			C.sqlite3_close_v2(db) | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} else if recursiveTriggers == 1 { | ||||
| 		if err := exec("PRAGMA recursive_triggers = ON;"); err != nil { | ||||
| 			C.sqlite3_close_v2(db) | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	conn := &SQLiteConn{db: db, loc: loc, txlock: txlock} | ||||
|  | ||||
| 	if len(d.Extensions) > 0 { | ||||
| 		if err := conn.loadExtensions(d.Extensions); err != nil { | ||||
| 			conn.Close() | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if d.ConnectHook != nil { | ||||
| 		if err := d.ConnectHook(conn); err != nil { | ||||
| 			conn.Close() | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| @@ -705,18 +783,33 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) { | ||||
|  | ||||
| // Close the connection. | ||||
| func (c *SQLiteConn) Close() error { | ||||
| 	deleteHandles(c) | ||||
| 	rv := C.sqlite3_close_v2(c.db) | ||||
| 	if rv != C.SQLITE_OK { | ||||
| 		return c.lastError() | ||||
| 	} | ||||
| 	deleteHandles(c) | ||||
| 	c.mu.Lock() | ||||
| 	c.db = nil | ||||
| 	c.mu.Unlock() | ||||
| 	runtime.SetFinalizer(c, nil) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (c *SQLiteConn) dbConnOpen() bool { | ||||
| 	if c == nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	c.mu.Lock() | ||||
| 	defer c.mu.Unlock() | ||||
| 	return c.db != nil | ||||
| } | ||||
|  | ||||
| // Prepare the query string. Return a new statement. | ||||
| func (c *SQLiteConn) Prepare(query string) (driver.Stmt, error) { | ||||
| 	return c.prepare(context.Background(), query) | ||||
| } | ||||
|  | ||||
| func (c *SQLiteConn) prepare(ctx context.Context, query string) (driver.Stmt, error) { | ||||
| 	pquery := C.CString(query) | ||||
| 	defer C.free(unsafe.Pointer(pquery)) | ||||
| 	var s *C.sqlite3_stmt | ||||
| @@ -729,29 +822,24 @@ func (c *SQLiteConn) Prepare(query string) (driver.Stmt, error) { | ||||
| 	if tail != nil && *tail != '\000' { | ||||
| 		t = strings.TrimSpace(C.GoString(tail)) | ||||
| 	} | ||||
| 	nv := int(C.sqlite3_bind_parameter_count(s)) | ||||
| 	var nn []string | ||||
| 	for i := 0; i < nv; i++ { | ||||
| 		pn := C.GoString(C.sqlite3_bind_parameter_name(s, C.int(i+1))) | ||||
| 		if len(pn) > 1 && pn[0] == '$' && 48 <= pn[1] && pn[1] <= 57 { | ||||
| 			nn = append(nn, C.GoString(C.sqlite3_bind_parameter_name(s, C.int(i+1)))) | ||||
| 		} | ||||
| 	} | ||||
| 	ss := &SQLiteStmt{c: c, s: s, nv: nv, nn: nn, t: t} | ||||
| 	ss := &SQLiteStmt{c: c, s: s, t: t} | ||||
| 	runtime.SetFinalizer(ss, (*SQLiteStmt).Close) | ||||
| 	return ss, nil | ||||
| } | ||||
|  | ||||
| // Close the statement. | ||||
| func (s *SQLiteStmt) Close() error { | ||||
| 	s.mu.Lock() | ||||
| 	defer s.mu.Unlock() | ||||
| 	if s.closed { | ||||
| 		return nil | ||||
| 	} | ||||
| 	s.closed = true | ||||
| 	if s.c == nil || s.c.db == nil { | ||||
| 	if !s.c.dbConnOpen() { | ||||
| 		return errors.New("sqlite statement with already closed database connection") | ||||
| 	} | ||||
| 	rv := C.sqlite3_finalize(s.s) | ||||
| 	s.s = nil | ||||
| 	if rv != C.SQLITE_OK { | ||||
| 		return s.c.lastError() | ||||
| 	} | ||||
| @@ -759,9 +847,9 @@ func (s *SQLiteStmt) Close() error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Return a number of parameters. | ||||
| // NumInput return a number of parameters. | ||||
| func (s *SQLiteStmt) NumInput() int { | ||||
| 	return s.nv | ||||
| 	return int(C.sqlite3_bind_parameter_count(s.s)) | ||||
| } | ||||
|  | ||||
| type bindArg struct { | ||||
| @@ -769,37 +857,30 @@ type bindArg struct { | ||||
| 	v driver.Value | ||||
| } | ||||
|  | ||||
| func (s *SQLiteStmt) bind(args []driver.Value) error { | ||||
| var placeHolder = []byte{0} | ||||
|  | ||||
| func (s *SQLiteStmt) bind(args []namedValue) error { | ||||
| 	rv := C.sqlite3_reset(s.s) | ||||
| 	if rv != C.SQLITE_ROW && rv != C.SQLITE_OK && rv != C.SQLITE_DONE { | ||||
| 		return s.c.lastError() | ||||
| 	} | ||||
|  | ||||
| 	var vargs []bindArg | ||||
| 	narg := len(args) | ||||
| 	vargs = make([]bindArg, narg) | ||||
| 	if len(s.nn) > 0 { | ||||
| 		for i, v := range s.nn { | ||||
| 			if pi, err := strconv.Atoi(v[1:]); err == nil { | ||||
| 				vargs[i] = bindArg{pi, args[i]} | ||||
| 			} | ||||
| 		} | ||||
| 	} else { | ||||
| 		for i, v := range args { | ||||
| 			vargs[i] = bindArg{i + 1, v} | ||||
| 	for i, v := range args { | ||||
| 		if v.Name != "" { | ||||
| 			cname := C.CString(":" + v.Name) | ||||
| 			args[i].Ordinal = int(C.sqlite3_bind_parameter_index(s.s, cname)) | ||||
| 			C.free(unsafe.Pointer(cname)) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for _, varg := range vargs { | ||||
| 		n := C.int(varg.n) | ||||
| 		v := varg.v | ||||
| 		switch v := v.(type) { | ||||
| 	for _, arg := range args { | ||||
| 		n := C.int(arg.Ordinal) | ||||
| 		switch v := arg.Value.(type) { | ||||
| 		case nil: | ||||
| 			rv = C.sqlite3_bind_null(s.s, n) | ||||
| 		case string: | ||||
| 			if len(v) == 0 { | ||||
| 				b := []byte{0} | ||||
| 				rv = C._sqlite3_bind_text(s.s, n, (*C.char)(unsafe.Pointer(&b[0])), C.int(0)) | ||||
| 				rv = C._sqlite3_bind_text(s.s, n, (*C.char)(unsafe.Pointer(&placeHolder[0])), C.int(0)) | ||||
| 			} else { | ||||
| 				b := []byte(v) | ||||
| 				rv = C._sqlite3_bind_text(s.s, n, (*C.char)(unsafe.Pointer(&b[0])), C.int(len(b))) | ||||
| @@ -815,11 +896,11 @@ func (s *SQLiteStmt) bind(args []driver.Value) error { | ||||
| 		case float64: | ||||
| 			rv = C.sqlite3_bind_double(s.s, n, C.double(v)) | ||||
| 		case []byte: | ||||
| 			if len(v) == 0 { | ||||
| 				rv = C._sqlite3_bind_blob(s.s, n, nil, 0) | ||||
| 			} else { | ||||
| 				rv = C._sqlite3_bind_blob(s.s, n, unsafe.Pointer(&v[0]), C.int(len(v))) | ||||
| 			ln := len(v) | ||||
| 			if ln == 0 { | ||||
| 				v = placeHolder | ||||
| 			} | ||||
| 			rv = C._sqlite3_bind_blob(s.s, n, unsafe.Pointer(&v[0]), C.int(ln)) | ||||
| 		case time.Time: | ||||
| 			b := []byte(v.Format(SQLiteTimestampFormats[0])) | ||||
| 			rv = C._sqlite3_bind_text(s.s, n, (*C.char)(unsafe.Pointer(&b[0])), C.int(len(b))) | ||||
| @@ -833,29 +914,86 @@ func (s *SQLiteStmt) bind(args []driver.Value) error { | ||||
|  | ||||
| // Query the statement with arguments. Return records. | ||||
| func (s *SQLiteStmt) Query(args []driver.Value) (driver.Rows, error) { | ||||
| 	list := make([]namedValue, len(args)) | ||||
| 	for i, v := range args { | ||||
| 		list[i] = namedValue{ | ||||
| 			Ordinal: i + 1, | ||||
| 			Value:   v, | ||||
| 		} | ||||
| 	} | ||||
| 	return s.query(context.Background(), list) | ||||
| } | ||||
|  | ||||
| func (s *SQLiteStmt) query(ctx context.Context, args []namedValue) (driver.Rows, error) { | ||||
| 	if err := s.bind(args); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return &SQLiteRows{s, int(C.sqlite3_column_count(s.s)), nil, nil, s.cls}, nil | ||||
|  | ||||
| 	rows := &SQLiteRows{ | ||||
| 		s:        s, | ||||
| 		nc:       int(C.sqlite3_column_count(s.s)), | ||||
| 		cols:     nil, | ||||
| 		decltype: nil, | ||||
| 		cls:      s.cls, | ||||
| 		closed:   false, | ||||
| 		done:     make(chan struct{}), | ||||
| 	} | ||||
|  | ||||
| 	go func(db *C.sqlite3) { | ||||
| 		select { | ||||
| 		case <-ctx.Done(): | ||||
| 			select { | ||||
| 			case <-rows.done: | ||||
| 			default: | ||||
| 				C.sqlite3_interrupt(db) | ||||
| 				rows.Close() | ||||
| 			} | ||||
| 		case <-rows.done: | ||||
| 		} | ||||
| 	}(s.c.db) | ||||
|  | ||||
| 	return rows, nil | ||||
| } | ||||
|  | ||||
| // Return last inserted ID. | ||||
| // LastInsertId teturn last inserted ID. | ||||
| func (r *SQLiteResult) LastInsertId() (int64, error) { | ||||
| 	return r.id, nil | ||||
| } | ||||
|  | ||||
| // Return how many rows affected. | ||||
| // RowsAffected return how many rows affected. | ||||
| func (r *SQLiteResult) RowsAffected() (int64, error) { | ||||
| 	return r.changes, nil | ||||
| } | ||||
|  | ||||
| // Execute the statement with arguments. Return result object. | ||||
| // Exec execute the statement with arguments. Return result object. | ||||
| func (s *SQLiteStmt) Exec(args []driver.Value) (driver.Result, error) { | ||||
| 	list := make([]namedValue, len(args)) | ||||
| 	for i, v := range args { | ||||
| 		list[i] = namedValue{ | ||||
| 			Ordinal: i + 1, | ||||
| 			Value:   v, | ||||
| 		} | ||||
| 	} | ||||
| 	return s.exec(context.Background(), list) | ||||
| } | ||||
|  | ||||
| func (s *SQLiteStmt) exec(ctx context.Context, args []namedValue) (driver.Result, error) { | ||||
| 	if err := s.bind(args); err != nil { | ||||
| 		C.sqlite3_reset(s.s) | ||||
| 		C.sqlite3_clear_bindings(s.s) | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	done := make(chan struct{}) | ||||
| 	defer close(done) | ||||
| 	go func(db *C.sqlite3) { | ||||
| 		select { | ||||
| 		case <-ctx.Done(): | ||||
| 			C.sqlite3_interrupt(db) | ||||
| 		case <-done: | ||||
| 		} | ||||
| 	}(s.c.db) | ||||
|  | ||||
| 	var rowid, changes C.longlong | ||||
| 	rv := C._sqlite3_step(s.s, &rowid, &changes) | ||||
| 	if rv != C.SQLITE_ROW && rv != C.SQLITE_OK && rv != C.SQLITE_DONE { | ||||
| @@ -864,27 +1002,39 @@ func (s *SQLiteStmt) Exec(args []driver.Value) (driver.Result, error) { | ||||
| 		C.sqlite3_clear_bindings(s.s) | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return &SQLiteResult{int64(rowid), int64(changes)}, nil | ||||
|  | ||||
| 	return &SQLiteResult{id: int64(rowid), changes: int64(changes)}, nil | ||||
| } | ||||
|  | ||||
| // Close the rows. | ||||
| func (rc *SQLiteRows) Close() error { | ||||
| 	if rc.s.closed { | ||||
| 	rc.s.mu.Lock() | ||||
| 	if rc.s.closed || rc.closed { | ||||
| 		rc.s.mu.Unlock() | ||||
| 		return nil | ||||
| 	} | ||||
| 	rc.closed = true | ||||
| 	if rc.done != nil { | ||||
| 		close(rc.done) | ||||
| 	} | ||||
| 	if rc.cls { | ||||
| 		rc.s.mu.Unlock() | ||||
| 		return rc.s.Close() | ||||
| 	} | ||||
| 	rv := C.sqlite3_reset(rc.s.s) | ||||
| 	if rv != C.SQLITE_OK { | ||||
| 		rc.s.mu.Unlock() | ||||
| 		return rc.s.c.lastError() | ||||
| 	} | ||||
| 	rc.s.mu.Unlock() | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Return column names. | ||||
| // Columns return column names. | ||||
| func (rc *SQLiteRows) Columns() []string { | ||||
| 	if rc.nc != len(rc.cols) { | ||||
| 	rc.s.mu.Lock() | ||||
| 	defer rc.s.mu.Unlock() | ||||
| 	if rc.s.s != nil && rc.nc != len(rc.cols) { | ||||
| 		rc.cols = make([]string, rc.nc) | ||||
| 		for i := 0; i < rc.nc; i++ { | ||||
| 			rc.cols[i] = C.GoString(C.sqlite3_column_name(rc.s.s, C.int(i))) | ||||
| @@ -893,9 +1043,8 @@ func (rc *SQLiteRows) Columns() []string { | ||||
| 	return rc.cols | ||||
| } | ||||
|  | ||||
| // Return column types. | ||||
| func (rc *SQLiteRows) DeclTypes() []string { | ||||
| 	if rc.decltype == nil { | ||||
| func (rc *SQLiteRows) declTypes() []string { | ||||
| 	if rc.s.s != nil && rc.decltype == nil { | ||||
| 		rc.decltype = make([]string, rc.nc) | ||||
| 		for i := 0; i < rc.nc; i++ { | ||||
| 			rc.decltype[i] = strings.ToLower(C.GoString(C.sqlite3_column_decltype(rc.s.s, C.int(i)))) | ||||
| @@ -904,8 +1053,20 @@ func (rc *SQLiteRows) DeclTypes() []string { | ||||
| 	return rc.decltype | ||||
| } | ||||
|  | ||||
| // Move cursor to next. | ||||
| // DeclTypes return column types. | ||||
| func (rc *SQLiteRows) DeclTypes() []string { | ||||
| 	rc.s.mu.Lock() | ||||
| 	defer rc.s.mu.Unlock() | ||||
| 	return rc.declTypes() | ||||
| } | ||||
|  | ||||
| // Next move cursor to next. | ||||
| func (rc *SQLiteRows) Next(dest []driver.Value) error { | ||||
| 	if rc.s.closed { | ||||
| 		return io.EOF | ||||
| 	} | ||||
| 	rc.s.mu.Lock() | ||||
| 	defer rc.s.mu.Unlock() | ||||
| 	rv := C.sqlite3_step(rc.s.s) | ||||
| 	if rv == C.SQLITE_DONE { | ||||
| 		return io.EOF | ||||
| @@ -918,7 +1079,7 @@ func (rc *SQLiteRows) Next(dest []driver.Value) error { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	rc.DeclTypes() | ||||
| 	rc.declTypes() | ||||
|  | ||||
| 	for i := range dest { | ||||
| 		switch C.sqlite3_column_type(rc.s.s, C.int(i)) { | ||||
| @@ -931,10 +1092,11 @@ func (rc *SQLiteRows) Next(dest []driver.Value) error { | ||||
| 				// large to be a reasonable timestamp in seconds. | ||||
| 				if val > 1e12 || val < -1e12 { | ||||
| 					val *= int64(time.Millisecond) // convert ms to nsec | ||||
| 					t = time.Unix(0, val) | ||||
| 				} else { | ||||
| 					val *= int64(time.Second) // convert sec to nsec | ||||
| 					t = time.Unix(val, 0) | ||||
| 				} | ||||
| 				t = time.Unix(0, val).UTC() | ||||
| 				t = t.UTC() | ||||
| 				if rc.s.c.loc != nil { | ||||
| 					t = t.In(rc.s.c.loc) | ||||
| 				} | ||||
|   | ||||
							
								
								
									
										103
									
								
								vendor/github.com/mattn/go-sqlite3/sqlite3_context.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								vendor/github.com/mattn/go-sqlite3/sqlite3_context.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | ||||
| // Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>. | ||||
| // | ||||
| // Use of this source code is governed by an MIT-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package sqlite3 | ||||
|  | ||||
| /* | ||||
|  | ||||
| #ifndef USE_LIBSQLITE3 | ||||
| #include <sqlite3-binding.h> | ||||
| #else | ||||
| #include <sqlite3.h> | ||||
| #endif | ||||
| #include <stdlib.h> | ||||
| // These wrappers are necessary because SQLITE_TRANSIENT | ||||
| // is a pointer constant, and cgo doesn't translate them correctly. | ||||
|  | ||||
| static inline void my_result_text(sqlite3_context *ctx, char *p, int np) { | ||||
| 	sqlite3_result_text(ctx, p, np, SQLITE_TRANSIENT); | ||||
| } | ||||
|  | ||||
| static inline void my_result_blob(sqlite3_context *ctx, void *p, int np) { | ||||
| 	sqlite3_result_blob(ctx, p, np, SQLITE_TRANSIENT); | ||||
| } | ||||
| */ | ||||
| import "C" | ||||
|  | ||||
| import ( | ||||
| 	"math" | ||||
| 	"reflect" | ||||
| 	"unsafe" | ||||
| ) | ||||
|  | ||||
| const i64 = unsafe.Sizeof(int(0)) > 4 | ||||
|  | ||||
| // SQLiteContext behave sqlite3_context | ||||
| type SQLiteContext C.sqlite3_context | ||||
|  | ||||
| // ResultBool sets the result of an SQL function. | ||||
| func (c *SQLiteContext) ResultBool(b bool) { | ||||
| 	if b { | ||||
| 		c.ResultInt(1) | ||||
| 	} else { | ||||
| 		c.ResultInt(0) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ResultBlob sets the result of an SQL function. | ||||
| // See: sqlite3_result_blob, http://sqlite.org/c3ref/result_blob.html | ||||
| func (c *SQLiteContext) ResultBlob(b []byte) { | ||||
| 	if i64 && len(b) > math.MaxInt32 { | ||||
| 		C.sqlite3_result_error_toobig((*C.sqlite3_context)(c)) | ||||
| 		return | ||||
| 	} | ||||
| 	var p *byte | ||||
| 	if len(b) > 0 { | ||||
| 		p = &b[0] | ||||
| 	} | ||||
| 	C.my_result_blob((*C.sqlite3_context)(c), unsafe.Pointer(p), C.int(len(b))) | ||||
| } | ||||
|  | ||||
| // ResultDouble sets the result of an SQL function. | ||||
| // See: sqlite3_result_double, http://sqlite.org/c3ref/result_blob.html | ||||
| func (c *SQLiteContext) ResultDouble(d float64) { | ||||
| 	C.sqlite3_result_double((*C.sqlite3_context)(c), C.double(d)) | ||||
| } | ||||
|  | ||||
| // ResultInt sets the result of an SQL function. | ||||
| // See: sqlite3_result_int, http://sqlite.org/c3ref/result_blob.html | ||||
| func (c *SQLiteContext) ResultInt(i int) { | ||||
| 	if i64 && (i > math.MaxInt32 || i < math.MinInt32) { | ||||
| 		C.sqlite3_result_int64((*C.sqlite3_context)(c), C.sqlite3_int64(i)) | ||||
| 	} else { | ||||
| 		C.sqlite3_result_int((*C.sqlite3_context)(c), C.int(i)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ResultInt64 sets the result of an SQL function. | ||||
| // See: sqlite3_result_int64, http://sqlite.org/c3ref/result_blob.html | ||||
| func (c *SQLiteContext) ResultInt64(i int64) { | ||||
| 	C.sqlite3_result_int64((*C.sqlite3_context)(c), C.sqlite3_int64(i)) | ||||
| } | ||||
|  | ||||
| // ResultNull sets the result of an SQL function. | ||||
| // See: sqlite3_result_null, http://sqlite.org/c3ref/result_blob.html | ||||
| func (c *SQLiteContext) ResultNull() { | ||||
| 	C.sqlite3_result_null((*C.sqlite3_context)(c)) | ||||
| } | ||||
|  | ||||
| // ResultText sets the result of an SQL function. | ||||
| // See: sqlite3_result_text, http://sqlite.org/c3ref/result_blob.html | ||||
| func (c *SQLiteContext) ResultText(s string) { | ||||
| 	h := (*reflect.StringHeader)(unsafe.Pointer(&s)) | ||||
| 	cs, l := (*C.char)(unsafe.Pointer(h.Data)), C.int(h.Len) | ||||
| 	C.my_result_text((*C.sqlite3_context)(c), cs, l) | ||||
| } | ||||
|  | ||||
| // ResultZeroblob sets the result of an SQL function. | ||||
| // See: sqlite3_result_zeroblob, http://sqlite.org/c3ref/result_blob.html | ||||
| func (c *SQLiteContext) ResultZeroblob(n int) { | ||||
| 	C.sqlite3_result_zeroblob((*C.sqlite3_context)(c), C.int(n)) | ||||
| } | ||||
							
								
								
									
										69
									
								
								vendor/github.com/mattn/go-sqlite3/sqlite3_go18.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								vendor/github.com/mattn/go-sqlite3/sqlite3_go18.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | ||||
| // Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>. | ||||
| // | ||||
| // Use of this source code is governed by an MIT-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| // +build go1.8 | ||||
|  | ||||
| package sqlite3 | ||||
|  | ||||
| import ( | ||||
| 	"database/sql/driver" | ||||
| 	"errors" | ||||
|  | ||||
| 	"context" | ||||
| ) | ||||
|  | ||||
| // Ping implement Pinger. | ||||
| func (c *SQLiteConn) Ping(ctx context.Context) error { | ||||
| 	if c.db == nil { | ||||
| 		return errors.New("Connection was closed") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // QueryContext implement QueryerContext. | ||||
| func (c *SQLiteConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) { | ||||
| 	list := make([]namedValue, len(args)) | ||||
| 	for i, nv := range args { | ||||
| 		list[i] = namedValue(nv) | ||||
| 	} | ||||
| 	return c.query(ctx, query, list) | ||||
| } | ||||
|  | ||||
| // ExecContext implement ExecerContext. | ||||
| func (c *SQLiteConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) { | ||||
| 	list := make([]namedValue, len(args)) | ||||
| 	for i, nv := range args { | ||||
| 		list[i] = namedValue(nv) | ||||
| 	} | ||||
| 	return c.exec(ctx, query, list) | ||||
| } | ||||
|  | ||||
| // PrepareContext implement ConnPrepareContext. | ||||
| func (c *SQLiteConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) { | ||||
| 	return c.prepare(ctx, query) | ||||
| } | ||||
|  | ||||
| // BeginTx implement ConnBeginTx. | ||||
| func (c *SQLiteConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { | ||||
| 	return c.begin(ctx) | ||||
| } | ||||
|  | ||||
| // QueryContext implement QueryerContext. | ||||
| func (s *SQLiteStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) { | ||||
| 	list := make([]namedValue, len(args)) | ||||
| 	for i, nv := range args { | ||||
| 		list[i] = namedValue(nv) | ||||
| 	} | ||||
| 	return s.query(ctx, list) | ||||
| } | ||||
|  | ||||
| // ExecContext implement ExecerContext. | ||||
| func (s *SQLiteStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) { | ||||
| 	list := make([]namedValue, len(args)) | ||||
| 	for i, nv := range args { | ||||
| 		list[i] = namedValue(nv) | ||||
| 	} | ||||
| 	return s.exec(ctx, list) | ||||
| } | ||||
							
								
								
									
										2
									
								
								vendor/github.com/mattn/go-sqlite3/sqlite3_icu.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/mattn/go-sqlite3/sqlite3_icu.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -2,7 +2,7 @@ | ||||
| // | ||||
| // Use of this source code is governed by an MIT-style | ||||
| // license that can be found in the LICENSE file. | ||||
| // +build icu  | ||||
| // +build icu | ||||
|  | ||||
| package sqlite3 | ||||
|  | ||||
|   | ||||
							
								
								
									
										4
									
								
								vendor/github.com/mattn/go-sqlite3/sqlite3_libsqlite3.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/mattn/go-sqlite3/sqlite3_libsqlite3.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -8,6 +8,8 @@ package sqlite3 | ||||
|  | ||||
| /* | ||||
| #cgo CFLAGS: -DUSE_LIBSQLITE3 | ||||
| #cgo LDFLAGS: -lsqlite3 | ||||
| #cgo linux LDFLAGS: -lsqlite3 | ||||
| #cgo darwin LDFLAGS: -L/usr/local/opt/sqlite/lib -lsqlite3 | ||||
| #cgo solaris LDFLAGS: -lsqlite3 | ||||
| */ | ||||
| import "C" | ||||
|   | ||||
							
								
								
									
										30
									
								
								vendor/github.com/mattn/go-sqlite3/sqlite3_load_extension.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										30
									
								
								vendor/github.com/mattn/go-sqlite3/sqlite3_load_extension.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -7,7 +7,11 @@ | ||||
| package sqlite3 | ||||
|  | ||||
| /* | ||||
| #ifndef USE_LIBSQLITE3 | ||||
| #include <sqlite3-binding.h> | ||||
| #else | ||||
| #include <sqlite3.h> | ||||
| #endif | ||||
| #include <stdlib.h> | ||||
| */ | ||||
| import "C" | ||||
| @@ -27,6 +31,7 @@ func (c *SQLiteConn) loadExtensions(extensions []string) error { | ||||
| 		defer C.free(unsafe.Pointer(cext)) | ||||
| 		rv = C.sqlite3_load_extension(c.db, cext, nil, nil) | ||||
| 		if rv != C.SQLITE_OK { | ||||
| 			C.sqlite3_enable_load_extension(c.db, 0) | ||||
| 			return errors.New(C.GoString(C.sqlite3_errmsg(c.db))) | ||||
| 		} | ||||
| 	} | ||||
| @@ -37,3 +42,28 @@ func (c *SQLiteConn) loadExtensions(extensions []string) error { | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // LoadExtension load the sqlite3 extension. | ||||
| func (c *SQLiteConn) LoadExtension(lib string, entry string) error { | ||||
| 	rv := C.sqlite3_enable_load_extension(c.db, 1) | ||||
| 	if rv != C.SQLITE_OK { | ||||
| 		return errors.New(C.GoString(C.sqlite3_errmsg(c.db))) | ||||
| 	} | ||||
|  | ||||
| 	clib := C.CString(lib) | ||||
| 	defer C.free(unsafe.Pointer(clib)) | ||||
| 	centry := C.CString(entry) | ||||
| 	defer C.free(unsafe.Pointer(centry)) | ||||
|  | ||||
| 	rv = C.sqlite3_load_extension(c.db, clib, centry, nil) | ||||
| 	if rv != C.SQLITE_OK { | ||||
| 		return errors.New(C.GoString(C.sqlite3_errmsg(c.db))) | ||||
| 	} | ||||
|  | ||||
| 	rv = C.sqlite3_enable_load_extension(c.db, 0) | ||||
| 	if rv != C.SQLITE_OK { | ||||
| 		return errors.New(C.GoString(C.sqlite3_errmsg(c.db))) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|   | ||||
							
								
								
									
										4
									
								
								vendor/github.com/mattn/go-sqlite3/sqlite3_omit_load_extension.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/mattn/go-sqlite3/sqlite3_omit_load_extension.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -17,3 +17,7 @@ import ( | ||||
| func (c *SQLiteConn) loadExtensions(extensions []string) error { | ||||
| 	return errors.New("Extensions have been disabled for static builds") | ||||
| } | ||||
|  | ||||
| func (c *SQLiteConn) LoadExtension(lib string, entry string) error { | ||||
| 	return errors.New("Extensions have been disabled for static builds") | ||||
| } | ||||
|   | ||||
							
								
								
									
										1
									
								
								vendor/github.com/mattn/go-sqlite3/sqlite3_other.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/mattn/go-sqlite3/sqlite3_other.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -9,5 +9,6 @@ package sqlite3 | ||||
| /* | ||||
| #cgo CFLAGS: -I. | ||||
| #cgo linux LDFLAGS: -ldl | ||||
| #cgo solaris LDFLAGS: -lc | ||||
| */ | ||||
| import "C" | ||||
|   | ||||
							
								
								
									
										414
									
								
								vendor/github.com/mattn/go-sqlite3/sqlite3_trace.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										414
									
								
								vendor/github.com/mattn/go-sqlite3/sqlite3_trace.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,414 @@ | ||||
| // Copyright (C) 2016 Yasuhiro Matsumoto <mattn.jp@gmail.com>. | ||||
| // | ||||
| // Use of this source code is governed by an MIT-style | ||||
| // license that can be found in the LICENSE file. | ||||
| // +build trace | ||||
|  | ||||
| package sqlite3 | ||||
|  | ||||
| /* | ||||
| #ifndef USE_LIBSQLITE3 | ||||
| #include <sqlite3-binding.h> | ||||
| #else | ||||
| #include <sqlite3.h> | ||||
| #endif | ||||
| #include <stdlib.h> | ||||
|  | ||||
| void stepTrampoline(sqlite3_context*, int, sqlite3_value**); | ||||
| void doneTrampoline(sqlite3_context*); | ||||
| int traceCallbackTrampoline(unsigned int traceEventCode, void *ctx, void *p, void *x); | ||||
| */ | ||||
| import "C" | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"unsafe" | ||||
| ) | ||||
|  | ||||
| // Trace... constants identify the possible events causing callback invocation. | ||||
| // Values are same as the corresponding SQLite Trace Event Codes. | ||||
| const ( | ||||
| 	TraceStmt    = C.SQLITE_TRACE_STMT | ||||
| 	TraceProfile = C.SQLITE_TRACE_PROFILE | ||||
| 	TraceRow     = C.SQLITE_TRACE_ROW | ||||
| 	TraceClose   = C.SQLITE_TRACE_CLOSE | ||||
| ) | ||||
|  | ||||
| type TraceInfo struct { | ||||
| 	// Pack together the shorter fields, to keep the struct smaller. | ||||
| 	// On a 64-bit machine there would be padding | ||||
| 	// between EventCode and ConnHandle; having AutoCommit here is "free": | ||||
| 	EventCode  uint32 | ||||
| 	AutoCommit bool | ||||
| 	ConnHandle uintptr | ||||
|  | ||||
| 	// Usually filled, unless EventCode = TraceClose = SQLITE_TRACE_CLOSE: | ||||
| 	// identifier for a prepared statement: | ||||
| 	StmtHandle uintptr | ||||
|  | ||||
| 	// Two strings filled when EventCode = TraceStmt = SQLITE_TRACE_STMT: | ||||
| 	// (1) either the unexpanded SQL text of the prepared statement, or | ||||
| 	//     an SQL comment that indicates the invocation of a trigger; | ||||
| 	// (2) expanded SQL, if requested and if (1) is not an SQL comment. | ||||
| 	StmtOrTrigger string | ||||
| 	ExpandedSQL   string // only if requested (TraceConfig.WantExpandedSQL = true) | ||||
|  | ||||
| 	// filled when EventCode = TraceProfile = SQLITE_TRACE_PROFILE: | ||||
| 	// estimated number of nanoseconds that the prepared statement took to run: | ||||
| 	RunTimeNanosec int64 | ||||
|  | ||||
| 	DBError Error | ||||
| } | ||||
|  | ||||
| // TraceUserCallback gives the signature for a trace function | ||||
| // provided by the user (Go application programmer). | ||||
| // SQLite 3.14 documentation (as of September 2, 2016) | ||||
| // for SQL Trace Hook = sqlite3_trace_v2(): | ||||
| // The integer return value from the callback is currently ignored, | ||||
| // though this may change in future releases. Callback implementations | ||||
| // should return zero to ensure future compatibility. | ||||
| type TraceUserCallback func(TraceInfo) int | ||||
|  | ||||
| type TraceConfig struct { | ||||
| 	Callback        TraceUserCallback | ||||
| 	EventMask       C.uint | ||||
| 	WantExpandedSQL bool | ||||
| } | ||||
|  | ||||
| func fillDBError(dbErr *Error, db *C.sqlite3) { | ||||
| 	// See SQLiteConn.lastError(), in file 'sqlite3.go' at the time of writing (Sept 5, 2016) | ||||
| 	dbErr.Code = ErrNo(C.sqlite3_errcode(db)) | ||||
| 	dbErr.ExtendedCode = ErrNoExtended(C.sqlite3_extended_errcode(db)) | ||||
| 	dbErr.err = C.GoString(C.sqlite3_errmsg(db)) | ||||
| } | ||||
|  | ||||
| func fillExpandedSQL(info *TraceInfo, db *C.sqlite3, pStmt unsafe.Pointer) { | ||||
| 	if pStmt == nil { | ||||
| 		panic("No SQLite statement pointer in P arg of trace_v2 callback") | ||||
| 	} | ||||
|  | ||||
| 	expSQLiteCStr := C.sqlite3_expanded_sql((*C.sqlite3_stmt)(pStmt)) | ||||
| 	if expSQLiteCStr == nil { | ||||
| 		fillDBError(&info.DBError, db) | ||||
| 		return | ||||
| 	} | ||||
| 	info.ExpandedSQL = C.GoString(expSQLiteCStr) | ||||
| } | ||||
|  | ||||
| //export traceCallbackTrampoline | ||||
| func traceCallbackTrampoline( | ||||
| 	traceEventCode C.uint, | ||||
| 	// Parameter named 'C' in SQLite docs = Context given at registration: | ||||
| 	ctx unsafe.Pointer, | ||||
| 	// Parameter named 'P' in SQLite docs (Primary event data?): | ||||
| 	p unsafe.Pointer, | ||||
| 	// Parameter named 'X' in SQLite docs (eXtra event data?): | ||||
| 	xValue unsafe.Pointer) C.int { | ||||
|  | ||||
| 	if ctx == nil { | ||||
| 		panic(fmt.Sprintf("No context (ev 0x%x)", traceEventCode)) | ||||
| 	} | ||||
|  | ||||
| 	contextDB := (*C.sqlite3)(ctx) | ||||
| 	connHandle := uintptr(ctx) | ||||
|  | ||||
| 	var traceConf TraceConfig | ||||
| 	var found bool | ||||
| 	if traceEventCode == TraceClose { | ||||
| 		// clean up traceMap: 'pop' means get and delete | ||||
| 		traceConf, found = popTraceMapping(connHandle) | ||||
| 	} else { | ||||
| 		traceConf, found = lookupTraceMapping(connHandle) | ||||
| 	} | ||||
|  | ||||
| 	if !found { | ||||
| 		panic(fmt.Sprintf("Mapping not found for handle 0x%x (ev 0x%x)", | ||||
| 			connHandle, traceEventCode)) | ||||
| 	} | ||||
|  | ||||
| 	var info TraceInfo | ||||
|  | ||||
| 	info.EventCode = uint32(traceEventCode) | ||||
| 	info.AutoCommit = (int(C.sqlite3_get_autocommit(contextDB)) != 0) | ||||
| 	info.ConnHandle = connHandle | ||||
|  | ||||
| 	switch traceEventCode { | ||||
| 	case TraceStmt: | ||||
| 		info.StmtHandle = uintptr(p) | ||||
|  | ||||
| 		var xStr string | ||||
| 		if xValue != nil { | ||||
| 			xStr = C.GoString((*C.char)(xValue)) | ||||
| 		} | ||||
| 		info.StmtOrTrigger = xStr | ||||
| 		if !strings.HasPrefix(xStr, "--") { | ||||
| 			// Not SQL comment, therefore the current event | ||||
| 			// is not related to a trigger. | ||||
| 			// The user might want to receive the expanded SQL; | ||||
| 			// let's check: | ||||
| 			if traceConf.WantExpandedSQL { | ||||
| 				fillExpandedSQL(&info, contextDB, p) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 	case TraceProfile: | ||||
| 		info.StmtHandle = uintptr(p) | ||||
|  | ||||
| 		if xValue == nil { | ||||
| 			panic("NULL pointer in X arg of trace_v2 callback for SQLITE_TRACE_PROFILE event") | ||||
| 		} | ||||
|  | ||||
| 		info.RunTimeNanosec = *(*int64)(xValue) | ||||
|  | ||||
| 		// sample the error //TODO: is it safe? is it useful? | ||||
| 		fillDBError(&info.DBError, contextDB) | ||||
|  | ||||
| 	case TraceRow: | ||||
| 		info.StmtHandle = uintptr(p) | ||||
|  | ||||
| 	case TraceClose: | ||||
| 		handle := uintptr(p) | ||||
| 		if handle != info.ConnHandle { | ||||
| 			panic(fmt.Sprintf("Different conn handle 0x%x (expected 0x%x) in SQLITE_TRACE_CLOSE event.", | ||||
| 				handle, info.ConnHandle)) | ||||
| 		} | ||||
|  | ||||
| 	default: | ||||
| 		// Pass unsupported events to the user callback (if configured); | ||||
| 		// let the user callback decide whether to panic or ignore them. | ||||
| 	} | ||||
|  | ||||
| 	// Do not execute user callback when the event was not requested by user! | ||||
| 	// Remember that the Close event is always selected when | ||||
| 	// registering this callback trampoline with SQLite --- for cleanup. | ||||
| 	// In the future there may be more events forced to "selected" in SQLite | ||||
| 	// for the driver's needs. | ||||
| 	if traceConf.EventMask&traceEventCode == 0 { | ||||
| 		return 0 | ||||
| 	} | ||||
|  | ||||
| 	r := 0 | ||||
| 	if traceConf.Callback != nil { | ||||
| 		r = traceConf.Callback(info) | ||||
| 	} | ||||
| 	return C.int(r) | ||||
| } | ||||
|  | ||||
| type traceMapEntry struct { | ||||
| 	config TraceConfig | ||||
| } | ||||
|  | ||||
| var traceMapLock sync.Mutex | ||||
| var traceMap = make(map[uintptr]traceMapEntry) | ||||
|  | ||||
| func addTraceMapping(connHandle uintptr, traceConf TraceConfig) { | ||||
| 	traceMapLock.Lock() | ||||
| 	defer traceMapLock.Unlock() | ||||
|  | ||||
| 	oldEntryCopy, found := traceMap[connHandle] | ||||
| 	if found { | ||||
| 		panic(fmt.Sprintf("Adding trace config %v: handle 0x%x already registered (%v).", | ||||
| 			traceConf, connHandle, oldEntryCopy.config)) | ||||
| 	} | ||||
| 	traceMap[connHandle] = traceMapEntry{config: traceConf} | ||||
| 	fmt.Printf("Added trace config %v: handle 0x%x.\n", traceConf, connHandle) | ||||
| } | ||||
|  | ||||
| func lookupTraceMapping(connHandle uintptr) (TraceConfig, bool) { | ||||
| 	traceMapLock.Lock() | ||||
| 	defer traceMapLock.Unlock() | ||||
|  | ||||
| 	entryCopy, found := traceMap[connHandle] | ||||
| 	return entryCopy.config, found | ||||
| } | ||||
|  | ||||
| // 'pop' = get and delete from map before returning the value to the caller | ||||
| func popTraceMapping(connHandle uintptr) (TraceConfig, bool) { | ||||
| 	traceMapLock.Lock() | ||||
| 	defer traceMapLock.Unlock() | ||||
|  | ||||
| 	entryCopy, found := traceMap[connHandle] | ||||
| 	if found { | ||||
| 		delete(traceMap, connHandle) | ||||
| 		fmt.Printf("Pop handle 0x%x: deleted trace config %v.\n", connHandle, entryCopy.config) | ||||
| 	} | ||||
| 	return entryCopy.config, found | ||||
| } | ||||
|  | ||||
| // RegisterAggregator makes a Go type available as a SQLite aggregation function. | ||||
| // | ||||
| // Because aggregation is incremental, it's implemented in Go with a | ||||
| // type that has 2 methods: func Step(values) accumulates one row of | ||||
| // data into the accumulator, and func Done() ret finalizes and | ||||
| // returns the aggregate value. "values" and "ret" may be any type | ||||
| // supported by RegisterFunc. | ||||
| // | ||||
| // RegisterAggregator takes as implementation a constructor function | ||||
| // that constructs an instance of the aggregator type each time an | ||||
| // aggregation begins. The constructor must return a pointer to a | ||||
| // type, or an interface that implements Step() and Done(). | ||||
| // | ||||
| // The constructor function and the Step/Done methods may optionally | ||||
| // return an error in addition to their other return values. | ||||
| // | ||||
| // See _example/go_custom_funcs for a detailed example. | ||||
| func (c *SQLiteConn) RegisterAggregator(name string, impl interface{}, pure bool) error { | ||||
| 	var ai aggInfo | ||||
| 	ai.constructor = reflect.ValueOf(impl) | ||||
| 	t := ai.constructor.Type() | ||||
| 	if t.Kind() != reflect.Func { | ||||
| 		return errors.New("non-function passed to RegisterAggregator") | ||||
| 	} | ||||
| 	if t.NumOut() != 1 && t.NumOut() != 2 { | ||||
| 		return errors.New("SQLite aggregator constructors must return 1 or 2 values") | ||||
| 	} | ||||
| 	if t.NumOut() == 2 && !t.Out(1).Implements(reflect.TypeOf((*error)(nil)).Elem()) { | ||||
| 		return errors.New("Second return value of SQLite function must be error") | ||||
| 	} | ||||
| 	if t.NumIn() != 0 { | ||||
| 		return errors.New("SQLite aggregator constructors must not have arguments") | ||||
| 	} | ||||
|  | ||||
| 	agg := t.Out(0) | ||||
| 	switch agg.Kind() { | ||||
| 	case reflect.Ptr, reflect.Interface: | ||||
| 	default: | ||||
| 		return errors.New("SQlite aggregator constructor must return a pointer object") | ||||
| 	} | ||||
| 	stepFn, found := agg.MethodByName("Step") | ||||
| 	if !found { | ||||
| 		return errors.New("SQlite aggregator doesn't have a Step() function") | ||||
| 	} | ||||
| 	step := stepFn.Type | ||||
| 	if step.NumOut() != 0 && step.NumOut() != 1 { | ||||
| 		return errors.New("SQlite aggregator Step() function must return 0 or 1 values") | ||||
| 	} | ||||
| 	if step.NumOut() == 1 && !step.Out(0).Implements(reflect.TypeOf((*error)(nil)).Elem()) { | ||||
| 		return errors.New("type of SQlite aggregator Step() return value must be error") | ||||
| 	} | ||||
|  | ||||
| 	stepNArgs := step.NumIn() | ||||
| 	start := 0 | ||||
| 	if agg.Kind() == reflect.Ptr { | ||||
| 		// Skip over the method receiver | ||||
| 		stepNArgs-- | ||||
| 		start++ | ||||
| 	} | ||||
| 	if step.IsVariadic() { | ||||
| 		stepNArgs-- | ||||
| 	} | ||||
| 	for i := start; i < start+stepNArgs; i++ { | ||||
| 		conv, err := callbackArg(step.In(i)) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		ai.stepArgConverters = append(ai.stepArgConverters, conv) | ||||
| 	} | ||||
| 	if step.IsVariadic() { | ||||
| 		conv, err := callbackArg(t.In(start + stepNArgs).Elem()) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		ai.stepVariadicConverter = conv | ||||
| 		// Pass -1 to sqlite so that it allows any number of | ||||
| 		// arguments. The call helper verifies that the minimum number | ||||
| 		// of arguments is present for variadic functions. | ||||
| 		stepNArgs = -1 | ||||
| 	} | ||||
|  | ||||
| 	doneFn, found := agg.MethodByName("Done") | ||||
| 	if !found { | ||||
| 		return errors.New("SQlite aggregator doesn't have a Done() function") | ||||
| 	} | ||||
| 	done := doneFn.Type | ||||
| 	doneNArgs := done.NumIn() | ||||
| 	if agg.Kind() == reflect.Ptr { | ||||
| 		// Skip over the method receiver | ||||
| 		doneNArgs-- | ||||
| 	} | ||||
| 	if doneNArgs != 0 { | ||||
| 		return errors.New("SQlite aggregator Done() function must have no arguments") | ||||
| 	} | ||||
| 	if done.NumOut() != 1 && done.NumOut() != 2 { | ||||
| 		return errors.New("SQLite aggregator Done() function must return 1 or 2 values") | ||||
| 	} | ||||
| 	if done.NumOut() == 2 && !done.Out(1).Implements(reflect.TypeOf((*error)(nil)).Elem()) { | ||||
| 		return errors.New("second return value of SQLite aggregator Done() function must be error") | ||||
| 	} | ||||
|  | ||||
| 	conv, err := callbackRet(done.Out(0)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	ai.doneRetConverter = conv | ||||
| 	ai.active = make(map[int64]reflect.Value) | ||||
| 	ai.next = 1 | ||||
|  | ||||
| 	// ai must outlast the database connection, or we'll have dangling pointers. | ||||
| 	c.aggregators = append(c.aggregators, &ai) | ||||
|  | ||||
| 	cname := C.CString(name) | ||||
| 	defer C.free(unsafe.Pointer(cname)) | ||||
| 	opts := C.SQLITE_UTF8 | ||||
| 	if pure { | ||||
| 		opts |= C.SQLITE_DETERMINISTIC | ||||
| 	} | ||||
| 	rv := sqlite3CreateFunction(c.db, cname, C.int(stepNArgs), C.int(opts), newHandle(c, &ai), nil, C.stepTrampoline, C.doneTrampoline) | ||||
| 	if rv != C.SQLITE_OK { | ||||
| 		return c.lastError() | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // SetTrace installs or removes the trace callback for the given database connection. | ||||
| // It's not named 'RegisterTrace' because only one callback can be kept and called. | ||||
| // Calling SetTrace a second time on same database connection | ||||
| // overrides (cancels) any prior callback and all its settings: | ||||
| // event mask, etc. | ||||
| func (c *SQLiteConn) SetTrace(requested *TraceConfig) error { | ||||
| 	connHandle := uintptr(unsafe.Pointer(c.db)) | ||||
|  | ||||
| 	_, _ = popTraceMapping(connHandle) | ||||
|  | ||||
| 	if requested == nil { | ||||
| 		// The traceMap entry was deleted already by popTraceMapping(): | ||||
| 		// can disable all events now, no need to watch for TraceClose. | ||||
| 		err := c.setSQLiteTrace(0) | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	reqCopy := *requested | ||||
|  | ||||
| 	// Disable potentially expensive operations | ||||
| 	// if their result will not be used. We are doing this | ||||
| 	// just in case the caller provided nonsensical input. | ||||
| 	if reqCopy.EventMask&TraceStmt == 0 { | ||||
| 		reqCopy.WantExpandedSQL = false | ||||
| 	} | ||||
|  | ||||
| 	addTraceMapping(connHandle, reqCopy) | ||||
|  | ||||
| 	// The callback trampoline function does cleanup on Close event, | ||||
| 	// regardless of the presence or absence of the user callback. | ||||
| 	// Therefore it needs the Close event to be selected: | ||||
| 	actualEventMask := uint(reqCopy.EventMask | TraceClose) | ||||
| 	err := c.setSQLiteTrace(actualEventMask) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func (c *SQLiteConn) setSQLiteTrace(sqliteEventMask uint) error { | ||||
| 	rv := C.sqlite3_trace_v2(c.db, | ||||
| 		C.uint(sqliteEventMask), | ||||
| 		(*[0]byte)(unsafe.Pointer(C.traceCallbackTrampoline)), | ||||
| 		unsafe.Pointer(c.db)) // Fourth arg is same as first: we are | ||||
| 	// passing the database connection handle as callback context. | ||||
|  | ||||
| 	if rv != C.SQLITE_OK { | ||||
| 		return c.lastError() | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										57
									
								
								vendor/github.com/mattn/go-sqlite3/sqlite3_type.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								vendor/github.com/mattn/go-sqlite3/sqlite3_type.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| package sqlite3 | ||||
|  | ||||
| /* | ||||
| #ifndef USE_LIBSQLITE3 | ||||
| #include <sqlite3-binding.h> | ||||
| #else | ||||
| #include <sqlite3.h> | ||||
| #endif | ||||
| */ | ||||
| import "C" | ||||
| import ( | ||||
| 	"reflect" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| // ColumnTypeDatabaseTypeName implement RowsColumnTypeDatabaseTypeName. | ||||
| func (rc *SQLiteRows) ColumnTypeDatabaseTypeName(i int) string { | ||||
| 	return C.GoString(C.sqlite3_column_decltype(rc.s.s, C.int(i))) | ||||
| } | ||||
|  | ||||
| /* | ||||
| func (rc *SQLiteRows) ColumnTypeLength(index int) (length int64, ok bool) { | ||||
| 	return 0, false | ||||
| } | ||||
|  | ||||
| func (rc *SQLiteRows) ColumnTypePrecisionScale(index int) (precision, scale int64, ok bool) { | ||||
| 	return 0, 0, false | ||||
| } | ||||
| */ | ||||
|  | ||||
| // ColumnTypeNullable implement RowsColumnTypeNullable. | ||||
| func (rc *SQLiteRows) ColumnTypeNullable(i int) (nullable, ok bool) { | ||||
| 	return true, true | ||||
| } | ||||
|  | ||||
| // ColumnTypeScanType implement RowsColumnTypeScanType. | ||||
| func (rc *SQLiteRows) ColumnTypeScanType(i int) reflect.Type { | ||||
| 	switch C.sqlite3_column_type(rc.s.s, C.int(i)) { | ||||
| 	case C.SQLITE_INTEGER: | ||||
| 		switch C.GoString(C.sqlite3_column_decltype(rc.s.s, C.int(i))) { | ||||
| 		case "timestamp", "datetime", "date": | ||||
| 			return reflect.TypeOf(time.Time{}) | ||||
| 		case "boolean": | ||||
| 			return reflect.TypeOf(false) | ||||
| 		} | ||||
| 		return reflect.TypeOf(int64(0)) | ||||
| 	case C.SQLITE_FLOAT: | ||||
| 		return reflect.TypeOf(float64(0)) | ||||
| 	case C.SQLITE_BLOB: | ||||
| 		return reflect.SliceOf(reflect.TypeOf(byte(0))) | ||||
| 	case C.SQLITE_NULL: | ||||
| 		return reflect.TypeOf(nil) | ||||
| 	case C.SQLITE_TEXT: | ||||
| 		return reflect.TypeOf("") | ||||
| 	} | ||||
| 	return reflect.SliceOf(reflect.TypeOf(byte(0))) | ||||
| } | ||||
							
								
								
									
										646
									
								
								vendor/github.com/mattn/go-sqlite3/sqlite3_vtable.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										646
									
								
								vendor/github.com/mattn/go-sqlite3/sqlite3_vtable.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,646 @@ | ||||
| // Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>. | ||||
| // | ||||
| // Use of this source code is governed by an MIT-style | ||||
| // license that can be found in the LICENSE file. | ||||
| // +build vtable | ||||
|  | ||||
| package sqlite3 | ||||
|  | ||||
| /* | ||||
| #cgo CFLAGS: -std=gnu99 | ||||
| #cgo CFLAGS: -DSQLITE_ENABLE_RTREE -DSQLITE_THREADSAFE | ||||
| #cgo CFLAGS: -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_FTS4_UNICODE61 | ||||
| #cgo CFLAGS: -DSQLITE_TRACE_SIZE_LIMIT=15 | ||||
| #cgo CFLAGS: -DSQLITE_ENABLE_COLUMN_METADATA=1 | ||||
| #cgo CFLAGS: -Wno-deprecated-declarations | ||||
|  | ||||
| #ifndef USE_LIBSQLITE3 | ||||
| #include <sqlite3-binding.h> | ||||
| #else | ||||
| #include <sqlite3.h> | ||||
| #endif | ||||
| #include <stdlib.h> | ||||
| #include <stdint.h> | ||||
| #include <memory.h> | ||||
|  | ||||
| static inline char *_sqlite3_mprintf(char *zFormat, char *arg) { | ||||
|   return sqlite3_mprintf(zFormat, arg); | ||||
| } | ||||
|  | ||||
| typedef struct goVTab goVTab; | ||||
|  | ||||
| struct goVTab { | ||||
| 	sqlite3_vtab base; | ||||
| 	void *vTab; | ||||
| }; | ||||
|  | ||||
| uintptr_t goMInit(void *db, void *pAux, int argc, char **argv, char **pzErr, int isCreate); | ||||
|  | ||||
| static int cXInit(sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char **pzErr, int isCreate) { | ||||
| 	void *vTab = (void *)goMInit(db, pAux, argc, (char**)argv, pzErr, isCreate); | ||||
| 	if (!vTab || *pzErr) { | ||||
| 		return SQLITE_ERROR; | ||||
| 	} | ||||
| 	goVTab *pvTab = (goVTab *)sqlite3_malloc(sizeof(goVTab)); | ||||
| 	if (!pvTab) { | ||||
| 		*pzErr = sqlite3_mprintf("%s", "Out of memory"); | ||||
| 		return SQLITE_NOMEM; | ||||
| 	} | ||||
| 	memset(pvTab, 0, sizeof(goVTab)); | ||||
| 	pvTab->vTab = vTab; | ||||
|  | ||||
| 	*ppVTab = (sqlite3_vtab *)pvTab; | ||||
| 	*pzErr = 0; | ||||
| 	return SQLITE_OK; | ||||
| } | ||||
|  | ||||
| static inline int cXCreate(sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char **pzErr) { | ||||
| 	return cXInit(db, pAux, argc, argv, ppVTab, pzErr, 1); | ||||
| } | ||||
| static inline int cXConnect(sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char **pzErr) { | ||||
| 	return cXInit(db, pAux, argc, argv, ppVTab, pzErr, 0); | ||||
| } | ||||
|  | ||||
| char* goVBestIndex(void *pVTab, void *icp); | ||||
|  | ||||
| static inline int cXBestIndex(sqlite3_vtab *pVTab, sqlite3_index_info *info) { | ||||
| 	char *pzErr = goVBestIndex(((goVTab*)pVTab)->vTab, info); | ||||
| 	if (pzErr) { | ||||
| 		if (pVTab->zErrMsg) | ||||
| 			sqlite3_free(pVTab->zErrMsg); | ||||
| 		pVTab->zErrMsg = pzErr; | ||||
| 		return SQLITE_ERROR; | ||||
| 	} | ||||
| 	return SQLITE_OK; | ||||
| } | ||||
|  | ||||
| char* goVRelease(void *pVTab, int isDestroy); | ||||
|  | ||||
| static int cXRelease(sqlite3_vtab *pVTab, int isDestroy) { | ||||
| 	char *pzErr = goVRelease(((goVTab*)pVTab)->vTab, isDestroy); | ||||
| 	if (pzErr) { | ||||
| 		if (pVTab->zErrMsg) | ||||
| 			sqlite3_free(pVTab->zErrMsg); | ||||
| 		pVTab->zErrMsg = pzErr; | ||||
| 		return SQLITE_ERROR; | ||||
| 	} | ||||
| 	if (pVTab->zErrMsg) | ||||
| 		sqlite3_free(pVTab->zErrMsg); | ||||
| 	sqlite3_free(pVTab); | ||||
| 	return SQLITE_OK; | ||||
| } | ||||
|  | ||||
| static inline int cXDisconnect(sqlite3_vtab *pVTab) { | ||||
| 	return cXRelease(pVTab, 0); | ||||
| } | ||||
| static inline int cXDestroy(sqlite3_vtab *pVTab) { | ||||
| 	return cXRelease(pVTab, 1); | ||||
| } | ||||
|  | ||||
| typedef struct goVTabCursor goVTabCursor; | ||||
|  | ||||
| struct goVTabCursor { | ||||
| 	sqlite3_vtab_cursor base; | ||||
| 	void *vTabCursor; | ||||
| }; | ||||
|  | ||||
| uintptr_t goVOpen(void *pVTab, char **pzErr); | ||||
|  | ||||
| static int cXOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor) { | ||||
| 	void *vTabCursor = (void *)goVOpen(((goVTab*)pVTab)->vTab, &(pVTab->zErrMsg)); | ||||
| 	goVTabCursor *pCursor = (goVTabCursor *)sqlite3_malloc(sizeof(goVTabCursor)); | ||||
| 	if (!pCursor) { | ||||
| 		return SQLITE_NOMEM; | ||||
| 	} | ||||
| 	memset(pCursor, 0, sizeof(goVTabCursor)); | ||||
| 	pCursor->vTabCursor = vTabCursor; | ||||
| 	*ppCursor = (sqlite3_vtab_cursor *)pCursor; | ||||
| 	return SQLITE_OK; | ||||
| } | ||||
|  | ||||
| static int setErrMsg(sqlite3_vtab_cursor *pCursor, char *pzErr) { | ||||
| 	if (pCursor->pVtab->zErrMsg) | ||||
| 		sqlite3_free(pCursor->pVtab->zErrMsg); | ||||
| 	pCursor->pVtab->zErrMsg = pzErr; | ||||
| 	return SQLITE_ERROR; | ||||
| } | ||||
|  | ||||
| char* goVClose(void *pCursor); | ||||
|  | ||||
| static int cXClose(sqlite3_vtab_cursor *pCursor) { | ||||
| 	char *pzErr = goVClose(((goVTabCursor*)pCursor)->vTabCursor); | ||||
| 	if (pzErr) { | ||||
| 		return setErrMsg(pCursor, pzErr); | ||||
| 	} | ||||
| 	sqlite3_free(pCursor); | ||||
| 	return SQLITE_OK; | ||||
| } | ||||
|  | ||||
| char* goVFilter(void *pCursor, int idxNum, char* idxName, int argc, sqlite3_value **argv); | ||||
|  | ||||
| static int cXFilter(sqlite3_vtab_cursor *pCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv) { | ||||
| 	char *pzErr = goVFilter(((goVTabCursor*)pCursor)->vTabCursor, idxNum, (char*)idxStr, argc, argv); | ||||
| 	if (pzErr) { | ||||
| 		return setErrMsg(pCursor, pzErr); | ||||
| 	} | ||||
| 	return SQLITE_OK; | ||||
| } | ||||
|  | ||||
| char* goVNext(void *pCursor); | ||||
|  | ||||
| static int cXNext(sqlite3_vtab_cursor *pCursor) { | ||||
| 	char *pzErr = goVNext(((goVTabCursor*)pCursor)->vTabCursor); | ||||
| 	if (pzErr) { | ||||
| 		return setErrMsg(pCursor, pzErr); | ||||
| 	} | ||||
| 	return SQLITE_OK; | ||||
| } | ||||
|  | ||||
| int goVEof(void *pCursor); | ||||
|  | ||||
| static inline int cXEof(sqlite3_vtab_cursor *pCursor) { | ||||
| 	return goVEof(((goVTabCursor*)pCursor)->vTabCursor); | ||||
| } | ||||
|  | ||||
| char* goVColumn(void *pCursor, void *cp, int col); | ||||
|  | ||||
| static int cXColumn(sqlite3_vtab_cursor *pCursor, sqlite3_context *ctx, int i) { | ||||
| 	char *pzErr = goVColumn(((goVTabCursor*)pCursor)->vTabCursor, ctx, i); | ||||
| 	if (pzErr) { | ||||
| 		return setErrMsg(pCursor, pzErr); | ||||
| 	} | ||||
| 	return SQLITE_OK; | ||||
| } | ||||
|  | ||||
| char* goVRowid(void *pCursor, sqlite3_int64 *pRowid); | ||||
|  | ||||
| static int cXRowid(sqlite3_vtab_cursor *pCursor, sqlite3_int64 *pRowid) { | ||||
| 	char *pzErr = goVRowid(((goVTabCursor*)pCursor)->vTabCursor, pRowid); | ||||
| 	if (pzErr) { | ||||
| 		return setErrMsg(pCursor, pzErr); | ||||
| 	} | ||||
| 	return SQLITE_OK; | ||||
| } | ||||
|  | ||||
| char* goVUpdate(void *pVTab, int argc, sqlite3_value **argv, sqlite3_int64 *pRowid); | ||||
|  | ||||
| static int cXUpdate(sqlite3_vtab *pVTab, int argc, sqlite3_value **argv, sqlite3_int64 *pRowid) { | ||||
| 	char *pzErr = goVUpdate(((goVTab*)pVTab)->vTab, argc, argv, pRowid); | ||||
| 	if (pzErr) { | ||||
| 		if (pVTab->zErrMsg) | ||||
| 			sqlite3_free(pVTab->zErrMsg); | ||||
| 		pVTab->zErrMsg = pzErr; | ||||
| 		return SQLITE_ERROR; | ||||
| 	} | ||||
| 	return SQLITE_OK; | ||||
| } | ||||
|  | ||||
| static sqlite3_module goModule = { | ||||
| 	0,                       // iVersion | ||||
| 	cXCreate,                // xCreate - create a table | ||||
| 	cXConnect,               // xConnect - connect to an existing table | ||||
| 	cXBestIndex,             // xBestIndex - Determine search strategy | ||||
| 	cXDisconnect,            // xDisconnect - Disconnect from a table | ||||
| 	cXDestroy,               // xDestroy - Drop a table | ||||
| 	cXOpen,                  // xOpen - open a cursor | ||||
| 	cXClose,                 // xClose - close a cursor | ||||
| 	cXFilter,                // xFilter - configure scan constraints | ||||
| 	cXNext,                  // xNext - advance a cursor | ||||
| 	cXEof,                   // xEof | ||||
| 	cXColumn,                // xColumn - read data | ||||
| 	cXRowid,                 // xRowid - read data | ||||
| 	cXUpdate,                // xUpdate - write data | ||||
| // Not implemented | ||||
| 	0,                       // xBegin - begin transaction | ||||
| 	0,                       // xSync - sync transaction | ||||
| 	0,                       // xCommit - commit transaction | ||||
| 	0,                       // xRollback - rollback transaction | ||||
| 	0,                       // xFindFunction - function overloading | ||||
| 	0,                       // xRename - rename the table | ||||
| 	0,                       // xSavepoint | ||||
| 	0,                       // xRelease | ||||
| 	0	                     // xRollbackTo | ||||
| }; | ||||
|  | ||||
| void goMDestroy(void*); | ||||
|  | ||||
| static int _sqlite3_create_module(sqlite3 *db, const char *zName, uintptr_t pClientData) { | ||||
|   return sqlite3_create_module_v2(db, zName, &goModule, (void*) pClientData, goMDestroy); | ||||
| } | ||||
| */ | ||||
| import "C" | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"math" | ||||
| 	"reflect" | ||||
| 	"unsafe" | ||||
| ) | ||||
|  | ||||
| type sqliteModule struct { | ||||
| 	c      *SQLiteConn | ||||
| 	name   string | ||||
| 	module Module | ||||
| } | ||||
|  | ||||
| type sqliteVTab struct { | ||||
| 	module *sqliteModule | ||||
| 	vTab   VTab | ||||
| } | ||||
|  | ||||
| type sqliteVTabCursor struct { | ||||
| 	vTab       *sqliteVTab | ||||
| 	vTabCursor VTabCursor | ||||
| } | ||||
|  | ||||
| // Op is type of operations. | ||||
| type Op uint8 | ||||
|  | ||||
| // Op mean identity of operations. | ||||
| const ( | ||||
| 	OpEQ         Op = 2 | ||||
| 	OpGT            = 4 | ||||
| 	OpLE            = 8 | ||||
| 	OpLT            = 16 | ||||
| 	OpGE            = 32 | ||||
| 	OpMATCH         = 64 | ||||
| 	OpLIKE          = 65 /* 3.10.0 and later only */ | ||||
| 	OpGLOB          = 66 /* 3.10.0 and later only */ | ||||
| 	OpREGEXP        = 67 /* 3.10.0 and later only */ | ||||
| 	OpScanUnique    = 1  /* Scan visits at most 1 row */ | ||||
| ) | ||||
|  | ||||
| // InfoConstraint give information of constraint. | ||||
| type InfoConstraint struct { | ||||
| 	Column int | ||||
| 	Op     Op | ||||
| 	Usable bool | ||||
| } | ||||
|  | ||||
| // InfoOrderBy give information of order-by. | ||||
| type InfoOrderBy struct { | ||||
| 	Column int | ||||
| 	Desc   bool | ||||
| } | ||||
|  | ||||
| func constraints(info *C.sqlite3_index_info) []InfoConstraint { | ||||
| 	l := info.nConstraint | ||||
| 	slice := (*[1 << 30]C.struct_sqlite3_index_constraint)(unsafe.Pointer(info.aConstraint))[:l:l] | ||||
|  | ||||
| 	cst := make([]InfoConstraint, 0, l) | ||||
| 	for _, c := range slice { | ||||
| 		var usable bool | ||||
| 		if c.usable > 0 { | ||||
| 			usable = true | ||||
| 		} | ||||
| 		cst = append(cst, InfoConstraint{ | ||||
| 			Column: int(c.iColumn), | ||||
| 			Op:     Op(c.op), | ||||
| 			Usable: usable, | ||||
| 		}) | ||||
| 	} | ||||
| 	return cst | ||||
| } | ||||
|  | ||||
| func orderBys(info *C.sqlite3_index_info) []InfoOrderBy { | ||||
| 	l := info.nOrderBy | ||||
| 	slice := (*[1 << 30]C.struct_sqlite3_index_orderby)(unsafe.Pointer(info.aOrderBy))[:l:l] | ||||
|  | ||||
| 	ob := make([]InfoOrderBy, 0, l) | ||||
| 	for _, c := range slice { | ||||
| 		var desc bool | ||||
| 		if c.desc > 0 { | ||||
| 			desc = true | ||||
| 		} | ||||
| 		ob = append(ob, InfoOrderBy{ | ||||
| 			Column: int(c.iColumn), | ||||
| 			Desc:   desc, | ||||
| 		}) | ||||
| 	} | ||||
| 	return ob | ||||
| } | ||||
|  | ||||
| // IndexResult is a Go struct representation of what eventually ends up in the | ||||
| // output fields for `sqlite3_index_info` | ||||
| // See: https://www.sqlite.org/c3ref/index_info.html | ||||
| type IndexResult struct { | ||||
| 	Used           []bool // aConstraintUsage | ||||
| 	IdxNum         int | ||||
| 	IdxStr         string | ||||
| 	AlreadyOrdered bool // orderByConsumed | ||||
| 	EstimatedCost  float64 | ||||
| 	EstimatedRows  float64 | ||||
| } | ||||
|  | ||||
| // mPrintf is a utility wrapper around sqlite3_mprintf | ||||
| func mPrintf(format, arg string) *C.char { | ||||
| 	cf := C.CString(format) | ||||
| 	defer C.free(unsafe.Pointer(cf)) | ||||
| 	ca := C.CString(arg) | ||||
| 	defer C.free(unsafe.Pointer(ca)) | ||||
| 	return C._sqlite3_mprintf(cf, ca) | ||||
| } | ||||
|  | ||||
| //export goMInit | ||||
| func goMInit(db, pClientData unsafe.Pointer, argc C.int, argv **C.char, pzErr **C.char, isCreate C.int) C.uintptr_t { | ||||
| 	m := lookupHandle(uintptr(pClientData)).(*sqliteModule) | ||||
| 	if m.c.db != (*C.sqlite3)(db) { | ||||
| 		*pzErr = mPrintf("%s", "Inconsistent db handles") | ||||
| 		return 0 | ||||
| 	} | ||||
| 	args := make([]string, argc) | ||||
| 	var A []*C.char | ||||
| 	slice := reflect.SliceHeader{Data: uintptr(unsafe.Pointer(argv)), Len: int(argc), Cap: int(argc)} | ||||
| 	a := reflect.NewAt(reflect.TypeOf(A), unsafe.Pointer(&slice)).Elem().Interface() | ||||
| 	for i, s := range a.([]*C.char) { | ||||
| 		args[i] = C.GoString(s) | ||||
| 	} | ||||
| 	var vTab VTab | ||||
| 	var err error | ||||
| 	if isCreate == 1 { | ||||
| 		vTab, err = m.module.Create(m.c, args) | ||||
| 	} else { | ||||
| 		vTab, err = m.module.Connect(m.c, args) | ||||
| 	} | ||||
|  | ||||
| 	if err != nil { | ||||
| 		*pzErr = mPrintf("%s", err.Error()) | ||||
| 		return 0 | ||||
| 	} | ||||
| 	vt := sqliteVTab{m, vTab} | ||||
| 	*pzErr = nil | ||||
| 	return C.uintptr_t(newHandle(m.c, &vt)) | ||||
| } | ||||
|  | ||||
| //export goVRelease | ||||
| func goVRelease(pVTab unsafe.Pointer, isDestroy C.int) *C.char { | ||||
| 	vt := lookupHandle(uintptr(pVTab)).(*sqliteVTab) | ||||
| 	var err error | ||||
| 	if isDestroy == 1 { | ||||
| 		err = vt.vTab.Destroy() | ||||
| 	} else { | ||||
| 		err = vt.vTab.Disconnect() | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return mPrintf("%s", err.Error()) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| //export goVOpen | ||||
| func goVOpen(pVTab unsafe.Pointer, pzErr **C.char) C.uintptr_t { | ||||
| 	vt := lookupHandle(uintptr(pVTab)).(*sqliteVTab) | ||||
| 	vTabCursor, err := vt.vTab.Open() | ||||
| 	if err != nil { | ||||
| 		*pzErr = mPrintf("%s", err.Error()) | ||||
| 		return 0 | ||||
| 	} | ||||
| 	vtc := sqliteVTabCursor{vt, vTabCursor} | ||||
| 	*pzErr = nil | ||||
| 	return C.uintptr_t(newHandle(vt.module.c, &vtc)) | ||||
| } | ||||
|  | ||||
| //export goVBestIndex | ||||
| func goVBestIndex(pVTab unsafe.Pointer, icp unsafe.Pointer) *C.char { | ||||
| 	vt := lookupHandle(uintptr(pVTab)).(*sqliteVTab) | ||||
| 	info := (*C.sqlite3_index_info)(icp) | ||||
| 	csts := constraints(info) | ||||
| 	res, err := vt.vTab.BestIndex(csts, orderBys(info)) | ||||
| 	if err != nil { | ||||
| 		return mPrintf("%s", err.Error()) | ||||
| 	} | ||||
| 	if len(res.Used) != len(csts) { | ||||
| 		return mPrintf("Result.Used != expected value", "") | ||||
| 	} | ||||
|  | ||||
| 	// Get a pointer to constraint_usage struct so we can update in place. | ||||
| 	l := info.nConstraint | ||||
| 	s := (*[1 << 30]C.struct_sqlite3_index_constraint_usage)(unsafe.Pointer(info.aConstraintUsage))[:l:l] | ||||
| 	index := 1 | ||||
| 	for i := C.int(0); i < info.nConstraint; i++ { | ||||
| 		if res.Used[i] { | ||||
| 			s[i].argvIndex = C.int(index) | ||||
| 			s[i].omit = C.uchar(1) | ||||
| 			index++ | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	info.idxNum = C.int(res.IdxNum) | ||||
| 	idxStr := C.CString(res.IdxStr) | ||||
| 	defer C.free(unsafe.Pointer(idxStr)) | ||||
| 	info.idxStr = idxStr | ||||
| 	info.needToFreeIdxStr = C.int(0) | ||||
| 	if res.AlreadyOrdered { | ||||
| 		info.orderByConsumed = C.int(1) | ||||
| 	} | ||||
| 	info.estimatedCost = C.double(res.EstimatedCost) | ||||
| 	info.estimatedRows = C.sqlite3_int64(res.EstimatedRows) | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| //export goVClose | ||||
| func goVClose(pCursor unsafe.Pointer) *C.char { | ||||
| 	vtc := lookupHandle(uintptr(pCursor)).(*sqliteVTabCursor) | ||||
| 	err := vtc.vTabCursor.Close() | ||||
| 	if err != nil { | ||||
| 		return mPrintf("%s", err.Error()) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| //export goMDestroy | ||||
| func goMDestroy(pClientData unsafe.Pointer) { | ||||
| 	m := lookupHandle(uintptr(pClientData)).(*sqliteModule) | ||||
| 	m.module.DestroyModule() | ||||
| } | ||||
|  | ||||
| //export goVFilter | ||||
| func goVFilter(pCursor unsafe.Pointer, idxNum C.int, idxName *C.char, argc C.int, argv **C.sqlite3_value) *C.char { | ||||
| 	vtc := lookupHandle(uintptr(pCursor)).(*sqliteVTabCursor) | ||||
| 	args := (*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.sqlite3_value)(nil))]*C.sqlite3_value)(unsafe.Pointer(argv))[:argc:argc] | ||||
| 	vals := make([]interface{}, 0, argc) | ||||
| 	for _, v := range args { | ||||
| 		conv, err := callbackArgGeneric(v) | ||||
| 		if err != nil { | ||||
| 			return mPrintf("%s", err.Error()) | ||||
| 		} | ||||
| 		vals = append(vals, conv.Interface()) | ||||
| 	} | ||||
| 	err := vtc.vTabCursor.Filter(int(idxNum), C.GoString(idxName), vals) | ||||
| 	if err != nil { | ||||
| 		return mPrintf("%s", err.Error()) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| //export goVNext | ||||
| func goVNext(pCursor unsafe.Pointer) *C.char { | ||||
| 	vtc := lookupHandle(uintptr(pCursor)).(*sqliteVTabCursor) | ||||
| 	err := vtc.vTabCursor.Next() | ||||
| 	if err != nil { | ||||
| 		return mPrintf("%s", err.Error()) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| //export goVEof | ||||
| func goVEof(pCursor unsafe.Pointer) C.int { | ||||
| 	vtc := lookupHandle(uintptr(pCursor)).(*sqliteVTabCursor) | ||||
| 	err := vtc.vTabCursor.EOF() | ||||
| 	if err { | ||||
| 		return 1 | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| //export goVColumn | ||||
| func goVColumn(pCursor, cp unsafe.Pointer, col C.int) *C.char { | ||||
| 	vtc := lookupHandle(uintptr(pCursor)).(*sqliteVTabCursor) | ||||
| 	c := (*SQLiteContext)(cp) | ||||
| 	err := vtc.vTabCursor.Column(c, int(col)) | ||||
| 	if err != nil { | ||||
| 		return mPrintf("%s", err.Error()) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| //export goVRowid | ||||
| func goVRowid(pCursor unsafe.Pointer, pRowid *C.sqlite3_int64) *C.char { | ||||
| 	vtc := lookupHandle(uintptr(pCursor)).(*sqliteVTabCursor) | ||||
| 	rowid, err := vtc.vTabCursor.Rowid() | ||||
| 	if err != nil { | ||||
| 		return mPrintf("%s", err.Error()) | ||||
| 	} | ||||
| 	*pRowid = C.sqlite3_int64(rowid) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| //export goVUpdate | ||||
| func goVUpdate(pVTab unsafe.Pointer, argc C.int, argv **C.sqlite3_value, pRowid *C.sqlite3_int64) *C.char { | ||||
| 	vt := lookupHandle(uintptr(pVTab)).(*sqliteVTab) | ||||
|  | ||||
| 	var tname string | ||||
| 	if n, ok := vt.vTab.(interface { | ||||
| 		TableName() string | ||||
| 	}); ok { | ||||
| 		tname = n.TableName() + " " | ||||
| 	} | ||||
|  | ||||
| 	err := fmt.Errorf("virtual %s table %sis read-only", vt.module.name, tname) | ||||
| 	if v, ok := vt.vTab.(VTabUpdater); ok { | ||||
| 		// convert argv | ||||
| 		args := (*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.sqlite3_value)(nil))]*C.sqlite3_value)(unsafe.Pointer(argv))[:argc:argc] | ||||
| 		vals := make([]interface{}, 0, argc) | ||||
| 		for _, v := range args { | ||||
| 			conv, err := callbackArgGeneric(v) | ||||
| 			if err != nil { | ||||
| 				return mPrintf("%s", err.Error()) | ||||
| 			} | ||||
|  | ||||
| 			// work around for SQLITE_NULL | ||||
| 			x := conv.Interface() | ||||
| 			if z, ok := x.([]byte); ok && z == nil { | ||||
| 				x = nil | ||||
| 			} | ||||
|  | ||||
| 			vals = append(vals, x) | ||||
| 		} | ||||
|  | ||||
| 		switch { | ||||
| 		case argc == 1: | ||||
| 			err = v.Delete(vals[0]) | ||||
|  | ||||
| 		case argc > 1 && vals[0] == nil: | ||||
| 			var id int64 | ||||
| 			id, err = v.Insert(vals[1], vals[2:]) | ||||
| 			if err == nil { | ||||
| 				*pRowid = C.sqlite3_int64(id) | ||||
| 			} | ||||
|  | ||||
| 		case argc > 1: | ||||
| 			err = v.Update(vals[1], vals[2:]) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return mPrintf("%s", err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Module is a "virtual table module", it defines the implementation of a | ||||
| // virtual tables. See: http://sqlite.org/c3ref/module.html | ||||
| type Module interface { | ||||
| 	// http://sqlite.org/vtab.html#xcreate | ||||
| 	Create(c *SQLiteConn, args []string) (VTab, error) | ||||
| 	// http://sqlite.org/vtab.html#xconnect | ||||
| 	Connect(c *SQLiteConn, args []string) (VTab, error) | ||||
| 	// http://sqlite.org/c3ref/create_module.html | ||||
| 	DestroyModule() | ||||
| } | ||||
|  | ||||
| // VTab describes a particular instance of the virtual table. | ||||
| // See: http://sqlite.org/c3ref/vtab.html | ||||
| type VTab interface { | ||||
| 	// http://sqlite.org/vtab.html#xbestindex | ||||
| 	BestIndex([]InfoConstraint, []InfoOrderBy) (*IndexResult, error) | ||||
| 	// http://sqlite.org/vtab.html#xdisconnect | ||||
| 	Disconnect() error | ||||
| 	// http://sqlite.org/vtab.html#sqlite3_module.xDestroy | ||||
| 	Destroy() error | ||||
| 	// http://sqlite.org/vtab.html#xopen | ||||
| 	Open() (VTabCursor, error) | ||||
| } | ||||
|  | ||||
| // VTabUpdater is a type that allows a VTab to be inserted, updated, or | ||||
| // deleted. | ||||
| // See: https://sqlite.org/vtab.html#xupdate | ||||
| type VTabUpdater interface { | ||||
| 	Delete(interface{}) error | ||||
| 	Insert(interface{}, []interface{}) (int64, error) | ||||
| 	Update(interface{}, []interface{}) error | ||||
| } | ||||
|  | ||||
| // VTabCursor describes cursors that point into the virtual table and are used | ||||
| // to loop through the virtual table. See: http://sqlite.org/c3ref/vtab_cursor.html | ||||
| type VTabCursor interface { | ||||
| 	// http://sqlite.org/vtab.html#xclose | ||||
| 	Close() error | ||||
| 	// http://sqlite.org/vtab.html#xfilter | ||||
| 	Filter(idxNum int, idxStr string, vals []interface{}) error | ||||
| 	// http://sqlite.org/vtab.html#xnext | ||||
| 	Next() error | ||||
| 	// http://sqlite.org/vtab.html#xeof | ||||
| 	EOF() bool | ||||
| 	// http://sqlite.org/vtab.html#xcolumn | ||||
| 	Column(c *SQLiteContext, col int) error | ||||
| 	// http://sqlite.org/vtab.html#xrowid | ||||
| 	Rowid() (int64, error) | ||||
| } | ||||
|  | ||||
| // DeclareVTab declares the Schema of a virtual table. | ||||
| // See: http://sqlite.org/c3ref/declare_vtab.html | ||||
| func (c *SQLiteConn) DeclareVTab(sql string) error { | ||||
| 	zSQL := C.CString(sql) | ||||
| 	defer C.free(unsafe.Pointer(zSQL)) | ||||
| 	rv := C.sqlite3_declare_vtab(c.db, zSQL) | ||||
| 	if rv != C.SQLITE_OK { | ||||
| 		return c.lastError() | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // CreateModule registers a virtual table implementation. | ||||
| // See: http://sqlite.org/c3ref/create_module.html | ||||
| func (c *SQLiteConn) CreateModule(moduleName string, module Module) error { | ||||
| 	mname := C.CString(moduleName) | ||||
| 	defer C.free(unsafe.Pointer(mname)) | ||||
| 	udm := sqliteModule{c, moduleName, module} | ||||
| 	rv := C._sqlite3_create_module(c.db, mname, C.uintptr_t(newHandle(c, &udm))) | ||||
| 	if rv != C.SQLITE_OK { | ||||
| 		return c.lastError() | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| @@ -1,3 +1,4 @@ | ||||
| #ifndef USE_LIBSQLITE3 | ||||
| /*
 | ||||
| ** 2006 June 7 | ||||
| ** | ||||
| @@ -15,11 +16,9 @@ | ||||
| ** as extensions by SQLite should #include this file instead of  | ||||
| ** sqlite3.h. | ||||
| */ | ||||
| #ifndef _SQLITE3EXT_H_ | ||||
| #define _SQLITE3EXT_H_ | ||||
| #include "sqlite3-binding.h" | ||||
| 
 | ||||
| typedef struct sqlite3_api_routines sqlite3_api_routines; | ||||
| #ifndef SQLITE3EXT_H | ||||
| #define SQLITE3EXT_H | ||||
| #include "sqlite3.h" | ||||
| 
 | ||||
| /*
 | ||||
| ** The following structure holds pointers to all of the SQLite API | ||||
| @@ -279,8 +278,23 @@ struct sqlite3_api_routines { | ||||
|   int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int); | ||||
|   int (*strlike)(const char*,const char*,unsigned int); | ||||
|   int (*db_cacheflush)(sqlite3*); | ||||
|   /* Version 3.12.0 and later */ | ||||
|   int (*system_errno)(sqlite3*); | ||||
|   /* Version 3.14.0 and later */ | ||||
|   int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*); | ||||
|   char *(*expanded_sql)(sqlite3_stmt*); | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
| ** This is the function signature used for all extension entry points.  It | ||||
| ** is also defined in the file "loadext.c". | ||||
| */ | ||||
| typedef int (*sqlite3_loadext_entry)( | ||||
|   sqlite3 *db,                       /* Handle to the database. */ | ||||
|   char **pzErrMsg,                   /* Used to set error string on failure. */ | ||||
|   const sqlite3_api_routines *pThunk /* Extension API function pointers. */ | ||||
| ); | ||||
| 
 | ||||
| /*
 | ||||
| ** The following macros redefine the API routines so that they are | ||||
| ** redirected through the global sqlite3_api structure. | ||||
| @@ -522,6 +536,11 @@ struct sqlite3_api_routines { | ||||
| #define sqlite3_status64               sqlite3_api->status64 | ||||
| #define sqlite3_strlike                sqlite3_api->strlike | ||||
| #define sqlite3_db_cacheflush          sqlite3_api->db_cacheflush | ||||
| /* Version 3.12.0 and later */ | ||||
| #define sqlite3_system_errno           sqlite3_api->system_errno | ||||
| /* Version 3.14.0 and later */ | ||||
| #define sqlite3_trace_v2               sqlite3_api->trace_v2 | ||||
| #define sqlite3_expanded_sql           sqlite3_api->expanded_sql | ||||
| #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ | ||||
| 
 | ||||
| #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) | ||||
| @@ -539,4 +558,8 @@ struct sqlite3_api_routines { | ||||
| # define SQLITE_EXTENSION_INIT3     /*no-op*/ | ||||
| #endif | ||||
| 
 | ||||
| #endif /* _SQLITE3EXT_H_ */ | ||||
| #endif /* SQLITE3EXT_H */ | ||||
| #else // USE_LIBSQLITE3
 | ||||
|  // If users really want to link against the system sqlite3 we
 | ||||
| // need to make this file a noop.
 | ||||
|  #endif | ||||
							
								
								
									
										99
									
								
								vendor/github.com/mattn/go-sqlite3/tool/upgrade.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								vendor/github.com/mattn/go-sqlite3/tool/upgrade.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,99 @@ | ||||
| // +build ignore | ||||
|  | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"archive/zip" | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"log" | ||||
| 	"net/http" | ||||
| 	"os" | ||||
| 	"path" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/PuerkitoBio/goquery" | ||||
| ) | ||||
|  | ||||
| func main() { | ||||
| 	site := "https://www.sqlite.org/download.html" | ||||
| 	fmt.Printf("scraping %v\n", site) | ||||
| 	doc, err := goquery.NewDocument(site) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 	var url string | ||||
| 	doc.Find("a").Each(func(_ int, s *goquery.Selection) { | ||||
| 		if url == "" && strings.HasPrefix(s.Text(), "sqlite-amalgamation-") { | ||||
| 			url = "https://www.sqlite.org/2017/" + s.Text() | ||||
| 		} | ||||
| 	}) | ||||
| 	if url == "" { | ||||
| 		return | ||||
| 	} | ||||
| 	fmt.Printf("downloading %v\n", url) | ||||
| 	resp, err := http.Get(url) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	b, err := ioutil.ReadAll(resp.Body) | ||||
| 	if err != nil { | ||||
| 		resp.Body.Close() | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	fmt.Printf("extracting %v\n", path.Base(url)) | ||||
| 	r, err := zip.NewReader(bytes.NewReader(b), resp.ContentLength) | ||||
| 	if err != nil { | ||||
| 		resp.Body.Close() | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 	resp.Body.Close() | ||||
|  | ||||
| 	for _, zf := range r.File { | ||||
| 		var f *os.File | ||||
| 		switch path.Base(zf.Name) { | ||||
| 		case "sqlite3.c": | ||||
| 			f, err = os.Create("sqlite3-binding.c") | ||||
| 		case "sqlite3.h": | ||||
| 			f, err = os.Create("sqlite3-binding.h") | ||||
| 		case "sqlite3ext.h": | ||||
| 			f, err = os.Create("sqlite3ext.h") | ||||
| 		default: | ||||
| 			continue | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			log.Fatal(err) | ||||
| 		} | ||||
| 		zr, err := zf.Open() | ||||
| 		if err != nil { | ||||
| 			log.Fatal(err) | ||||
| 		} | ||||
|  | ||||
| 		_, err = io.WriteString(f, "#ifndef USE_LIBSQLITE3\n") | ||||
| 		if err != nil { | ||||
| 			zr.Close() | ||||
| 			f.Close() | ||||
| 			log.Fatal(err) | ||||
| 		} | ||||
| 		_, err = io.Copy(f, zr) | ||||
| 		if err != nil { | ||||
| 			zr.Close() | ||||
| 			f.Close() | ||||
| 			log.Fatal(err) | ||||
| 		} | ||||
| 		_, err = io.WriteString(f, "#else // USE_LIBSQLITE3\n // If users really want to link against the system sqlite3 we\n// need to make this file a noop.\n #endif") | ||||
| 		if err != nil { | ||||
| 			zr.Close() | ||||
| 			f.Close() | ||||
| 			log.Fatal(err) | ||||
| 		} | ||||
| 		zr.Close() | ||||
| 		f.Close() | ||||
| 		fmt.Printf("extracted %v\n", filepath.Base(f.Name())) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										5
									
								
								vendor/vendor.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/vendor.json
									
									
									
									
										vendored
									
									
								
							| @@ -644,9 +644,10 @@ | ||||
| 			"revisionTime": "2016-01-26T19:01:36+01:00" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"checksumSHA1": "nwSNZJ3vawDOJytOB86EWGKXJ+U=", | ||||
| 			"path": "github.com/mattn/go-sqlite3", | ||||
| 			"revision": "10876d7dac65f02064c03d7372a2f1dfb90043fe", | ||||
| 			"revisionTime": "2016-03-07T18:57:06+09:00", | ||||
| 			"revision": "05548ff55570cdb9ac72ff4a25a3b5e77a6fb7e5", | ||||
| 			"revisionTime": "2017-09-01T08:40:05Z", | ||||
| 			"tree": true | ||||
| 		}, | ||||
| 		{ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user