Try OpenEdge Now
skip to main content
Programming Interfaces
External Program Interfaces : Named Pipes : UNIX named pipes : UNIX named pipe examples : Example 2: using a named pipe with ABL
 
Example 2: using a named pipe with ABL
Before working with the following procedures, create a copy of the demo database with the PRODB utility:
prodb demo demo
This example shows a simple user program that sends one line requests to an ABL message handler routine running in the background, and displays the results. The example consists of four files:
1. A script called i-pipex2 that runs the example:
I-pipex2
# Named Pipe Example 2.
#
# Create named pipes...
mknod inpipe p
mknod outpipe p
# Start OpenEdge background session with i-pipex2.p running...
bpro demo -1 -p i-pipex2.p
# Run executable i-asksql...
i-asksql
# Terminate OpenEdge background session...
echo "outpipe \"quit\"" > inpipe
cat outpipe
# Delete named pipes...
rm inpipe
rm outpipe
2. The message handler procedure, i-pipex2.p:
i-pipex2.p
/* Target variable for the request:*/
DEFINE VARIABLE sql-stmt AS CHARACTER NO-UNDO FORMAT "x(220)".
/* Holds the output file or FIFO: */
DEFINE VARIABLE out-pipe AS CHARACTER NO-UNDO FORMAT "x(32)".

/* Do forever: */
REPEAT:
  /* Set up to read from in-FIFO named "inpipe". */
INPUT FROM inpipe NO-ECHO.
  /* For each request received: */
  REPEAT:
    /* Get the output name and the request. */
IMPORT out-pipe sql-stmt.
    /* Set up to write results. */
    OUTPUT TO VALUE(out-pipe) APPEND.
    /* Pass SQL request to sub-proc. */
    RUN i-do-sql.p sql-stmt.
OUTPUT CLOSE.
    /* This loop ends when the in-FIFO is empty. Just reopen it and wait
       for the next request. */
  END.
END.
3. A subprocedure, i-do-sql.p:
i-do-sql.p
/* This program consists of a single line of code. */
{1}
4. A C source file called i-asksql.c that implements the requestor:
i-asksql.c
#include <stdio.h>
#include <fcntl.h>

main()

{
#define LEN 250
char result[LEN];
int fdi, fdo, nread;
char request[LEN+8]; /* 8 for "outpipe " + punctuation */
char *ptr;
int validq, i;
fdi = open("inpipe", O_WRONLY);
if (fdi < 0)
{ printf("Error on inpipe open\n"); exit(1);}

strcpy(request, "outpipe \""); /* request starts with 'outpipe "' */

while (1)
{
printf("\n\nEnter your request (type [RETURN] to exit):\n");
ptr = request+9;
nread = read(0, ptr, LEN);
if (nread < 2)
exit(0);
else
{
validq = 1; /* valid query? */
for (i = 9; i<nread+9; i++)
if (request[i] == '\"')
{ printf("Use only single quotes in queries.\n");
validq = 0;
break;
}

if (! validq) continue;
ptr += nread-1;
*ptr++ = '\"';
*ptr++ = '\n';
*ptr++ = '\0';
write(fdi, request, strlen(request));
            sleep(1);
fdo = open("outpipe", O_RDONLY);
if (fdo < 0)
{ printf("Error on outpipe open\n"); exit(1);}

while ((nread = read(fdo, result, LEN)) != 0)
{
result[nread] = '\0';
printf("%s", result);
}
close(fdo);
}
}
}
To prepare and run the example:
1. Use cc to compile and link the requestor source i-asksql.c to produce the executable i-asksql, as shown:
cc i-asksql.c -o i-asksql
2. Execute the i-pipex2 script to run the example:
i-pipex2
The i-pipex2 script performs the following actions:
1. It uses mknod to create two named pipes: inpipe and outpipe. Named pipe inpipe carries requests from the requestor to the message handler routine. Named pipe outpipe carries results back in the opposite direction, from the message handler to the requestor. The following figure illustrates this process.
Figure 50. Named pipes and ABL
2. It starts a background OpenEdge session that runs the message handler procedure, i-pipex2.p, with the demo database. The following line in i-pipex2.p opens the named pipe inpipe for input:
INPUT FROM inpipe NO-ECHO.
Notice that ABL accesses named pipes in exactly the same way as UNIX text files. At this point, i-pipex2.p blocks until a requestor process opens inpipe for output.
3. After starting the ABL message handler, the script starts the requestor, i-asksql, which opens inpipe for output using the following statements:
int fdi, fdo, nread;
. . .
fdi = open("inpipe", O_WRONLY);
4. As i-asksql opens inpipe, i-pipex2.p unblocks and blocks again as it attempts to read a message from inpipe. The message handler procedure, i-pipex2.p, expects single-line requests from requestors, and can handle more than one requestor. This is the syntax for message handler requests:
Syntax
output-pipe-nameSQL-statement
Each request contains the name of the named (output-named-pipe) pipe from which the requestor expects to receive results and an SQL statement (SQL-statement) surrounded by double quotes (" "). The message handler procedure reads these messages with the following statement:
IMPORT out-pipe sql-stmt.
Each requestor must specify a unique value for output-pipe-name, or results might be intermixed. (Using the requestor's PID number as part of the name ensures uniqueness. However, for that to work, the requestor probably has to create its own named pipe using the mknod() system call.) Note that for this example, the requestor, i-asksql, uses the existing named pipe outpipe created by the script.
5. As the message handler waits for input, the requestor displays the following prompt:
Enter your request (type [RETURN] to exit):
You can enter a one-line SQL query like the following SELECT from the demo database:
SELECT name FROM customer.
6. The requestor constructs a message from the name of the output pipe (outpipe, in the example) and the contents of your query, and writes the message to inpipe, as in the following statements from i-asksql.c:
char request[LEN+8]; /* 8 for "outpipe " + punctuation */
. . .
write(fdi, request, strlen(request));
7. As the message handler receives (and removes) the message from inpipe, it unblocks and opens the output pipe named in the message with the following statement:
OUTPUT TO VALUE(out-pipe).
8. The message handler blocks again, waiting for the requestor to open the same pipe for input (to receive the query result), as in the following statements from i-asksql.c:
int fdi, fdo, nread;
. . .
fdo = open("outpipe", O_RDONLY);
9. The ABL message handler then continues to compile and run the SQL query using the following statement:
RUN i-do-sql.p sql-stmt.
As the query generates output, ABL writes it one line at a time to the named pipe specified by outpipe. The requestor reads each line as it is written to the output pipe, as in the following statements from i-asksql. In the example, the requestor also writes each line to its standard output:
char result[LEN];
int fdi, fdo, nread;int fdi, fdo, nread;
. . .
while ((nread = read(fdo, result, LEN)) != 0)
{
result[nread] = '\0';
printf("%s", result);
}
Note: If there is no output, you might have entered your SQL statement incorrectly. This causes i-pipex2.p to terminate. To trap this type of error, write the SQL statement to a file instead of to a named pipe, then compile the file. If the compilation is successful, run it.
Note that although the query procedure, i-do-sql.p, contains only the single procedure parameter, {1}, you can extend it with formatting statements to avoid having to include these in each query, as in the following examples:
{1} WITH NO-LABELS.
{1} WITH EXPORT.
10. The example requestor, i-asksql, continues to prompt for queries, repeating Actions 5 through 9, until you press RETURN with no additional input.
11. After the requestor terminates, the i-pipex2 script terminates the ABL background process with the following commands:
echo "outpipe \"quit\"" > inpipe
cat outpipe
The first command sends the ABL QUIT statement to the message handler (instead of an SQL statement). The second command takes the place of Action 8, originally handled by the requestor. The requestor does not send the QUIT to terminate the ABL background process so that multiple copies of the requestor—each with its own output pipe—can run without affecting the message handler. It is necessary because a process blocks until a named pipe it opens for writing is opened for reading (see Operational characteristics of named pipes). In this case, the message handler opens named pipe outpipe for writing, and cannot execute QUIT until the cat command opens outpipe for reading.
12. The i-pipex2 script uses the rm command to remove the named pipes that it created.