@@ -60,9 +60,102 @@ func compileTimeHash[T](original: static[T]): CachedHash[T] =
6060type Statement * = object
6161 raw* : ptr RawStatement
6262
63+ type
64+ AuthorizerResult * {.pure , size : sizeof (cint ).} = enum
65+ ok = 0 ,
66+ deny = 1 ,
67+ ignore = 2
68+ AuthorizerActionCode * {.pure , size : sizeof (cint ).} = enum
69+ # action code # arg3 arg4
70+ copy = 0 , # No longer used
71+ create_index = 1 , # Index Name Table Name
72+ create_table = 2 , # Table Name NULL
73+ create_temp_index = 3 , # Index Name Table Name
74+ create_temp_table = 4 , # Table Name NULL
75+ create_temp_trigger = 5 , # Trigger Name Table Name
76+ create_temp_view = 6 , # View Name NULL
77+ create_trigger = 7 , # Trigger Name Table Name
78+ create_view = 8 , # View Name NULL
79+ delete = 9 , # Table Name NULL
80+ drop_index = 10 , # Index Name Table Name
81+ drop_table = 11 , # Table Name NULL
82+ drop_temp_index = 12 , # Index Name Table Name
83+ drop_temp_table = 13 , # Table Name NULL
84+ drop_temp_trigger = 14 , # Trigger Name Table Name
85+ drop_temp_view = 15 , # View Name NULL
86+ drop_trigger = 16 , # Trigger Name Table Name
87+ drop_view = 17 , # View Name NULL
88+ insert = 18 , # Table Name NULL
89+ pragma = 19 , # Pragma Name 1st arg or NULL
90+ read = 20 , # Table Name Column Name
91+ select = 21 , # NULL NULL
92+ transaction = 22 , # Operation NULL
93+ update = 23 , # Table Name Column Name
94+ attach = 24 , # Filename NULL
95+ detach = 25 , # Database Name NULL
96+ alter_table = 26 , # Database Name Table Name
97+ reindex = 27 , # Index Name NULL
98+ analyze = 28 , # Table Name NULL
99+ create_vtable = 29 , # Table Name Module Name
100+ drop_vtable = 30 , # Table Name Module Name
101+ function = 31 , # NULL Function Name
102+ savepoint = 32 , # Operation Savepoint Name
103+ recursive = 33 , # NULL NULL
104+ AuthorizerRequest * = ref object
105+ case action_code* : AuthorizerActionCode
106+ of create_index, create_temp_index, drop_index, drop_temp_index:
107+ index_name* : string
108+ index_table_name* : string
109+ of create_table, create_temp_table, delete, drop_table, drop_temp_table, insert, analyze:
110+ table_name* : string
111+ of create_temp_trigger, create_trigger, drop_temp_trigger, drop_trigger:
112+ trigger_name* : string
113+ trigger_table_name* : string
114+ of create_temp_view, create_view, drop_temp_view, drop_view:
115+ view_name* : string
116+ of pragma:
117+ pragma_name* : string
118+ pragma_arg* : Option [string ]
119+ of read, update:
120+ target_table_name* : string
121+ column_name* : string
122+ of select, recursive, copy:
123+ discard
124+ of transaction:
125+ transaction_operation* : string
126+ of attach:
127+ filename* : string
128+ of detach:
129+ database_name* : string
130+ of alter_table:
131+ alter_database_name* : string
132+ alter_table_name* : string
133+ of reindex:
134+ reindex_index_name* : string
135+ of create_vtable, drop_vtable:
136+ vtable_name* : string
137+ module_name* : string
138+ of function:
139+ # no arg3
140+ function_name* : string
141+ of savepoint:
142+ savepoint_operation* : string
143+ savepoint_name* : string
144+ SqliteRawAuthorizer * = proc (
145+ userdata: pointer ,
146+ action_code: AuthorizerActionCode ,
147+ arg3, arg4, arg5, arg6: cstring ): AuthorizerResult {.cdecl .}
148+ RawAuthorizer * = proc (
149+ action_code: AuthorizerActionCode ,
150+ arg3, arg4, arg5, arg6: Option [string ]): AuthorizerResult
151+ Authorizer * = proc (request: AuthorizerRequest ): AuthorizerResult
152+ WrapAuthorizer = object
153+ authorizer: RawAuthorizer
154+
63155type Database * = object
64156 raw* : ptr RawDatabase
65157 stmtcache: Table [CachedHash [string ], ref Statement ]
158+ authorizer: ref WrapAuthorizer
66159
67160type ResultCode * {.pure .} = enum
68161 sr_ok = 0 ,
@@ -224,7 +317,7 @@ type SqliteDestroctor* = proc (p: pointer) {.cdecl.}
224317const StaticDestructor * = cast [SqliteDestroctor ](0 )
225318const TransientDestructor * = cast [SqliteDestroctor ](- 1 )
226319
227- type SqliteDateType * = enum
320+ type SqliteDataType * = enum
228321 dt_integer = 1 ,
229322 dt_float = 2 ,
230323 dt_text = 3 ,
@@ -374,6 +467,7 @@ proc sqlite3_prepare_v3*(db: ptr RawDatabase, sql: cstring, nbyte: int, flags: P
374467proc sqlite3_finalize * (st: ptr RawStatement ): ResultCode {.sqlite3linkage .}
375468proc sqlite3_reset * (st: ptr RawStatement ): ResultCode {.sqlite3linkage .}
376469proc sqlite3_step * (st: ptr RawStatement ): ResultCode {.sqlite3linkage .}
470+ proc sqlite3_set_authorizer * (db: ptr RawDatabase , auth: SqliteRawAuthorizer , userdata: pointer ): ResultCode {.sqlite3linkage .}
377471proc sqlite3_bind_parameter_index * (st: ptr RawStatement , name: cstring ): int {.sqlite3linkage .}
378472proc sqlite3_bind_blob64 * (st: ptr RawStatement , idx: int , buffer: pointer , len: int , free: SqliteDestroctor ): ResultCode {.sqlite3linkage .}
379473proc sqlite3_bind_double * (st: ptr RawStatement , idx: int , value: float64 ): ResultCode {.sqlite3linkage .}
@@ -385,7 +479,9 @@ proc sqlite3_bind_pointer*(st: ptr RawStatement, idx: int, val: pointer, name: c
385479proc sqlite3_bind_zeroblob64 * (st: ptr RawStatement , idx: int , len: int ): ResultCode {.sqlite3linkage .}
386480proc sqlite3_changes * (st: ptr RawDatabase ): int {.sqlite3linkage .}
387481proc sqlite3_last_insert_rowid * (st: ptr RawDatabase ): int {.sqlite3linkage .}
388- proc sqlite3_column_type * (st: ptr RawStatement , idx: int ): SqliteDateType {.sqlite3linkage .}
482+ proc sqlite3_column_count * (st: ptr RawStatement ): int {.sqlite3linkage .}
483+ proc sqlite3_column_type * (st: ptr RawStatement , idx: int ): SqliteDataType {.sqlite3linkage .}
484+ proc sqlite3_column_name * (st: ptr RawStatement , idx: int ): cstring {.sqlite3linkage .}
389485proc sqlite3_column_blob * (st: ptr RawStatement , idx: int ): pointer {.sqlite3linkage .}
390486proc sqlite3_column_bytes * (st: ptr RawStatement , idx: int ): int {.sqlite3linkage .}
391487proc sqlite3_column_double * (st: ptr RawStatement , idx: int ): float64 {.sqlite3linkage .}
@@ -442,6 +538,107 @@ proc initDatabase*(
442538 sqliteCheck sqlite3_open_v2 (filename, addr result .raw, flags, vfs)
443539 result .stmtcache = initTable [CachedHash [string ], ref Statement ]()
444540
541+ proc toS (s: cstring ): Option [string ] =
542+ if s == nil :
543+ result = none (string )
544+ else :
545+ result = some ($ s)
546+
547+ proc setAuthorizer * (db: var Database , callback: RawAuthorizer = nil ) =
548+ let userdata: ref WrapAuthorizer = new (WrapAuthorizer )
549+ userdata.authorizer = callback
550+
551+ proc raw_callback (
552+ userdata: pointer ,
553+ action_code: AuthorizerActionCode ,
554+ arg3, arg4, arg5, arg6: cstring ): AuthorizerResult {.cdecl .} =
555+ let callback = cast [ref WrapAuthorizer ](userdata).authorizer
556+ callback (action_code, arg3.toS (), arg4.toS (), arg5.toS (), arg6.toS ())
557+
558+ var res: ResultCode
559+ if callback == nil :
560+ res = db.raw.sqlite3_set_authorizer (nil , nil )
561+ else :
562+ res = db.raw.sqlite3_set_authorizer (raw_callback, cast [pointer ](userdata))
563+ db.authorizer = userdata
564+ if res != ResultCode .sr_ok:
565+ raise newSQLiteError res
566+
567+ proc setAuthorizer * (db: var Database , callback: Authorizer = nil ) =
568+ var raw_callback: RawAuthorizer = nil
569+ if callback != nil :
570+ raw_callback = proc (code: AuthorizerActionCode , arg3, arg4, arg5, arg6: Option [string ]): AuthorizerResult =
571+ var req: AuthorizerRequest
572+ case code
573+ of create_index, create_temp_index, drop_index, drop_temp_index:
574+ req = AuthorizerRequest (
575+ action_code: code,
576+ index_name: arg3.get,
577+ index_table_name: arg4.get)
578+ of create_table, create_temp_table, delete, drop_table, drop_temp_table, insert, analyze:
579+ req = AuthorizerRequest (
580+ action_code: code,
581+ table_name: arg3.get)
582+ of create_temp_trigger, create_trigger, drop_temp_trigger, drop_trigger:
583+ req = AuthorizerRequest (
584+ action_code: code,
585+ trigger_name: arg3.get,
586+ trigger_table_name: arg4.get)
587+ of create_temp_view, create_view, drop_temp_view, drop_view:
588+ req = AuthorizerRequest (
589+ action_code: code,
590+ view_name: arg3.get)
591+ of pragma:
592+ req = AuthorizerRequest (
593+ action_code: code,
594+ pragma_name: arg3.get,
595+ pragma_arg: arg4)
596+ of read, update:
597+ req = AuthorizerRequest (
598+ action_code: code,
599+ target_table_name: arg3.get,
600+ column_name: arg4.get)
601+ of select, recursive, copy:
602+ req = AuthorizerRequest (action_code: code)
603+ of transaction:
604+ req = AuthorizerRequest (
605+ action_code: code,
606+ transaction_operation: arg3.get)
607+ of attach:
608+ req = AuthorizerRequest (
609+ action_code: code,
610+ filename: arg3.get)
611+ of detach:
612+ req = AuthorizerRequest (
613+ action_code: code,
614+ database_name: arg3.get)
615+ of alter_table:
616+ req = AuthorizerRequest (
617+ action_code: code,
618+ alter_database_name: arg3.get,
619+ alter_table_name: arg4.get)
620+ of reindex:
621+ req = AuthorizerRequest (
622+ action_code: code,
623+ reindex_index_name: arg3.get)
624+ of create_vtable, drop_vtable:
625+ req = AuthorizerRequest (
626+ action_code: code,
627+ vtable_name: arg3.get,
628+ module_name: arg4.get)
629+ of function:
630+ req = AuthorizerRequest (
631+ action_code: code,
632+ # no arg3
633+ function_name: arg4.get)
634+ of savepoint:
635+ req = AuthorizerRequest (
636+ action_code: code,
637+ savepoint_operation: arg3.get,
638+ savepoint_name: arg4.get)
639+ return callback (req)
640+ db.setAuthorizer (raw_callback)
641+
445642proc changes * (st: var Database ): int =
446643 sqlite3_changes st.raw
447644
@@ -497,6 +694,9 @@ proc `[]=`*[T](st: ref Statement, idx: int, val: Option[T]) =
497694 else :
498695 st[idx] = val.get
499696
697+ proc `[]=` * [T](st: ref Statement , name: string , value: T) =
698+ st[st.getParameterIndex (name)] = value
699+
500700proc reset * (st: ref Statement ) =
501701 st.raw.sqliteCheck sqlite3_reset (st.raw)
502702
@@ -515,7 +715,7 @@ proc withColumnBlob*(st: ref Statement, idx: int, recv: proc(vm: openarray[byte]
515715 let l = sqlite3_column_bytes (st.raw, idx)
516716 recv (cast [ptr UncheckedArray [byte ]](p).toOpenArray (0 , l))
517717
518- proc getColumnType * (st: ref Statement , idx: int ): SqliteDateType =
718+ proc getColumnType * (st: ref Statement , idx: int ): SqliteDataType =
519719 sqlite3_column_type (st.raw, idx)
520720
521721proc getColumn * (st: ref Statement , idx: int , T: typedesc [seq [byte ]]): seq [byte ] =
@@ -542,6 +742,31 @@ proc getColumn*[T](st: ref Statement, idx: int, _: typedesc[Option[T]]): Option[
542742 else :
543743 some (st.getColumn (idx, T))
544744
745+ type ColumnDef * = object
746+ st* : ref Statement
747+ idx* : int
748+ data_type* : SqliteDataType
749+ name* : string
750+
751+ proc columns * (st: ref Statement ): seq [ref ColumnDef ] =
752+ result = @ []
753+ var idx = 0
754+ let count = sqlite3_column_count (st.raw)
755+ while idx < count:
756+ let col = new (ColumnDef )
757+ col.st = st
758+ col.idx = idx
759+ col.data_type = sqlite3_column_type (st.raw, idx)
760+ col.name = $ sqlite3_column_name (st.raw, idx)
761+ result .add (col)
762+ idx += 1
763+
764+ proc `[]` * (st: ref Statement , idx: int ): ref ColumnDef =
765+ result = st.columns[idx]
766+
767+ proc `[]` * [T](col: ref ColumnDef , t: typedesc [T]): T =
768+ result = col.st.getColumn (col.idx, t)
769+
545770proc unpack * [T: tuple ](st: ref Statement , _: typedesc [T]): T =
546771 var idx = 0
547772 for value in result .fields:
@@ -568,3 +793,10 @@ proc execM*(db: var Database, sqls: varargs[string]) {.discardable.} =
568793 except CatchableError :
569794 discard db.exec " ROLLBACK"
570795 raise getCurrentException ()
796+
797+ iterator rows * (st: ref Statement ): seq [ref ColumnDef ] =
798+ try :
799+ while st.step ():
800+ yield st.columns ()
801+ finally :
802+ st.reset ()
0 commit comments