@@ -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