package sqlite3

import (
	
	
	
	

	

	
	
)

// Config makes configuration changes to a database connection.
// Only boolean configuration options are supported.
// Called with no arg reads the current configuration value,
// called with one arg sets and returns the new value.
//
// https://sqlite.org/c3ref/db_config.html
func ( *Conn) ( DBConfig,  ...bool) (bool, error) {
	if  < DBCONFIG_ENABLE_FKEY ||  > DBCONFIG_REVERSE_SCANORDER {
		return false, MISUSE
	}

	// We need to call sqlite3_db_config, a variadic function.
	// We only support the `int int*` variants.
	// The int is a three-valued bool: -1 queries, 0/1 sets false/true.
	// The int* points to where new state will be written to.
	// The vararg is a pointer to an array containing these arguments:
	// an int and an int* pointing to that int.

	defer .arena.mark()()
	 := .arena.new(intlen + ptrlen)

	var  int32
	switch {
	case len() == 0:
		 = -1
	case [0]:
		 = 1
	}

	util.Write32(.mod, +0*ptrlen, )
	util.Write32(.mod, +1*ptrlen, )

	 := res_t(.call("sqlite3_db_config", stk_t(.handle),
		stk_t(), stk_t()))
	return util.ReadBool(.mod, ), .error()
}

var defaultLogger atomic.Pointer[func(code ExtendedErrorCode, msg string)]

// ConfigLog sets up the default error logging callback for new connections.
//
// https://sqlite.org/errlog.html
func ( func( ExtendedErrorCode,  string)) {
	defaultLogger.Store(&)
}

// ConfigLog sets up the error logging callback for the connection.
//
// https://sqlite.org/errlog.html
func ( *Conn) ( func( ExtendedErrorCode,  string)) error {
	var  int32
	if  != nil {
		 = 1
	}
	 := res_t(.call("sqlite3_config_log_go", stk_t()))
	if  := .error();  != nil {
		return 
	}
	.log = 
	return nil
}

func logCallback( context.Context,  api.Module,  ptr_t,  res_t,  ptr_t) {
	if ,  := .Value(connKey{}).(*Conn);  && .log != nil {
		 := util.ReadString(, , _MAX_LENGTH)
		.log(xErrorCode(), )
	}
}

// Log writes a message into the error log established by [Conn.ConfigLog].
//
// https://sqlite.org/c3ref/log.html
func ( *Conn) ( ExtendedErrorCode,  string,  ...any) {
	if .log != nil {
		.log(, fmt.Sprintf(, ...))
	}
}

// FileControl allows low-level control of database files.
// Only a subset of opcodes are supported.
//
// https://sqlite.org/c3ref/file_control.html
func ( *Conn) ( string,  FcntlOpcode,  ...any) (any, error) {
	defer .arena.mark()()
	 := .arena.new(max(ptrlen, intlen))

	var  ptr_t
	if  != "" {
		 = .arena.string()
	}

	var  res_t
	var  any
	switch  {
	default:
		return nil, MISUSE

	case FCNTL_RESET_CACHE, FCNTL_NULL_IO:
		 = res_t(.call("sqlite3_file_control",
			stk_t(.handle), stk_t(),
			stk_t(), 0))

	case FCNTL_PERSIST_WAL, FCNTL_POWERSAFE_OVERWRITE:
		var  int32
		switch {
		case len() == 0:
			 = -1
		case [0]:
			 = 1
		}
		util.Write32(.mod, , )
		 = res_t(.call("sqlite3_file_control",
			stk_t(.handle), stk_t(),
			stk_t(), stk_t()))
		 = util.ReadBool(.mod, )

	case FCNTL_CHUNK_SIZE:
		util.Write32(.mod, , int32([0].(int)))
		 = res_t(.call("sqlite3_file_control",
			stk_t(.handle), stk_t(),
			stk_t(), stk_t()))

	case FCNTL_RESERVE_BYTES:
		 := -1
		if len() > 0 {
			 = [0].(int)
		}
		util.Write32(.mod, , int32())
		 = res_t(.call("sqlite3_file_control",
			stk_t(.handle), stk_t(),
			stk_t(), stk_t()))
		 = int(util.Read32[int32](.mod, ))

	case FCNTL_DATA_VERSION:
		 = res_t(.call("sqlite3_file_control",
			stk_t(.handle), stk_t(),
			stk_t(), stk_t()))
		 = util.Read32[uint32](.mod, )

	case FCNTL_LOCKSTATE:
		 = res_t(.call("sqlite3_file_control",
			stk_t(.handle), stk_t(),
			stk_t(), stk_t()))
		 = util.Read32[vfs.LockLevel](.mod, )

	case FCNTL_VFS_POINTER:
		 = res_t(.call("sqlite3_file_control",
			stk_t(.handle), stk_t(),
			stk_t(), stk_t()))
		if  == _OK {
			const  = 16
			 = util.Read32[ptr_t](.mod, )
			 = util.Read32[ptr_t](.mod, +)
			 := util.ReadString(.mod, , _MAX_NAME)
			 = vfs.Find()
		}

	case FCNTL_FILE_POINTER, FCNTL_JOURNAL_POINTER:
		 = res_t(.call("sqlite3_file_control",
			stk_t(.handle), stk_t(),
			stk_t(), stk_t()))
		if  == _OK {
			const  = 4
			 = util.Read32[ptr_t](.mod, )
			 = util.Read32[ptr_t](.mod, +)
			 = util.GetHandle(.ctx, )
		}
	}

	if  := .error();  != nil {
		return nil, 
	}
	return , nil
}

// Limit allows the size of various constructs to be
// limited on a connection by connection basis.
//
// https://sqlite.org/c3ref/limit.html
func ( *Conn) ( LimitCategory,  int) int {
	 := int32(.call("sqlite3_limit", stk_t(.handle), stk_t(), stk_t()))
	return int()
}

// SetAuthorizer registers an authorizer callback with the database connection.
//
// https://sqlite.org/c3ref/set_authorizer.html
func ( *Conn) ( func( AuthorizerActionCode, , , ,  string) AuthorizerReturnCode) error {
	var  int32
	if  != nil {
		 = 1
	}
	 := res_t(.call("sqlite3_set_authorizer_go", stk_t(.handle), stk_t()))
	if  := .error();  != nil {
		return 
	}
	.authorizer = 
	return nil

}

func authorizerCallback( context.Context,  api.Module,  ptr_t,  AuthorizerActionCode, , , ,  ptr_t) ( AuthorizerReturnCode) {
	if ,  := .Value(connKey{}).(*Conn);  && .handle ==  && .authorizer != nil {
		var , , ,  string
		if  != 0 {
			 = util.ReadString(, , _MAX_NAME)
		}
		if  != 0 {
			 = util.ReadString(, , _MAX_NAME)
		}
		if  != 0 {
			 = util.ReadString(, , _MAX_NAME)
		}
		if  != 0 {
			 = util.ReadString(, , _MAX_NAME)
		}
		 = .authorizer(, , , , )
	}
	return 
}

// Trace registers a trace callback function against the database connection.
//
// https://sqlite.org/c3ref/trace_v2.html
func ( *Conn) ( TraceEvent,  func( TraceEvent,  any,  any) error) error {
	 := res_t(.call("sqlite3_trace_go", stk_t(.handle), stk_t()))
	if  := .error();  != nil {
		return 
	}
	.trace = 
	return nil
}

func traceCallback( context.Context,  api.Module,  TraceEvent, , ,  ptr_t) ( res_t) {
	if ,  := .Value(connKey{}).(*Conn);  && .handle ==  && .trace != nil {
		var ,  any
		if  == TRACE_CLOSE {
			 = 
		} else {
			for ,  := range .stmts {
				if  == .handle {
					 = 
					switch  {
					case TRACE_STMT:
						 = .SQL()
					case TRACE_PROFILE:
						 = util.Read64[int64](, )
					}
					break
				}
			}
		}
		if  != nil {
			_,  = errorCode(.trace(, , ), ERROR)
		}
	}
	return 
}

// WALCheckpoint checkpoints a WAL database.
//
// https://sqlite.org/c3ref/wal_checkpoint_v2.html
func ( *Conn) ( string,  CheckpointMode) (,  int,  error) {
	if .interrupt.Err() != nil {
		return 0, 0, INTERRUPT
	}

	defer .arena.mark()()
	 := .arena.new(ptrlen)
	 := .arena.new(ptrlen)
	 := .arena.string()
	 := res_t(.call("sqlite3_wal_checkpoint_v2",
		stk_t(.handle), stk_t(), stk_t(),
		stk_t(), stk_t()))
	 = int(util.Read32[int32](.mod, ))
	 = int(util.Read32[int32](.mod, ))
	return , , .error()
}

// WALAutoCheckpoint configures WAL auto-checkpoints.
//
// https://sqlite.org/c3ref/wal_autocheckpoint.html
func ( *Conn) ( int) error {
	 := res_t(.call("sqlite3_wal_autocheckpoint", stk_t(.handle), stk_t()))
	return .error()
}

// WALHook registers a callback function to be invoked
// each time data is committed to a database in WAL mode.
//
// https://sqlite.org/c3ref/wal_hook.html
func ( *Conn) ( func( *Conn,  string,  int) error) {
	var  int32
	if  != nil {
		 = 1
	}
	.call("sqlite3_wal_hook_go", stk_t(.handle), stk_t())
	.wal = 
}

func walCallback( context.Context,  api.Module, , ,  ptr_t,  int32) ( res_t) {
	if ,  := .Value(connKey{}).(*Conn);  && .handle ==  && .wal != nil {
		 := util.ReadString(, , _MAX_NAME)
		 := .wal(, , int())
		_,  = errorCode(, ERROR)
	}
	return 
}

// AutoVacuumPages registers a autovacuum compaction amount callback.
//
// https://sqlite.org/c3ref/autovacuum_pages.html
func ( *Conn) ( func( string, , ,  uint) uint) error {
	var  ptr_t
	if  != nil {
		 = util.AddHandle(.ctx, )
	}
	 := res_t(.call("sqlite3_autovacuum_pages_go", stk_t(.handle), stk_t()))
	return .error()
}

func autoVacuumCallback( context.Context,  api.Module, ,  ptr_t, , ,  uint32) uint32 {
	 := util.GetHandle(, ).(func( string, , ,  uint) uint)
	 := util.ReadString(, , _MAX_NAME)
	return uint32((, uint(), uint(), uint()))
}

// SoftHeapLimit imposes a soft limit on heap size.
//
// https://sqlite.org/c3ref/hard_heap_limit64.html
func ( *Conn) ( int64) int64 {
	return int64(.call("sqlite3_soft_heap_limit64", stk_t()))
}

// HardHeapLimit imposes a hard limit on heap size.
//
// https://sqlite.org/c3ref/hard_heap_limit64.html
func ( *Conn) ( int64) int64 {
	return int64(.call("sqlite3_hard_heap_limit64", stk_t()))
}

// EnableChecksums enables checksums on a database.
//
// https://sqlite.org/cksumvfs.html
func ( *Conn) ( string) error {
	,  := .FileControl(, FCNTL_RESERVE_BYTES)
	if  != nil {
		return 
	}
	if  == 8 {
		// Correct value, enabled.
		return nil
	}
	if  == 0 {
		// Default value, enable.
		_,  = .FileControl(, FCNTL_RESERVE_BYTES, 8)
		if  != nil {
			return 
		}
		,  = .FileControl(, FCNTL_RESERVE_BYTES)
		if  != nil {
			return 
		}
	}
	if  != 8 {
		// Invalid value.
		return util.ErrorString("sqlite3: reserve bytes must be 8, is: " + strconv.Itoa(.(int)))
	}

	// VACUUM the database.
	if  != "" {
		 = .Exec(`VACUUM ` + QuoteIdentifier())
	} else {
		 = .Exec(`VACUUM`)
	}
	if  != nil {
		return 
	}

	// Checkpoint the WAL.
	_, _,  = .WALCheckpoint(, CHECKPOINT_FULL)
	return 
}