-
Notifications
You must be signed in to change notification settings - Fork 0
/
sl3.icn
697 lines (663 loc) · 25 KB
/
sl3.icn
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
$ifndef SL3
$define SL3
############################################################################
#
# File: sl3.icn
#
# Subject: sl3.icn - an Icon interface to sqlite3 command line interface
#
# Author: Arthur Eschenlauer (https://orcid.org/0000-0002-2882-0508)
#
# Date: 28 December 2022
#
# URL: https://chiselapp.com/user/eschen42/repository/aceincl/file?name=sl3.icn
#
############################################################################
#
# This file is in the public domain. Art Eschenlauer has waived all
# copyright and related or neighboring rights to:
# sl3.icn - an Icon interface to sqlite3 command line interface
# For details, see:
# https://creativecommons.org/publicdomain/zero/1.0/
#
# If you require a specific license and public domain status is not
# sufficient for your needs, please substitute the MIT license (see below),
# bearing in mind that the copyright "claim" is solely to meet your require-
# ments and does not imply any restriction on use or copying by the author:
#
# Copyright (c) 2022, Arthur Eschenlauer
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject
# to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
############################################################################
#
# sl3.icn defines an interface to the sqlite3 command line interface,
# which is described in detail at https://sqlite.org/cli.html
#
# No generalized process interface exists in the basic Icon implementation
# and library that would allow access to both the standard input and the
# standard output of a child process, this interface uses the `baton`
# inteface via `baton.icn`, `baton_main.icn`, and `batonsys.icn` to hand
# data back and forth between Icon and sqlite3 without resorting to such
# platform-specific devices as FIFOs or named-pipes.
#
# By default, baton files are created in the directory whose path is
# returned by `tmpdir()` in fileDirIo.icn. To override
# this behavior, assign a path string to the global variable
# `g_sl3_tmpdir`
# which is defined in this file.
#
# # For convenience, if the symbol "sl3" is not defined by the preprocessor
# before "sl3.icn" is included, then it is defined as "sl3msg", which
# is the actual identifier for the implementation here; this header
# assumes this definition.
#
# sl3new(path, options, errC) : VNom (a SQLite3 connection)
# - This is a synonym for sl3(&null, "open", path, options, errC)
# - See below for details of the "open" message.
#
# sl3(conn:SQLite3, message, arg1, arg2, arg3) : x
# - takes as its first argument, a "database connection" that is a
# "SQLite3" VNom (or &null when the message is "open").
# - takes as its second argument an operation message string, which is:
# - either one of "open" | "prepare" | "fetch" | "close"
# - or "the default key", a prepared statement or SQL string.
# - The value produced depends on the signature invoked.
#
# The signatures of sl3 messages are as follows:
#
# sl3(&null, "open", path, options, errC ) : VNom (a SQLite3 conn)
# sl3(conn, "prepare", stmt ) : VNom (a prep_stmt)
# sl3(conn, stmt:s, parmL:L, errC ) : n|fail
# sl3(conn, prep_stmt:V, &null|x, errC ) : n|fail
# sl3(conn, "fetch" ) : VNom (a result row)
# sl3(conn, "close", errC ) : &null
#
# The behaviors of sl3 messages are as follows:
#
# sl3(connection, "open", path, options, errC) : SQLite3
# - Opens a connection using a database path.
# - Produces a SQLite3 connection structure.
# - connection : &null
# - connection should be &null but is ignored.
# - Construct and produce new SQLite3 instance.
# - path : s (or &null)
# - Path to (possibly not-yet-existing) sqlite3 database.
# - When &null, path defaults to ":memory:", an in-memory temp database.
# - options : s (or &null)
# - Additional options to be passed on the command line to sqlite3.
# - When &null, only standard options will be passed.
# - errC : C
# - Co-expression to which error message strings will be transmitted.
# - When &null, error message strings will not be transmitted.
#
# sl3(connection, "prepare", stmt) : VNom (as specified here)
# - Purge previous results (by fetching all, if any).
# - Parse SQL statement containing placeholders.
# - Fails when connection is not open;
# - otherwise, produces a VNom having:
# - ordered parameter names for the prepared statement (param "?")
# - parameter "?" (the last parameter), a string containing a
# parameterized SQL statement compatible with sqlite3
# - connection : SQLite3
# - an open database connection
# - stmt : s
# - SQL text including placeholders; this is assigned to parameter "?"
# - Please provide named placeholders appropriately, as described at:
# https://sqlite.org/cli.html#sql_parameters
#
# sl3(connection, stmt:s, parmL:L, errC) : n|fail
# sl3(connection, prep_stmt:V, &null|x, errC) : n|fail
# - Purge previous results (by fetching all, if any).
# - Execute a SQL statement.
# - Produces &null if successful; otherwise fails.
# - On failure, a string is transmitted to errC (if not &null)
# - connection : SQLite3
# - open database connection
# - stmt:s | prep_stmt:V
# - s (for SQL text; params, if any, taken from parmL)
# - V (result from "prepare" message; parmL is ignored)
# - parmL : L
# - list of parameters for a prepared statement,
# ignored unless prep_stmt is a string
# - errC : C
# - Co-expression to which error message strings will be transmitted.
# - When &null, error message strings will not be transmitted.
#
# sl3(connection, "fetch") : VNom (representing a result row)
# - Fetch a result from the result list.
# - Produce one result row (as a VNom) from the result list.
# - This is a VNom so that fields ordered independently of their names.
# - connection : SQLite3
# - open database connection
#
# sl3(connection, "close", errC) : &null
# - Purge previous results (by fetching all, if any).
# - Close and dispose connection.
# - Produces &null only when successful;
# - fails otherwise.
# - connection : SQLite3
# - open database connection
# - errC : C
# - Co-expression to which error message strings will be transmitted.
# - When &null, error message strings will not be transmitted.
#
# SQLite3 is an extension of VNom that implements the following extensions
# to VNom state:
# - batonsys : result from baton_system(...)
# - status : "open" | "fetching" | &null (closed)
# - rows : C producing rows; failing when rows are exhausted.
#
# The result mode for sqlite3 is json for deterministic parsing by this
# routine; this parsing is internal but it implies that
# sl3(connection, stmt_or_prepstmt, parm_L, errC) : s # result status
# must not change the result mode to something else (e.g., to use the
# .output to format results in an output file) without changing it back.
#
############################################################################
#
# Requires:
# - preprocessor
# - pipes
# - system
# - $include "batonsys.icn"
# - this includes baton_main.icn and baton.icn
# - $include "fileDirIo.icn"
# - $include "jsonparse.icn"
# - $include "lindel.icn"
# - $include "vnom.icn"
# - calling baton_flatware(args) from main(args).
#
############################################################################
#
# Preprocessor symbols defined in this file:
# - SL3_TRACE, if defined, should look like `write` or `&fail`
# - SL3_EOT, if defined, should be a string defining a line not expected
# in output of commands or queries; default is "."
#
# Global identifiers defined in this file:
# - g_sl3_tmpdir if set, should be the path to a directory in which temp-
# orary baton files may be created; default is the string produced by
# `tmppath()` from fileDirIo.icn
#
############################################################################
#
# Links: strings
#
############################################################################
link strings
# ref: https://www2.cs.arizona.edu/icon/library/src/procs/strings.icn
# replacem(s, ...)
# Performs multiple replacements in the style of
# of replace(), where multiple argument pairs
# may be given, as in
# replacem(s, "a", "bc", "d", "cd")
# which replaces all "a"s with "bc"s
# and replaces all "d"s with "cd"s.
# Replacements are performed one after another, not in parallel.
# replace(s1, s2, s3)
# Replaces all occurrences of s2 in s1 by s3; fails when s2 is null.
$ifndef _fileDirIo_
# need fileDirIo.icn for which and tmppath
$include "fileDirIo.icn"
$endif
$ifndef LINDEL
$include "lindel.icn"
$endif
$ifndef VNOM
$include "vnom.icn"
$endif
$ifndef JSONPARSE
$include "jsonparse.icn"
$endif
$ifndef BATONSYS
$include "batonsys.icn"
$endif
$ifndef sl3
$define sl3msg sl3
$endif
$ifndef _PIPES
$error "sl3.icn" requires pipes
fail
$endif # _PIPES
$ifndef SL3_TRACE
$define SL3_TRACE &fail
#$define SL3_TRACE write
$endif # SL3_TRACE
$ifndef SL3_EOT
#$define SL3_EOT "[]"
$define SL3_EOT "."
$endif # SL3_EOT
global g_sl3_tmpdir
procedure sl3new(path, options, errC)
return sl3msg(&null, "open", path, options, errC)
end
procedure sl3msg(cnxn, command, arg1, arg2, arg3)
static sl3_path
local errC, chunk, unparsed, i
initial {
# initialize path to sqlite3; else, raise "program malfunction" error
if not sl3_path := which("sqlite3")
then runerr(500, "no path found to sqlite3")
}
if /command | (/cnxn, command ~=== "open") then fail
return case command of {
"open" : { # either reopen cnxn or open new cnxn
# sl3(connection, "open", path, options, errC) : SQLite3
# - Opens a connection using a database path.
# - Produces a SQLite3 connection structure.
# - connection : &null
# - connection should be &null but is ignored.
# - Construct and produce new SQLite3 instance.
# - path : s (or &null)
# - Path to (possibly not-yet-existing) sqlite3 database.
# - When &null, defaults to ":memory:", an in-memory temp database.
# - options : s (or &null)
# - Additional options to be passed on the command line to sqlite3.
# - When &null, only standard options (-batch -json) will be passed.
# - errC : C
# - Co-expression to which error message strings will be
# transmitted.
# - When &null, error message strings will not be transmitted.
cnxn :=
vnew(
&null, # Original - "default-constuctor" behavior
&null, # Type - default to Kind || typecount
&null, # ID - default to VNom_n; n is the table counter
&null, # Metatable - use default metatable
"yes", # Disposable - this requires disposal via "close"
"SQLite3" # Kind - set to SQLite3 for all instances
) | fail
# default is to open in-memory database
/arg1 := ":memory:"
vmsg(cnxn, "put", "path", arg1)
/arg2 := "" # options passed to command line before path to database
# it may be impossible to specify tcl output mode with switches
arg2 ||:= " -batch -json"
errC := arg3
# instantiate BatonSys for sqlite3 and abort on error
# baton_system(basename:s, cmd:s, stdin:C, stdout:C) : BatonSys
vmsg(cnxn, "put", "batonsys",
baton_system(
sl3_baton_system_tmppath(),
"sqlite3 " || arg2 || " " || arg1,
¤t,
¤t
)
)
if \(@cnxn["batonsys", "Cexit"])
then {
sl3_transmit(
"batonsys constructor failed for sqlite3",
errC
)
runerr(500, "batonsys constructor failed for sqlite3")
}
# initialize keys having &null values
every vmsg(cnxn, "put", !["rows", "disposition"], &null)
# initial set-up for prepared statemeents
sl3msg(cnxn, ".param init")
# mark status as open
vmsg(cnxn, "put", "status", "open")
# return the database connection
cnxn
}
# sl3(connection, "close") : SQLite3
"close" : { # close cnxn
# sl3(connection, "close", errC) : &null
# - Purge previous results (by fetching all, if any).
# - Close and dispose connection.
# - Produces &null only when successful;
# - fails otherwise.
# - connection : SQLite3
# - open database connection
# - errC : C
# - Co-expression to which error message strings will be
# transmitted.
# - When &null, error message strings will not be transmitted.
errC := arg1
if cnxn["status"] == "open" | "fetching"
then {
vmsg(
cnxn,
"put",
"disposition",
vmsg(cnxn["batonsys"], "dispose") # send "dispose" to batonsys
)
# set status to closed/disposed
cnxn["status"] := &null
}
# produce (closed) connection
cnxn
}
"prepare" : { # parse command; produce VNom
# sl3(connection, "prepare", stmt) : VNom (as specified here)
# - Purge previous results (by fetching all, if any).
# - Parse SQL statement containing placeholders.
# - Fails when connection is not open;
# - otherwise, produces a VNom having:
# - ordered param. names for the prepared statement (param "?")
# - parameter "?" (the last parameter), a string containing a
# parameterized SQL statement compatible with sqlite3
# - connection : SQLite3
# - an open database connection
# - stmt : s
# - SQL text including placeholders; this is assigned to
# parameter "?"
# - Please provide named placeholders appropriately, as
# described at:
# https://sqlite.org/cli.html#sql_parameters
return sl3_prep_stmt(arg1)
}
# sl3(connection, "fetch") : VNom # result row
"fetch" : { # get a result VNom from left of result_L
# sl3(connection, "fetch") : VNom (representing a result row)
# - Fetch a result from the result list.
# - Produce one result row (as a VNom) from the result list.
# - This is a VNom so that fields ordered independently of their
# names.
# - connection : SQLite3
# - open database connection
if cnxn["status"] == "fetching"
then
while chunk := pop(cnxn["rows"])
do suspend chunk
cnxn["status"] := "open"
fail # fail when there are no more rows to return
}
default : { # execute command or prepares stmt specified by "command"
# sl3msg(cnxn, command, arg1, arg2, arg3)
# sl3(connection, stmt|prep_stmt, parm_L, errC) : n|fail
# - Purge previous results (by fetching all, if any).
# - Execute a SQL statement.
# - Produces &null if successful; otherwise fails.
# - On failure, a string is transmitted to errC (if not &null)
# - connection : SQLite3
# - open database connection
# - stmt|prep_stmt : s | L
# - s (stmt; for SQL text)
# - L (prep_stmt; result from "prepare" message)
# - parmL : L
# - list of parameters for stmt specifying unnamed parameter
# - errC : C
# - Co-expression to which error message strings will be
# transmitted.
# - When &null, error message strings will not be transmitted.
#
# TODO add error messaging
# send query or command to sqlite3
if /arg2
then @(errC := arg2 := create while write(&errout, @&source))
else errC := arg2 # assume that arg2 has already been activated
if (type(arg1) == "list", type(command) == "string")
then {
SL3_TRACE(&errout,
"sl3msg: preparing command for implicit prepared stmt")
command :=
sl3(cnxn, "prepare", command) | {
sl3_transmit(
"sl3msg: failure while preparing command for implicit " ||
"prepared stmt: " || command,
errC
)
fail
}
SL3_TRACE(&errout,
"sl3msg: setting params for implicit prepared stmt")
every i := vmsg(command, "key")
do
if i ~=== "?"
then {
SL3_TRACE(&errout, "sl3msg: setting param" || image(i))
vmsg(command, "put", i, pop(arg1)) | {
sl3_transmit(
"sl3msg: failure while setting param " ||
image(i) || " for implicit prepared stmt: " || command,
errC
)
fail
}
}
SL3_TRACE(&errout, "sl3msg: implicit prepared stmt ready2go")
}
case type(command) of {
"table" :
if not vmsg(command, "kind") == "PreparedStatement"
then {
sl3_transmit(
"sl3msg: command table is does not have kind " ||
"\"PreparedStatement\"",
errC
)
fail
}
else { # command has PreparedStatement as its Kind
command := sl3_bind_parms(command, errC) | {
sl3_transmit(
"sl3msg: failure to bind params to command: " ||
command,
errC
)
fail
}
SL3_TRACE(&errout, image(command))
}
"string" : {
SL3_TRACE(&errout, command)
&null
}
default : {
sl3_transmit(
"sl3msg: command should be string or \"PreparedStatement\" " ||
"VNom table but is " || type(command),
errC
)
fail
}
}
# at this point, command should be a string
command := ".param clear\n" || command
SL3_TRACE(&errout, "sl3msg - sending command:\n", command)
command @cnxn["batonsys", "Csend"]
# send "print end-of-results" command to sqlite3
sl3_transmit(".print " || SL3_EOT, cnxn["batonsys", "Csend"])
# initialize result list for non-JSON results
cnxn["rows"] := []
# initialize row-counter for non-JSON results
i := 0
# initialize string-builder for JSON results
unparsed := ""
# receive lines until "end-of-results" sentinel is encountered
while SL3_EOT ~=== (chunk := vmsg(cnxn["batonsys"], "receive"))
do {
SL3_TRACE(&errout, " sl3msg - received chunk:\n ", chunk)
# When JSON is a possibility; append chunk to unparsed
\unparsed ||:= chunk
# Only when unparsed begins with "[" are results possibly JSON
if /unparsed | not (unparsed[1] == "[")
then {
# Results are not JSON; stop looking for JSON
\unparsed := &null
# Put one-valued table onto cnxn["rows"], with ascending keys
put(cnxn["rows"], vmsg(vnew(), "put", i +:= 1, chunk))
}
}
SL3_TRACE(&errout, "sl3msg: after while, chunk is " || image(chunk))
# If JSON is still a possibility, parse or fail
if \unparsed ~== ""
then
cnxn["rows"] := jsonparse(unparsed) | {
sl3_transmit(
"sl3msg: jsonparse failed for: " || image(unparsed),
errC
)
fail
}
cnxn["status"] := "fetching"
&null # produce null on success (otherwise need to fail)
}
}
end
# convenience/legibility function, because @ has greater precedence than ||
procedure sl3_transmit(s, errC)
if \errC
then {
s @errC
return
}
end
# ref: https://sqlite.org/cli.html#sql_parameters
procedure sl3_named_parm_check(p)
if not (type(\p) == ("string" | "integer"))
then fail
p ? case move(1) of {
"?" :
if (tab(many(&digits)), pos(0))
then return
":" | "@" | "$" :
if (tab(many(&letters ++ &digits)), pos(0))
then return
default: fail
}
end
procedure sl3_bind_parms(chunk, errC)
local parm, v, rslt
rslt := ""
# row fields are ordered by VNom key
every parm := vmsg(chunk, "key")
do {
v := chunk[parm]
case type(v) of {
"string" :
if parm == "?"
then
return rslt || v
else
rslt ||:= sl3_bind_string(v, parm) || "\n"
"integer" | "real" :
rslt ||:= sl3_bind_numeric(v, parm) || "\n"
default : {
sl3_transmit(
"sl3_bind_parms: parameter value for key \"" ||
parm ||
"\" should be string|integer|real but is " || type(v),
errC
)
fail
}
}
}
fail
end
# e.g., sl3_bind_string("where's \"Waldo\"", "@puzzle")
# produces: .parameter set @puzzle "'where''s \"Waldo\"'"
procedure sl3_bind_string(s, p)
if (not sl3_named_parm_check(p)) | /s | type(s) ~== "string"
then {
write(&errout, &progname,
": FATAL error - precondition violation in sl3_bind_string(s, p)")
writes(&errout, "type(p) is ", type(p), "; p is: ");
write(&errout, image(p))
write(&errout, "type(s) is ", type(s), "; s is:");
write(&errout, " ", image(s))
fail
}
return ".parameter set " || p ||
" \"'" || # precede string value with "'
(
replacem(
s,
"\"", "\\\"", # replace " with \"
"'", "''" # replace ' with ''
) |
s
) ||
"'\"" # succede string value with '"
end
# e.g., sl3_bind_numeric("42", "@answer")
# produces: .parameter set @answer 42
procedure sl3_bind_numeric(n, p)
if (not sl3_named_parm_check(p)) | (not (n := numeric(\n)))
then {
write(&errout, &progname,
": FATAL error - precondition violation in sl3_bind_numeric(n, p)")
write(&errout, "type(n) is ", type(n), "; n is ", image(n))
write(&errout, "type(p) is ", type(p), "; p is ", image(p))
fail
}
return ".parameter set " || p || " " || n
end
# create prepared statement as VNom
procedure sl3_prep_stmt(s)
local V, p, i
# vnew(Original:T, Type:s, ID:s, Metatable:T, Disposable:s, Kind:s):V
V := vnew( , , , , , "PreparedStatement"); i := 0
every p := sl3_prep_parm(s)
do
if p == "?"
then vmsg(V, "put", "?" || (i +:= 1), &null)
else vmsg(V, "put", p, &null)
vmsg(V, "put", "?", s)
return V
end
# procedure matching pepared statement bind variables
procedure sl3_prep_parm(s)
local b
s ?
every sl3_prep_tmplt() || (b := sl3_prep_bindee()\1)
do suspend b
end
# matching procedure to match a bind variable in a prepared statement
# : sl3_prep_bindee '@' many(alphaum) | # named parameters:
# ':' many(alphaum) | # alphanum := &letters ++ &digits
# '$' many(alphaum) |
# '?' many(&digits) |
# '?' # unnamed parameter
#
procedure sl3_prep_bindee()
static alfnum
initial alfnum := &letters ++ &digits
suspend ="@" || tab(many(alfnum)) |
suspend =":" || tab(many(alfnum)) |
suspend ="$" || tab(many(alfnum)) |
suspend ="?" || tab(many(&digits)) |
suspend ="?"
end
# matching procedure to match a query context in a prepared statement
# : sl3_prep_tmplt sq nosq sq sl3_prep_tmplt |
# nosq punc |
# nosq sl3_prep_tmplt
procedure sl3_prep_tmplt()
static nosq # exclude single-quotes
static punc # characters beginning named-parameter names
initial {
nosq := &cset -- '\''
punc := '@:$?'
}
suspend ="'" || tab(many(nosq)) || ="'" || sl3_prep_tmplt() |
1(tab(any(nosq)), any(punc)) |
tab(any(nosq)) || sl3_prep_tmplt()
end
# procedure to create paths to baton files passed to baton_system
procedure sl3_baton_system_tmppath()
\g_sl3_tmpdir := tmpdir()
return tmppath( , , g_sl3_tmpdir)
end
$endif # SL3