@@ -60,9 +60,102 @@ func compileTimeHash[T](original: static[T]): CachedHash[T] =
60
60
type Statement * = object
61
61
raw* : ptr RawStatement
62
62
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
+
63
155
type Database * = object
64
156
raw* : ptr RawDatabase
65
157
stmtcache: Table [CachedHash [string ], ref Statement ]
158
+ authorizer: ref WrapAuthorizer
66
159
67
160
type ResultCode * {.pure .} = enum
68
161
sr_ok = 0 ,
@@ -224,7 +317,7 @@ type SqliteDestroctor* = proc (p: pointer) {.cdecl.}
224
317
const StaticDestructor * = cast [SqliteDestroctor ](0 )
225
318
const TransientDestructor * = cast [SqliteDestroctor ](- 1 )
226
319
227
- type SqliteDateType * = enum
320
+ type SqliteDataType * = enum
228
321
dt_integer = 1 ,
229
322
dt_float = 2 ,
230
323
dt_text = 3 ,
@@ -374,6 +467,7 @@ proc sqlite3_prepare_v3*(db: ptr RawDatabase, sql: cstring, nbyte: int, flags: P
374
467
proc sqlite3_finalize * (st: ptr RawStatement ): ResultCode {.sqlite3linkage .}
375
468
proc sqlite3_reset * (st: ptr RawStatement ): ResultCode {.sqlite3linkage .}
376
469
proc sqlite3_step * (st: ptr RawStatement ): ResultCode {.sqlite3linkage .}
470
+ proc sqlite3_set_authorizer * (db: ptr RawDatabase , auth: SqliteRawAuthorizer , userdata: pointer ): ResultCode {.sqlite3linkage .}
377
471
proc sqlite3_bind_parameter_index * (st: ptr RawStatement , name: cstring ): int {.sqlite3linkage .}
378
472
proc sqlite3_bind_blob64 * (st: ptr RawStatement , idx: int , buffer: pointer , len: int , free: SqliteDestroctor ): ResultCode {.sqlite3linkage .}
379
473
proc 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
385
479
proc sqlite3_bind_zeroblob64 * (st: ptr RawStatement , idx: int , len: int ): ResultCode {.sqlite3linkage .}
386
480
proc sqlite3_changes * (st: ptr RawDatabase ): int {.sqlite3linkage .}
387
481
proc 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 .}
389
485
proc sqlite3_column_blob * (st: ptr RawStatement , idx: int ): pointer {.sqlite3linkage .}
390
486
proc sqlite3_column_bytes * (st: ptr RawStatement , idx: int ): int {.sqlite3linkage .}
391
487
proc sqlite3_column_double * (st: ptr RawStatement , idx: int ): float64 {.sqlite3linkage .}
@@ -442,6 +538,107 @@ proc initDatabase*(
442
538
sqliteCheck sqlite3_open_v2 (filename, addr result .raw, flags, vfs)
443
539
result .stmtcache = initTable [CachedHash [string ], ref Statement ]()
444
540
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
+
445
642
proc changes * (st: var Database ): int =
446
643
sqlite3_changes st.raw
447
644
@@ -497,6 +694,9 @@ proc `[]=`*[T](st: ref Statement, idx: int, val: Option[T]) =
497
694
else :
498
695
st[idx] = val.get
499
696
697
+ proc `[]=` * [T](st: ref Statement , name: string , value: T) =
698
+ st[st.getParameterIndex (name)] = value
699
+
500
700
proc reset * (st: ref Statement ) =
501
701
st.raw.sqliteCheck sqlite3_reset (st.raw)
502
702
@@ -515,7 +715,7 @@ proc withColumnBlob*(st: ref Statement, idx: int, recv: proc(vm: openarray[byte]
515
715
let l = sqlite3_column_bytes (st.raw, idx)
516
716
recv (cast [ptr UncheckedArray [byte ]](p).toOpenArray (0 , l))
517
717
518
- proc getColumnType * (st: ref Statement , idx: int ): SqliteDateType =
718
+ proc getColumnType * (st: ref Statement , idx: int ): SqliteDataType =
519
719
sqlite3_column_type (st.raw, idx)
520
720
521
721
proc 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[
542
742
else :
543
743
some (st.getColumn (idx, T))
544
744
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
+
545
770
proc unpack * [T: tuple ](st: ref Statement , _: typedesc [T]): T =
546
771
var idx = 0
547
772
for value in result .fields:
@@ -568,3 +793,10 @@ proc execM*(db: var Database, sqls: varargs[string]) {.discardable.} =
568
793
except CatchableError :
569
794
discard db.exec " ROLLBACK"
570
795
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