Skip to content
Merged
5 changes: 4 additions & 1 deletion error_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ func TestCorruptDbErrors(t *testing.T) {
_, err = db.Exec("drop table foo")
}

sqliteErr := err.(Error)
sqliteErr, ok := err.(Error)
if !ok {
t.Fatal(err)
}
if sqliteErr.Code != ErrNotADB {
t.Error("wrong error code for corrupted DB")
}
Expand Down
43 changes: 35 additions & 8 deletions sqlite3-binding.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#ifndef USE_LIBSQLITE3
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
** version 3.50.3. By combining all the individual C code files into this
** version 3.50.4. By combining all the individual C code files into this
** single large file, the entire code can be compiled as a single translation
** unit. This allows many compilers to do optimizations that would not be
** possible if the files were compiled separately. Performance improvements
Expand All @@ -19,7 +19,7 @@
** separate file. This file contains only code for the core SQLite library.
**
** The content in this amalgamation comes from Fossil check-in
** 3ce993b8657d6d9deda380a93cdd6404a8c8 with changes in files:
** 4d8adfb30e03f9cf27f800a2c1ba3c48fb4c with changes in files:
**
**
*/
Expand Down Expand Up @@ -466,9 +466,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.50.3"
#define SQLITE_VERSION_NUMBER 3050003
#define SQLITE_SOURCE_ID "2025-07-17 13:25:10 3ce993b8657d6d9deda380a93cdd6404a8c8ba1b185b2bc423703e41ae5f2543"
#define SQLITE_VERSION "3.50.4"
#define SQLITE_VERSION_NUMBER 3050004
#define SQLITE_SOURCE_ID "2025-07-30 19:33:53 4d8adfb30e03f9cf27f800a2c1ba3c48fb4ca1b08b0f5ed59a4d5ecbf45e20a3"

/*
** CAPI3REF: Run-Time Library Version Numbers
Expand Down Expand Up @@ -19441,6 +19441,7 @@ struct Expr {
Table *pTab; /* TK_COLUMN: Table containing column. Can be NULL
** for a column of an index on an expression */
Window *pWin; /* EP_WinFunc: Window/Filter defn for a function */
int nReg; /* TK_NULLS: Number of registers to NULL out */
struct { /* TK_IN, TK_SELECT, and TK_EXISTS */
int iAddr; /* Subroutine entry address */
int regReturn; /* Register used to hold return address */
Expand Down Expand Up @@ -21475,6 +21476,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn(Parse*, Table*, Column*, int)
SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse*, Expr*, int);
SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse*, Expr*, int);
SQLITE_PRIVATE int sqlite3ExprCodeRunJustOnce(Parse*, Expr*, int);
SQLITE_PRIVATE void sqlite3ExprNullRegisterRange(Parse*, int, int);
SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse*, Expr*, int*);
SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse*, Expr*, int);
SQLITE_PRIVATE int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int, u8);
Expand Down Expand Up @@ -115242,6 +115244,12 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
sqlite3VdbeLoadString(v, target, pExpr->u.zToken);
return target;
}
case TK_NULLS: {
/* Set a range of registers to NULL. pExpr->y.nReg registers starting
** with target */
sqlite3VdbeAddOp3(v, OP_Null, 0, target, target + pExpr->y.nReg - 1);
return target;
}
default: {
/* Make NULL the default case so that if a bug causes an illegal
** Expr node to be passed into this function, it will be handled
Expand Down Expand Up @@ -115926,6 +115934,25 @@ SQLITE_PRIVATE int sqlite3ExprCodeRunJustOnce(
return regDest;
}

/*
** Make arrangements to invoke OP_Null on a range of registers
** during initialization.
*/
SQLITE_PRIVATE SQLITE_NOINLINE void sqlite3ExprNullRegisterRange(
Parse *pParse, /* Parsing context */
int iReg, /* First register to set to NULL */
int nReg /* Number of sequential registers to NULL out */
){
u8 okConstFactor = pParse->okConstFactor;
Expr t;
memset(&t, 0, sizeof(t));
t.op = TK_NULLS;
t.y.nReg = nReg;
pParse->okConstFactor = 1;
sqlite3ExprCodeRunJustOnce(pParse, &t, iReg);
pParse->okConstFactor = okConstFactor;
}

/*
** Generate code to evaluate an expression and store the results
** into a register. Return the register number where the results
Expand Down Expand Up @@ -153176,6 +153203,7 @@ SQLITE_PRIVATE int sqlite3Select(
sqlite3VdbeAddOp2(v, OP_Integer, 0, iAbortFlag);
VdbeComment((v, "clear abort flag"));
sqlite3VdbeAddOp3(v, OP_Null, 0, iAMem, iAMem+pGroupBy->nExpr-1);
sqlite3ExprNullRegisterRange(pParse, iAMem, pGroupBy->nExpr);

/* Begin a loop that will extract all source rows in GROUP BY order.
** This might involve two separate loops with an OP_Sort in between, or
Expand Down Expand Up @@ -168471,6 +168499,7 @@ static int whereLoopAddBtree(
pNew->u.btree.nEq = 0;
pNew->u.btree.nBtm = 0;
pNew->u.btree.nTop = 0;
pNew->u.btree.nDistinctCol = 0;
pNew->nSkip = 0;
pNew->nLTerm = 0;
pNew->iSortIdx = 0;
Expand Down Expand Up @@ -169539,8 +169568,6 @@ static i8 wherePathSatisfiesOrderBy(
obSat = obDone;
}
break;
}else if( wctrlFlags & WHERE_DISTINCTBY ){
pLoop->u.btree.nDistinctCol = 0;
}
iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor;

Expand Down Expand Up @@ -257281,7 +257308,7 @@ static void fts5SourceIdFunc(
){
assert( nArg==0 );
UNUSED_PARAM2(nArg, apUnused);
sqlite3_result_text(pCtx, "fts5: 2025-07-17 13:25:10 3ce993b8657d6d9deda380a93cdd6404a8c8ba1b185b2bc423703e41ae5f2543", -1, SQLITE_TRANSIENT);
sqlite3_result_text(pCtx, "fts5: 2025-07-30 19:33:53 4d8adfb30e03f9cf27f800a2c1ba3c48fb4ca1b08b0f5ed59a4d5ecbf45e20a3", -1, SQLITE_TRANSIENT);
}

/*
Expand Down
6 changes: 3 additions & 3 deletions sqlite3-binding.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.50.3"
#define SQLITE_VERSION_NUMBER 3050003
#define SQLITE_SOURCE_ID "2025-07-17 13:25:10 3ce993b8657d6d9deda380a93cdd6404a8c8ba1b185b2bc423703e41ae5f2543"
#define SQLITE_VERSION "3.50.4"
#define SQLITE_VERSION_NUMBER 3050004
#define SQLITE_SOURCE_ID "2025-07-30 19:33:53 4d8adfb30e03f9cf27f800a2c1ba3c48fb4ca1b08b0f5ed59a4d5ecbf45e20a3"

/*
** CAPI3REF: Run-Time Library Version Numbers
Expand Down
153 changes: 13 additions & 140 deletions sqlite3_opt_userauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,62 +16,20 @@ package sqlite3
#else
#include <sqlite3.h>
#endif
#include <stdlib.h>

static int
_sqlite3_user_authenticate(sqlite3* db, const char* zUsername, const char* aPW, int nPW)
{
return sqlite3_user_authenticate(db, zUsername, aPW, nPW);
}

static int
_sqlite3_user_add(sqlite3* db, const char* zUsername, const char* aPW, int nPW, int isAdmin)
{
return sqlite3_user_add(db, zUsername, aPW, nPW, isAdmin);
}

static int
_sqlite3_user_change(sqlite3* db, const char* zUsername, const char* aPW, int nPW, int isAdmin)
{
return sqlite3_user_change(db, zUsername, aPW, nPW, isAdmin);
}

static int
_sqlite3_user_delete(sqlite3* db, const char* zUsername)
{
return sqlite3_user_delete(db, zUsername);
}

static int
_sqlite3_auth_enabled(sqlite3* db)
{
int exists = -1;

sqlite3_stmt *stmt;
sqlite3_prepare_v2(db, "select count(type) from sqlite_master WHERE type='table' and name='sqlite_user';", -1, &stmt, NULL);

while ( sqlite3_step(stmt) == SQLITE_ROW) {
exists = sqlite3_column_int(stmt, 0);
}

sqlite3_finalize(stmt);

return exists;
}
*/
import "C"
import (
"errors"
"unsafe"
)

const (
SQLITE_AUTH = C.SQLITE_AUTH
)

var (
ErrUnauthorized = errors.New("SQLITE_AUTH: Unauthorized")
ErrAdminRequired = errors.New("SQLITE_AUTH: Unauthorized; Admin Privileges Required")
ErrUnauthorized = errors.New("SQLITE_AUTH: Unauthorized")
ErrAdminRequired = errors.New("SQLITE_AUTH: Unauthorized; Admin Privileges Required")
errUserAuthNoLongerSupported = errors.New("sqlite3: the sqlite_userauth tag is no longer supported as the userauth extension is no longer supported by the SQLite authors, see https://github.com/mattn/go-sqlite3/issues/1341")
)

// Authenticate will perform an authentication of the provided username
Expand All @@ -88,15 +46,7 @@ var (
// If the SQLITE_USER table is not present in the database file, then
// this interface is a harmless no-op returning SQLITE_OK.
func (c *SQLiteConn) Authenticate(username, password string) error {
rv := c.authenticate(username, password)
switch rv {
case C.SQLITE_ERROR, C.SQLITE_AUTH:
return ErrUnauthorized
case C.SQLITE_OK:
return nil
default:
return c.lastError()
}
return errUserAuthNoLongerSupported
}

// authenticate provides the actual authentication to SQLite.
Expand All @@ -109,17 +59,7 @@ func (c *SQLiteConn) Authenticate(username, password string) error {
// C.SQLITE_ERROR (1)
// C.SQLITE_AUTH (23)
func (c *SQLiteConn) authenticate(username, password string) int {
// Allocate C Variables
cuser := C.CString(username)
cpass := C.CString(password)

// Free C Variables
defer func() {
C.free(unsafe.Pointer(cuser))
C.free(unsafe.Pointer(cpass))
}()

return int(C._sqlite3_user_authenticate(c.db, cuser, cpass, C.int(len(password))))
return 1
}

// AuthUserAdd can be used (by an admin user only)
Expand All @@ -131,20 +71,7 @@ func (c *SQLiteConn) authenticate(username, password string) int {
// for any ATTACH-ed databases. Any call to AuthUserAdd by a
// non-admin user results in an error.
func (c *SQLiteConn) AuthUserAdd(username, password string, admin bool) error {
isAdmin := 0
if admin {
isAdmin = 1
}

rv := c.authUserAdd(username, password, isAdmin)
switch rv {
case C.SQLITE_ERROR, C.SQLITE_AUTH:
return ErrAdminRequired
case C.SQLITE_OK:
return nil
default:
return c.lastError()
}
return errUserAuthNoLongerSupported
}

// authUserAdd enables the User Authentication if not enabled.
Expand All @@ -162,17 +89,7 @@ func (c *SQLiteConn) AuthUserAdd(username, password string, admin bool) error {
// C.SQLITE_ERROR (1)
// C.SQLITE_AUTH (23)
func (c *SQLiteConn) authUserAdd(username, password string, admin int) int {
// Allocate C Variables
cuser := C.CString(username)
cpass := C.CString(password)

// Free C Variables
defer func() {
C.free(unsafe.Pointer(cuser))
C.free(unsafe.Pointer(cpass))
}()

return int(C._sqlite3_user_add(c.db, cuser, cpass, C.int(len(password)), C.int(admin)))
return 1
}

// AuthUserChange can be used to change a users
Expand All @@ -181,20 +98,7 @@ func (c *SQLiteConn) authUserAdd(username, password string, admin int) int {
// credentials or admin privilege setting. No user may change their own
// admin privilege setting.
func (c *SQLiteConn) AuthUserChange(username, password string, admin bool) error {
isAdmin := 0
if admin {
isAdmin = 1
}

rv := c.authUserChange(username, password, isAdmin)
switch rv {
case C.SQLITE_ERROR, C.SQLITE_AUTH:
return ErrAdminRequired
case C.SQLITE_OK:
return nil
default:
return c.lastError()
}
return errUserAuthNoLongerSupported
}

// authUserChange allows to modify a user.
Expand All @@ -215,17 +119,7 @@ func (c *SQLiteConn) AuthUserChange(username, password string, admin bool) error
// C.SQLITE_ERROR (1)
// C.SQLITE_AUTH (23)
func (c *SQLiteConn) authUserChange(username, password string, admin int) int {
// Allocate C Variables
cuser := C.CString(username)
cpass := C.CString(password)

// Free C Variables
defer func() {
C.free(unsafe.Pointer(cuser))
C.free(unsafe.Pointer(cpass))
}()

return int(C._sqlite3_user_change(c.db, cuser, cpass, C.int(len(password)), C.int(admin)))
return 1
}

// AuthUserDelete can be used (by an admin user only)
Expand All @@ -234,15 +128,7 @@ func (c *SQLiteConn) authUserChange(username, password string, admin int) int {
// the database cannot be converted into a no-authentication-required
// database.
func (c *SQLiteConn) AuthUserDelete(username string) error {
rv := c.authUserDelete(username)
switch rv {
case C.SQLITE_ERROR, C.SQLITE_AUTH:
return ErrAdminRequired
case C.SQLITE_OK:
return nil
default:
return c.lastError()
}
return errUserAuthNoLongerSupported
}

// authUserDelete can be used to delete a user.
Expand All @@ -258,25 +144,12 @@ func (c *SQLiteConn) AuthUserDelete(username string) error {
// C.SQLITE_ERROR (1)
// C.SQLITE_AUTH (23)
func (c *SQLiteConn) authUserDelete(username string) int {
// Allocate C Variables
cuser := C.CString(username)

// Free C Variables
defer func() {
C.free(unsafe.Pointer(cuser))
}()

return int(C._sqlite3_user_delete(c.db, cuser))
return 1
}

// AuthEnabled checks if the database is protected by user authentication
func (c *SQLiteConn) AuthEnabled() (exists bool) {
rv := c.authEnabled()
if rv == 1 {
exists = true
}

return
return false
}

// authEnabled perform the actual check for user authentication.
Expand All @@ -289,7 +162,7 @@ func (c *SQLiteConn) AuthEnabled() (exists bool) {
// 0 - Disabled
// 1 - Enabled
func (c *SQLiteConn) authEnabled() int {
return int(C._sqlite3_auth_enabled(c.db))
return 0
}

// EOF
Loading