diff --git a/.gitignore b/.gitignore index 9b1ee42..4fb8eb6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore - +*.so +*.dylib # Logs logs diff --git a/cgo/dal.go b/cgo/dal.go new file mode 100644 index 0000000..b2a9f7a --- /dev/null +++ b/cgo/dal.go @@ -0,0 +1,31 @@ +package main + +// #include +import "C" +import ( + "strings" + "unsafe" + + "l12.xyz/dal/facade" +) + +//export InitSQLite +func InitSQLite(pragmas *C.char) { + str := C.GoString(pragmas) + pragmasArray := strings.Split(str, ";") + facade.InitSQLite(pragmasArray) +} + +//export HandleQuery +func HandleQuery(input *C.char) *C.char { + var in, out []byte + inPtr := unsafe.Pointer(input) + defer C.free(inPtr) + + in = C.GoBytes(inPtr, C.int(len(C.GoString(input)))) + facade.HandleQuery(&in, &out) + output := C.CString(string(out)) + return output +} + +func main() {} diff --git a/cgo/dal.h b/cgo/dal.h new file mode 100644 index 0000000..dab4483 --- /dev/null +++ b/cgo/dal.h @@ -0,0 +1,86 @@ +/* Code generated by cmd/cgo; DO NOT EDIT. */ + +/* package command-line-arguments */ + + +#line 1 "cgo-builtin-export-prolog" + +#include + +#ifndef GO_CGO_EXPORT_PROLOGUE_H +#define GO_CGO_EXPORT_PROLOGUE_H + +#ifndef GO_CGO_GOSTRING_TYPEDEF +typedef struct { const char *p; ptrdiff_t n; } _GoString_; +#endif + +#endif + +/* Start of preamble from import "C" comments. */ + + +#line 3 "dal.go" + #include + +#line 1 "cgo-generated-wrapper" + + +/* End of preamble from import "C" comments. */ + + +/* Start of boilerplate cgo prologue. */ +#line 1 "cgo-gcc-export-header-prolog" + +#ifndef GO_CGO_PROLOGUE_H +#define GO_CGO_PROLOGUE_H + +typedef signed char GoInt8; +typedef unsigned char GoUint8; +typedef short GoInt16; +typedef unsigned short GoUint16; +typedef int GoInt32; +typedef unsigned int GoUint32; +typedef long long GoInt64; +typedef unsigned long long GoUint64; +typedef GoInt64 GoInt; +typedef GoUint64 GoUint; +typedef size_t GoUintptr; +typedef float GoFloat32; +typedef double GoFloat64; +#ifdef _MSC_VER +#include +typedef _Fcomplex GoComplex64; +typedef _Dcomplex GoComplex128; +#else +typedef float _Complex GoComplex64; +typedef double _Complex GoComplex128; +#endif + +/* + static assertion to make sure the file is being used on architecture + at least with matching size of GoInt. +*/ +typedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*)==64/8 ? 1:-1]; + +#ifndef GO_CGO_GOSTRING_TYPEDEF +typedef _GoString_ GoString; +#endif +typedef void *GoMap; +typedef void *GoChan; +typedef struct { void *t; void *v; } GoInterface; +typedef struct { void *data; GoInt len; GoInt cap; } GoSlice; + +#endif + +/* End of boilerplate cgo prologue. */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern void InitSQLite(char* pragmas); +extern char* HandleQuery(char* input); + +#ifdef __cplusplus +} +#endif diff --git a/cgo/go.mod b/cgo/go.mod new file mode 100644 index 0000000..f703f8f --- /dev/null +++ b/cgo/go.mod @@ -0,0 +1,33 @@ +module srv + +go 1.22.6 + +replace l12.xyz/dal/filters v0.0.0 => ../pkg/filters + +replace l12.xyz/dal/builder v0.0.0 => ../pkg/builder + +replace l12.xyz/dal/handler v0.0.0 => ../pkg/handler + +require l12.xyz/dal/adapter v0.0.0 // indirect + +replace l12.xyz/dal/adapter v0.0.0 => ../pkg/adapter + +replace l12.xyz/dal/utils v0.0.0 => ../pkg/utils + +replace l12.xyz/dal/proto v0.0.0 => ../pkg/proto + +require l12.xyz/dal/facade v0.0.0 + +require l12.xyz/dal/handler v0.0.0 // indirect + +replace l12.xyz/dal/facade v0.0.0 => ../pkg/facade + +require ( + github.com/philhofer/fwd v1.1.3-0.20240612014219-fbbf4953d986 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/tinylib/msgp v1.2.0 // indirect + l12.xyz/dal/builder v0.0.0 // indirect + l12.xyz/dal/filters v0.0.0 // indirect + l12.xyz/dal/proto v0.0.0 // indirect + l12.xyz/dal/utils v0.0.0 // indirect +) diff --git a/cgo/go.sum b/cgo/go.sum new file mode 100644 index 0000000..5cf32ca --- /dev/null +++ b/cgo/go.sum @@ -0,0 +1,8 @@ +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/philhofer/fwd v1.1.3-0.20240612014219-fbbf4953d986 h1:jYi87L8j62qkXzaYHAQAhEapgukhenIMZRBKTNRLHJ4= +github.com/philhofer/fwd v1.1.3-0.20240612014219-fbbf4953d986/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/tinylib/msgp v1.2.0 h1:0uKB/662twsVBpYUPbokj4sTSKhWFKB7LopO2kWK8lY= +github.com/tinylib/msgp v1.2.0/go.mod h1:2vIGs3lcUo8izAATNobrCHevYZC/LMsJtw4JPiYPHro= diff --git a/pkg/facade/SQLIteShared.go b/pkg/facade/SQLIteShared.go new file mode 100644 index 0000000..720b06b --- /dev/null +++ b/pkg/facade/SQLIteShared.go @@ -0,0 +1,78 @@ +package facade + +import ( + "log" + "reflect" + + "l12.xyz/dal/adapter" + "l12.xyz/dal/proto" +) + +var db adapter.DBAdapter + +func InitSQLite(pragmas []string) { + if db.Type == "" { + adapter.RegisterDialect("sqlite3", adapter.CommonDialect{}) + db = adapter.DBAdapter{ + Type: "sqlite3", + } + db.AfterOpen("PRAGMA journal_mode=WAL") + } + for _, pragma := range pragmas { + if pragma == "" { + continue + } + db.AfterOpen(pragma) + } +} + +func HandleQuery(input *[]byte, output *[]byte) int { + InitSQLite([]string{}) + req := proto.Request{} + _, err := req.UnmarshalMsg(*input) + if err != nil { + log.Printf("failed to unmarshal request: %v", err) + return 1 + } + query, err := req.Parse(adapter.GetDialect(db.Type)) + if err != nil { + log.Printf("failed to parse request: %v", err) + return 1 + } + if query.Exec { + result, err := db.Exec(query) + if err != nil { + log.Printf("failed to exec query: %v", err) + return 1 + } + ra, _ := result.RowsAffected() + la, _ := result.LastInsertId() + res := proto.Response{ + Id: 0, + RowsAffected: ra, + LastInsertId: la, + } + *output, _ = res.MarshalMsg(nil) + return 0 + } + rows, err := db.Query(query) + if err != nil { + log.Printf("failed to query: %v", err) + return 1 + } + columns, _ := rows.Columns() + types, _ := rows.ColumnTypes() + cols, _ := proto.MarshalRow(columns) + *output = append(*output, cols...) + for rows.Next() { + data := make([]interface{}, len(columns)) + for i := range data { + typ := reflect.New(types[i].ScanType()).Interface() + data[i] = &typ + } + rows.Scan(data...) + cols, _ := proto.MarshalRow(data) + *output = append(*output, cols...) + } + return 0 +} diff --git a/pkg/facade/SQLiteServer.go b/pkg/facade/SQLiteServer.go index c609c1b..8995317 100644 --- a/pkg/facade/SQLiteServer.go +++ b/pkg/facade/SQLiteServer.go @@ -1,6 +1,7 @@ package facade import ( + "log" "net/http" "os" "strings" @@ -64,6 +65,8 @@ Use `GetHandler` to get a handler for a custom server. */ func (s *SQLiteServer) Serve() { s.Init() + log.Println("Starting server on port " + s.Port) + log.Println("Using directory: " + s.Cwd) err := http.ListenAndServe(":"+s.Port, s.GetHandler()) if err != nil { panic(err)