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
|
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>CLI Shell Extensibility</title>
</head>
<body>
<style>
body{counter-reset: section}
h2{counter-reset: h2counter; text-indent: 10px}
h3{counter-reset: h3counter; text-indent: 25px}
h4{counter-reset: h4counter; text-indent: 40px}
h2:before{
counter-increment: section;
content: counter(section) " ";
}
h3:before{
counter-increment: h2counter;
content: counter(section) "." counter(h2counter) " ";
}
h4:before{
counter-increment: h3counter;
content: counter(section) "." counter(h2counter) "." counter(h3counter) " ";
}
h5:before{
counter-increment: h4counter;
content: counter(section) "." counter(h2counter) "." counter(h3counter) "." counter(h4counter) " ";
}
</style>
<img class="logo" src="https://sqlite.org/images/sqlite370_banner.gif"
alt="SQLite" border="0"/>
<h1>CLI Shell Extensibility</h1>
<hr/>
<h2>Introduction</h2>
<p>The command line shell for SQLite can be customized
to modify or add certain kinds of features, without altering its source.
This document details this extensibility
and how such extension may be accomplished by shell users.
<p>Shell extensibility serves to reduce the tension between
keeping the shell simple with broadly useful features
and allowing the shell to become an ever-growing tool
meeting diverse needs for those not ready to satisfy them
with a custom program using the SQLite libary.
Extensions contributed by the SQLite developers or others
will become (or are) available for use in situations
that may not justify permanently adding the same features
to the core shell published by the SQLite project in binary form.
<h2>Extensible Features</h2>
<p>Only certain categories of features may be
added or modified via extension, namely:
<h3>New or Revised Meta-Commands</h3>
<p>The "dot" commands implemented by the shell,
along with help text for them, may be augmented or overridden.
A meta-command effected with an extension may be used
in the same ways as one available in the core, non-extended shell.
<h3>New or Revised Import Modes</h3>
<p>The ways in which data may be imported to a DB table
may be augmented or overriden. Once that is done, the .import
meta-command will either have a new option to specify a new import
handler or an existing .import option can be overridden for this.
<h3>New or Revised Query Result Handling</h3>
<p>The display formatting or other disposition of query results
may be augmented or overriden. Once that is done, the .mode
meta-command will either have a new option to specify a new result
handler or an existing .mode option can be overridden for this.
<h3>Generalized Import Modes and Query Result Handling</h3>
<p>New handlers added via extension are not restricted to
importing data from a file or result display formatting.
They may be considered more generally to be either
a data source or a data sink, producing or accepting
data row sets. The origin or destination of
the data is up to the handler, as may be affected
by arguments to the .import or most recent .mode command.
<h2>Extension Methods, Dynamic or Static</h2>
<p>Shell extension may be effected at different times
in different ways according to convenience and need.
<h3>Runtime Extension</h3>
<p>Extension at runtime (when the shell is running)
is effected via the .load command with a --shell flag.
In this way, a dynamically loaded library (DLL) is loaded with
provision made for its sqlite3_X_init() function to obtain
the shell extension API entry points and thereby
register with the shell core any
new meta-commands, or import or query result handlers
that it implements.
<h3>Build-Time Extension</h3>
<p>Extension when the shell is built is effected by specifying
certain option values to either the "make" invocation or
to a utility, (tool/mkshellc.tcl), which assembles and transforms
sources to produce the shell's unitary source file (shell.c).
<h3>Extension Source Code</h3>
<p>With certain coding conventions and methods followed,
the same source code can be used either
to produce most of a runtime shell extension DLL or to
be incorporated into shell.c as a built-in shell extension.
(See the extension code samples for details.)
<h3>Build-Time Diminuation</h3>
<p>Just as new meta-commands can be readily incorporated into
the shell when it is built, many of the core meta-commands
can be readily omitted from the shell build. This is done
with a variation of the option values that may be given
to "make" or to tool/mkshellc.tcl as the shell is built.
(See tool/mkshellc.tcl --help output for details.)
Such omission of meta-commands might be done when building
a customized shell which need not have the various meta-commands
which exist for the purpose of testing the SQLite library.
<h2>Interface</h2>
<p>The following details relate to src/shext_linkage.h, a header
in which declarations appear for objects and functions
that facilitate runtime interaction between the shell core
and shell extensions written in C/C++.
Comments in that header tersely summarize these explanations:
<h3>struct ShellStateX and ShellExState</h3>
<p>The ShellStateX object, (maintained by the shell and known as
shellState), consists of a public portion, which is available and
stable for use in shell/extension interactions, and a private
portion which may not be stable. Shell extension code used only for
build-time extension might use the private part, (to which it has
access because such code is compiled within the same translation unit
as the core shell code), but such usage generally precludes (or makes
hazardous) use of runtime loadable extensions built from such code.
<h3>ExtensionId typedef and eid Member</h3>
<p>An object of this type serves to uniquely identify an extension
loaded at runtime so that it may be unloaded later. It must be
passed back to the shell (in the ShellExtensionLink eid member)
by the sqlite3_X_init() function if the extension DLL is ever
to be unloaded during that shell session.
<h3>ShellExState typedef</h3>
<p>An object of this type is passed between the shell core and its
import or query result handlers to: (1) convey or keep parameters and
data related to formatting or parsing data rows in an external form;
(2) keep state associated with the progression of an import or result
handling operation from initiation to completion; (3) to facilitate
access to exposed shell state generally useful to such handlers or
meta-commands; or (4) to provide for abnormal shell exits.
<p>The shell core .mode and .import implementations also use the same
instance of this type to affect result output and import operations.
That instance resides in a ShellStateX object kept by the shell so
that extension meta-commands can access it, possibly to change it.
Meta-commands or handlers which alter this instance for their own
purposes (rather than for intended effect) should take care to
restore its prior value as the operation completes.
<h3>extensionDestruct member</h3>
<p>The function addressed by this member will be called prior to
the extension being unloaded (if the pointer is non-zero.)
This is an out parameter from the sqlite3_X_init() function.
It may perform any cleanup or deallocations necessitated by
successful initialization generally (and will never be called
after failed initialization.)
<h3>Notes Regarding Object Interfaces for C vs C++ Writers</h3>
<p>The objects registered with the shell core to provided extension
functionality may be implemented in C or C++ (or anything else
producing the same ABI.) In the below descriptions of their
interfaces, it should be understood that: C++ implementations
need not explicitly deal with anything like a Whatsit_Vtable
struct and will refer to the object pointer, passed implicitly,
as "this"; and C implementations will need to populate a static
Whatsit_Vtable and refer to the initial object pointer as "pThis".
<p>All shell extension interfaces have a method, destruct(), which
is (or may be) called by the shell core prior to deactivating any
registered meta-command, output result or import handler.
This call will be made in addition to any automatic (or implicit)
takedown that may occur due to atexit() or C++ destructor calls,
so destruct()'s responsibility should be limited to reversing
the per-registered-object effects of sqlite3_X_init().
<p>A registered object is deactivated when either: the extension
is immanently going to be unloaded; or the registered object is
being overridden by some like-named object (such that it can no
longer be reached by the core shell.)
<h3>MetaCommand typedef</h3>
<p>These objects represent an extension meta-command, including a
dispatch table for the public interface and any accompanying
data (which is opaque to the core shell.) Such objects are created
by extensions and passed to the core shell only by reference.
They are made known to the shell core via registerMetaCommand() calls.
<h3>MetaCommand_Vtable typedef</h3>
<p>These objects represent the dispatch table of a MetaCommand object.
<p>All methods are given the same leading (or lone) argument:<br>
(1) the address of the registered MetaCommand object.
<h4>destruct method</h4>
<p>This method is called prior to unloading a runtime extension
for any registered MetaCommand object, provided its dispatch
table entry is non-zero.
It should free resources allocated during the sqlite3_X_init() call
associated with creation or preparation of the object.
<h4>name method</h4>
<p>This method returns the name of the meta-command (sans leading '.'.)
The returned pointer must remain valid throughout the lifetime of
the registered MetaCommand object.
<h4>help method</h4>
<p>This method returns help text for the meta-command. This text
should be formatted and aligned with the built-in meta-command
help text so that it can be displayed seamlessly.
<p>There is one additional argument:<br>
(2) an integer directing what help text to return, with
0 indicating primary, single-line help, or
1 indicating any more detailed help beyond the primary level.
<p>The return is either a C string or null pointer. The C string
will not be freed by the core shell, and must remain valid
during the lifetime of the MetaCommand object.
<h4>argsRange method</h4>
<p>This method returns a pair of unsigned integers indicating the range
of valid argument counts for the meta-command.
<p>The returned .minArgs value indicates the minimum number of
arguments required for a successful execute call.
The returned .maxArgs value indicates the maximum number of
arguments allowed for a successful execute call, with ~0
indicating no (practical) upper limit. The execute method will
never be called with an argument count not within this range.
(This significantly simplifies argument checking.)
<h4>execute method</h4>
<p>This method performs whatever work the meta-command is supposed
to do when invoked. It has 4 additional arguments:<br>
(2) present ShellStateX, passed by reference (an in/out parameter);<br>
(3) an error message pointer, passed by reference, set upon error but
otherwise not modified, to be freed by the shell core;<br>
(4) the number of invocation arguments;<br>
(5) an array of C strings constituting the invocation arguments;<br>
<p>The return is 0 for success, or anything else to indicate error.
The special value SHELL_INVALID_ARGS (aka SQLITE_MISUSE) should be
returned when argument checking shows an invalid call. This will
cause the command dispatcher to issue usage help (in interactive
shell sessions) without further fuss by the execute() method itself.
(And if an extension causes this error to be returned from the SQLite
library, which is a serious error by itself, it must either translate
it for return or trouble its users with a misleading error message
from the dispatcher.) If the output error message is set, it will
be issued in lieu of the standard error message for invalid calls.
<h3>OutModeHandler typedef</h3>
<p>These objects represent an extension query result handler, including
a dispatch table for the public interface and any accompanying
data which is opaque to the core shell. Such objects are created
by extensions and passed to the core shell only by reference.
They are made known to the shell core via registerOutMode() calls.
<h3>OutModeHandler_Vtable typedef</h3>
<p>These objects represent the dispatch table of an OutModeHandler object.
All methods in the dispatch table are given at
least this leading argument:<br>
(1) The OutModeHandler address registered via registerOutMode();<br>
<h4>destruct method</h4>
<p>This method is called prior to unloading a runtime extension
for any registered OutModeHandler object, provided its dispatch
table entry is non-zero.
It should free resources allocated during the sqlite3_X_init() call
associated with creation or preparation of the object.
<h4>name method</h4>
<p>This method returns the name of the OutModeHandler, which users
specify to the .mode command (as the mode's name) to designate use
of the registered OutModeHandler for subsequent query results.
The returned pointer must remain valid throughout the lifetime of
the registered MetaCommand object.
<h4>help method</h4>
<p>This method returns help text for the OutModeHandler.
<p>There is one additional argument:<br>
(2) an integer directing what help text to return, with
0 indicating primary, single-line help, or
1 indicating any more detailed help beyond the primary level.
The primary help is included in the .mode command's own
detailed help text, so it should be aligned accordingly.
The detailed help is shown by the .mode command's --help option.
<p>The return is either a C string or null pointer. The C string
will not be freed by the core shell, and must remain valid
during the lifetime of the MetaCommand object.
<h4>Common arguments</h4>
<p>The following methods are given these 2 additional arguments:<br>
(2) A ShellExState object passed by reference; and<br>
(3) An error message pointer, passed by reference, to receive errors.
<h4>openResultsOutStream method</h4>
<p>This method is called when a query output is setup,
(via the .mode command with the handler's name given as a --flag.)
<p>It is given 3 additional arguments:<br>
(4) the number of arguments in the said .mode command;<br>
(5) an array of C strings with the said argument values; and<br>
(6) the name given as a --flag which caused the handler to be used.
<p>When the extension handler is activated via a .mode command,
parsing that command and behaving accordingly is the responsibility
of this method alone. (The command is parsed and acted upon by the
default .mode implementation only when no OutModeHandler is used.)
<p>Once this method is called and succeeds, it is guaranteed that the
closeResultsOutStream method will be called.
<p>This method should return SQLITE_OK only upon success.
Any other return will abort remaining calls in the handling sequence.
<h4>prependResultsOut method</h4>
<p>This method is called when a query succeeds for which this handler
will be given the results. This is purely preparatory; zero or
more result rows may follow. It is up to this method to determine
if any results can even be had (by considering the return from
sqlite3_column_count()) and acting accordingly.
<p>It is given 1 additional argument:<br>
(4) the query prepared statement (pointer), not yet stepped.
<p>This method should return SQLITE_OK only upon success.
Any other return will abort the next 2 calls in the handling sequence.
(TBD: Such aborts without error should be supported for DDL and DML.)
<h4>rowResultsOut method</h4>
<p>This method is called when a query's prepared statement is stepped,
for each result row available.
<p>It is given 1 additional argument:<br>
(4) the query prepared statement (pointer), stepped with
a result row available. It is permitted for this method to
perform the remaining stepping, as indicated by the return.
<p>This method should return SQLITE_OK only upon success
without having completed stepping. If this method completes stepping,
(by making its own calls to sqlite3_step() until it returns SQLITE_DONE),
it must return SQLITE_DONE. Any other return will abort the next call
in the handling sequence.
<h4>appendResultsOut method</h4>
<p>This method is called when result set stepping has been completed.
<p>It is given additional argument:<br>
(4) the query prepared statement (pointer), completely stepped.
<p>This method should return SQLITE_OK upon success, or may return
something else to indicate error with no effect upon succeeding calls.
<h4>closeResultsOutStream method</h4>
<p>This method is called when a new .mode command is invoked specifying
some output mode not using this OutModeHandler or when the extension
is about to be unloaded with this OutModeHandler selected for output.
It should free resources allocated or held as a result of the
previous openResultsOutStream call.
<h3>ImportHandler typedef</h3>
<p>These objects represent an extension data import handler, including
a dispatch table for the public interface and any accompanying
data which is opaque to the core shell. Such objects are created
by extensions and passed to the core shell only by reference.
They are made known to the shell core via registerImporter() calls.
<h3>ImportHandler_Vtable typedef</h3>
<p>These objects represent the dispatch table of an ImportHandler object.
All methods in the dispatch table are given this 1 leading argument:<br>
(1) The ImportHandler address registered via registerImporter().
<h4>destruct method</h4>
<p>This method is called prior to unloading a runtime extension
for any registered OutModeHandler object, provided its dispatch
table entry is non-zero.
It should free resources allocated during the sqlite3_X_init() call
associated with creation or preparation of the object.
<h4>name method</h4>
<p>This method returns the name of the importer, which is to
be passed with leading '--' (or '-') to the .import command
to specify use of the registered importer for that invocation.
The returned pointer must remain valid throughout the lifetime of
the registered MetaCommand object.
<h4>help method</h4>
<p>This method returns help text for the importer.
<p>There is one additional argument:<br>
(2) an integer directing what help text to return, with
0 indicating primary, single-line help, or
1 indicating any more detailed help beyond the primary level.
The primary help is included in the .import command's own
detailed help text, so it should be aligned accordingly.
The detailed help is shown by the .import command's --help option.
<p>The return is either a C string or null pointer. The C string
will not be freed by the core shell, and must remain valid
during the lifetime of the MetaCommand object.
<h4>Common arguments</h4>
<p>The following methods are given these 2 additional arguments:<br>
(2) A ShellExState object passed by reference; and<br>
(3) An error message pointer, passed by reference, to receive errors.
<h4>openDataInStream method</h4>
<p>This method is called when a .import command is invoked with
the '--' (or '-') prefixed name of the ImportHandler as an argument.
<p>These 3 additional arguments are passed:<br>
(4) the number of arguments to said .import command;<br>
(5) an array of C strings with the said argument values; and<br>
(6) the name of the ImportHandler (as its name method would return.)
<p>When the extension handler is activated via a .import command,
responsibility for parsing that command and behaving accordingly is
shared between the shell core .import implementation and this method.
The shell core normally takes the last argument as the name of a table
(to be created if necessary) which will receive the imported data.
(But see return values for exceptions to this treatment.)
The shell core also detects any --flag argument selecting a registered
ImportHandler (giving effect to the last one) and calls this and
following methods to perform the input part of the import operation.
This method may interpret any or all of the arguments as needed
and (supposedly) documented by the associated help(...) method returns.
<p>Once this method is called and succeeds, it is guaranteed that the
closeDataInStream method will be called.
<p>This method should return SQLITE_OK upon success where disposition
of the imported data (into a table named by the last argument) is
to be handled normally, by the shell core.
An alternative success return is SQLITE_DONE, indicating that
disposition of the imported data has been done by the ImportHandler.
In that case, the next 3 methods (*DataInput(...)) will not be called
and this method should have completed the whole import operation.
After a success return, closeDataInStream is guaranteed to be called.
Other returns will abort all remaining calls in the handling sequence.
<h4>prepareDataInput method</h4>
<p>This method prepares for the particular import operation commenced
with a .import invocation. It may take into account the shape of
the input data (and possibly its type) as discovered during the call.
<p>This 1 additional argument is passed:<br>
(4) a to-be-prepared statement (pointer), passed by reference.
This is an out parameter conveying a prepared statement created
by this method specifically for the single import operation.
<p>The prepared statement should, in some manner wholly determined
by the extension handler, incorporate compiled SQL (possibly with
as-yet unbound parameters) which will (or may) produce a result set.
(This may be no more than a query such as "SELECT @1 as one, ...",
or could be a SELECT from a temporary table used for buffering.)
<p>The return should be SQLITE_OK upon success, in which case the
following 2 methods will also be called. Any other return will
abort the {prepare,row,finish}DataInput() call sequence. In that
case, no prepared statement should be returned either.
<h4>rowDataInput method</h4>
<p>This method is called to collect imported data, making it available
through the prepared statement passed as the last argument with as
many steps as are needed to get SQLITE_DONE from sqlite3_step().
It will be called repeatedly until its return indicates no more data.
<p>It is given 1 additional argument:<br>
(4) the prepared statement (pointer) returned by prepareDataInput().<br>
This prepared statement can have values bound to it or be reset as
necessary to return some or more data. However, it must remain the
same sqlite3_statement instance returned by prepareDataInput().
<p>The return should be SQLITE_DONE when no more data is available,
or SQLITE_ROW to indicate that more data is or might be available.
Any other return (including SQLITE_OK) indicates a condition which
will abort the data collection phase of the import operation. Any
of those 3 returns is treated as success by the shell core.
<h4>finishDataInput method</h4>
<p>This method is called to complete the data input phase of the
import operation commenced by prepareDataInput().
<p>It is given 1 additional argument:<br>
(4) the prepared statement (pointer) returned by prepareDataInput().<br>
This prepared statement should be finalized by this method. Other
cleanup or import wrap-up related to the transfer may also be performed.
<h4>closeDataInStream method</h4>
<p>This method is called as a .import command which specified this
ImportHandler completes.
It should free resources allocated or held as a result of the
previous openDataInStream call.
<h3>ShellExtensionLink typedef</h3>
<p>An object of this type is passed (somewhat indirectly) to the
sqlite3_X_init(...) function which is called when a runtime
extension is loaded via a .load command with a --shell flag.
It is used to establish linkage between the loaded extension
and a shell core API exposed specifically for extensibility.
<p>At present, the extension API is limited to registration of
meta-commands, query result handlers, and import handlers
implemented by extensions. This API may be extended in future
versions of the core shell, in a backwards-compatible manner.
(See the pExtra sentinel, whose offset may increase.)
<h4>Establishing Shell/Extension Linkage</h4>
<p>The 1st or 2nd parameter passed to the sqlite3_X_init() function
as an extension is dynamically loaded is used to obtain a pointer
to the ShellExtensionLink object (provided that .load was
invoked with the --shell flag.) To verify that the correct
object type was passed and reference it if so, the extension's
sqlite3_X_init() function can use one of these two means:
<p>The least code-intensive means is implemented by a macro,
EXTENSION_LINKAGE_PTR(pzem), parameter of which is the char**
passed as the 2nd sqlite3_X_init() argument. This is reliable
except in the case of a maliciously written shell core (which
portends worse problems than the undefined behavior which
could arise from invoking .load from such a shell.)
<p>A more code-intensive means, (which is no safer in the
case of a maliciously written shell core), is to use
a C macro, DEFINE_SHDB_TO_SHEXT_API(function_name),
in the extension source to define a function named per
the macro argument. Then that function may be called with its
lone argument being the sqlite3 * (db) pointer which was passed
as the 1st argument to sqlite3_X_init().
<p>Either means will return (or yield) either a null pointer
or a verified ShellExtensionLink pointer. In the former
case, sqlite3_X_init() may return SHELL_INVALID_ARGS to induce
the emission of help on using the .load command. (Said help
will mention the need to use the --shell flag for extensions.)
In the latter case, the obtained pointer may be called to
register the extension's feature implementor(s) as described.
<h2>Development Aspects of Extensibility and Its Evolution</h2>
<p>There is critical tension between competing uses of the ShellState
object which is kept and used by the core shell for state which
must persist between meta-command invocations. For unhindered
implementation and feature expansion flexibility, the structure
of the ShellState data should be unconstrained across versions
of the shell. However, unless extension meta-commands and data
transferers are to act entirely independently of built-in meta-commands,
(excepting interaction through the above-described extension methods),
some portion of the ShellState data needs to be shared in a stable
manner between extensions and the core shell code.
<p>With respect to interface stability concerns, it is nearly immaterial
whether the sharing occurs through exposed data structures
or an extension API devised to convey similar data. (Only data layout
and possible change notification are at stake in that choice.)
<p>For simplicity, and because it can work in a way consistent with how
built-in shell features are implemented now, the chosen sharing method
is to simply directly expose a subset of the ShellState data. That
subset will be extremely limited to minimize hinderance of what has
previously been unfettered change to that data structure/meaning.
It will initially be: the present output stream, as affected by
.output and .once commands; the currently open user DB (if any);
the dedicated shell DB; and the data related to formatting
and transfer of data in external forms. This data resides in the
ShellStateX object as a ShellExState struct.
<p>As shell extensibility evolves, additional data items may need to
move into the publicly exposed portion of the ShellStateX object,
either directly (via exposed data members) or by means of additional
extension APIs defined in the ShellExtensionLink object (which has
been defined to accommodate growth of its function pointer list in
a backwards-compatible manner.)
</body>
</html>
|