8.6 Creating a Dynamic Query Exit to Access Custom Data Sources
LISTSERV supports a dynamic query exit to provide support for custom data sources other than LDAP and SQL databases, or to query LDAP or SQL data sources in a specific manner not otherwise supported by LISTSERV. This functionality is implemented as a standard LISTSERV exit with the following operational requirements:
- Registration: The name of the dynamic query exit is registered in the DYN_QUERY_EXIT configuration variable.
- Input Parameters: LISTSERV converts the EXITPARM1 through EXITPARM4 keywords to plain-text counted format (see below) and concatenates them in order from 1 through 4 to form the exit input parameter. See sample decoding code below.
Warning: These keywords can contain arbitrary data. The exit script is responsible for escaping or removing harmful characters as required by its particular environment and programming language. These parameters should not be inserted ‘as is’ in shell command strings! |
- Output requirements, successful completion: If it completes successfully, the exit must return the standard success return code for the operating system on which LISTSERV is running, and create a result file (see below).
- Output requirements, unsuccessful completion: Any error return code causes LISTSERV to fail the dynamic query. A result file does not need to be created in this case.
8.6.1 The Result File
The exit script must store the results of the dynamic query in a plain-text result file named exit.results. LISTSERV deletes this file before calling the exit.
Each record in the result file must be in Plain-Text Counted Format (see below). The first record specifies a name for each of the attributes returned by the exit. This first record must be supplied even if the query returns no data. The second and following records contain attributes for each entry returned by the query, in the same order as the first record. See the Example below.
If the query succeeds, the exit must return at least an e-mail address for each entry, and it may return additional attributes. As with LDAP and DBMS queries, the name of the attribute containing the e-mail address is defined with the E-MAIL= keyword when configuring the query.
8.6.2 Plain-Text Counted Format
A string is converted to plain-text counted format by prepending the length of the string, formatted as plain-text decimal characters, and an underscore. For instance, the string “Hello” becomes “5_Hello” and the empty string becomes “0_”. Encoded strings are concatenated with no spaces or other delimiters in between. See the Example below.
8.6.3 Example
In this example, we will use a dynamic query called SAMPLE, which has been defined as follows:
TYPE=EXIT E-MAIL=MAIL EXITPARM1=Employees EXITPARM2=%1
The query is invoked as:
* Sub-Lists= Query(SAMPLE,HR)
LISTSERV calls the exit with the following input argument:
9_Employees2_HR0_0_
The exit writes the following in the plain-text file, exit.results:
4_MAIL4_NAME
15_joe@example.com8_Joe User
16_jane@example.com9_Jane User
If the query had returned no results, the exit would have written the header record only :
4_MAIL4_NAME
The following sample REXX code (written for Windows exit conventions) illustrates the process of extracting exit parameters 1 through 4 from the exit input argument and creating a hardcoded query result:
/* Extract EXITPARM1..4 */
Parse arg data
ep1 = Parm()
ep2 = Parm()
ep3 = Parm()
ep4 = Parm()
/* Create hardcoded result set to illustrate encoding process */
ofile = 'exit.results'
Call Lineout ofile,N('MAIL')N('NAME')N('PHONE')
Call Lineout ofile,N('mike@example.com')N('Mike Smith')N('555-125-9182')
Call Lineout ofile,N('marie@example.com')N('Marie Jourdain')N('N/A')
/* Exit with SUCCESS return code (OS-dependent) */
Exit 0
N:
/* ENCODE to plain-text counted format */
Procedure
Parse arg line
Return Length(line)'_'line
Parm:
/* DECODE from plain-text counted format string ‘data’ (updated) */
Procedure expose data
Parse var data n'_'data
If ^Datatype(n,'W') | n < 0 Then Exit 100 /* 100 = error on any OS */
chunk = Left(data,n)
data = Substr(data,n+1)
Return chunk