#ifdef RCSID static char *RCSid = "$Header: readpipe.c 7010300.1 94/02/24 18:40:31 snataraj Generic $ "; #endif /* RCSID */ /* Copyright (c) 1991 by Oracle Corporation */ /* NAME readpipe.c - read a server named pipe NOTES described in ORACLE7 Server Application Developer's Guide MODIFIED (MM/DD/YY) emendez 02/02/94 - Fix for bug 157576 gdoherty 01/31/94 - make oci header inclusion for ansi or k+r adaptive rkooi 12/15/92 - add some comments tssmith 12/15/92 - Added break in for(;;) loop tssmith 12/12/92 - Creation */ /* * readpipe.c * * This OCI program demonstrates how to read messages from * a named pipe. This program can be run in * a window or terminal session, and be used to print messages * from a PL/SQL source program (an anonymous block or a * stored procedure). * * This is very useful in debugging PL/SQL programs. * * First, you must create a PL/SQL package and package body that packs * your message(s) and sends them to a named pipe. * In the example below, two 'put' procedures are implemented, * overloaded by type: VARCHAR2 and NUMBER. This you can extend * as required for additional types. * * Store this package in the server in an appropriate schema, * and grant execute privilege on it to the users who require it. * * You will need to grant execute privilege on the dbms_pipe package * to the owner of the plsdbg package below. * * Note that this example uses only a single named pipe. It could * be confusing if more than one PL/SQL program were writing to * the same pipe (unless some identifying protocol is established). * It would certainly be confusing if several OCI programs like * the one below were reading the same pipe. * * Here is the example package: * * create or replace package plsdbg as * -- the procedure put is overloaded for varchar strings * -- and numbers. extend as needed. * procedure put(info varchar2); * procedure put(n number); * end; * / * * create or replace package body plsdbg as * * procedure put(info varchar2) is * status integer; -- ret. val. required for the * -- send_message function, not used here * begin * dbms_pipe.pack_message(info); * status := dbms_pipe.send_message('ora$plsql_debug'); * end; * * procedure put(n number) is * chr varchar2(44); * status integer; * begin * chr := to_char(n); * dbms_pipe.pack_message(chr); * status := dbms_pipe.send_message('ora$plsql_debug'); * end; * end; * / * * In a PL/SQL program, you call plsdbg to write messages to the * pipe 'ora$plsql_debug' like this: * ... * declare * my_var integer; * ... * begin * my_var := 42; * ... -- program procedes until debug output is needed * plsdbg.put('Hmm, my_var is--'); * plsdbg.put(my_var); * -- and the OCI program reading ora$plsql_debug will * -- print the text message, and the value of my_var * ... */ #include #include /* These header files must be included for the type information, and #defined constants. */ #include #include #ifdef __STDC__ #include #else #include #endif /* demo constants and structs */ #include /* Declare the CDA, LDA, and HDA. */ Cda_Def lda; ub1 hda[HDA_SIZE]; Cda_Def cda; /* Define a string that holds the anonymous PL/SQL block. The block calls the DBMS_PIPE procedures to get messages written to the pipe named ora$plsql_debug. */ #define GETNEXTITEM "\ declare\ s integer;\ chr varchar2(200);\ begin\ chr := '';\ s := dbms_pipe.receive_message('ora$plsql_debug');\ if s = 0 then\ dbms_pipe.unpack_message(chr);\ end if;\ :status := s;\ :retval := chr;\ end;" /* Error-handling function */ void errrpt(); main(argc, argv) sword argc; text **argv; { text username[128]; ub1 retval[132]; sword status; /* Prepare username/password, from command line or else use scott/tiger as the default if none given on the command line. */ if (argc > 1) strncpy((char *) username, (char *) argv[1], (sword) sizeof (username) - 1); else strcpy((char *) username, "SCOTT/TIGER"); /* Connect to ORACLE. */ if (orlon(&lda, hda, username, -1, (text *) 0, -1, 0)) { printf("Cannot connect as %s. Exiting...\n", username); exit(1); } else printf("connected\n"); /* Open the cursor -- must quit if we cannot. */ if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) { printf("Error opening cursor. Exiting...\n"); exit(1); } /* Parse the anonymous PL/SQL block. */ if (oparse(&cda, (text *) GETNEXTITEM, (sb4) -1, 0, (ub4) 2)) { errrpt(); exit(1); } /* Bind the status program variable. */ if (obndrv(&cda, (text *) ":status", -1, (ub1 *) &status, (sword) sizeof (sword), SQLT_INT, -1, (sb2 *) 0, (text *) 0, -1, -1)) { errrpt(); exit(1); } /* Bind the return string (retval). */ if (obndrv(&cda, (text *) ":retval", -1, (ub1 *) retval, (sword) sizeof (retval), SQLT_STR, -1, (sb2 *) 0, (text *) 0, -1, -1)) { errrpt(); exit(1); } /* Loop to look for print messages on the pipe */ printf("listening...\n"); for (;;) { if (oexec(&cda)) { errrpt(); break; } if (status != 0) printf("Abnormal pipe status: %d\n\r", status); else printf("%s\n\r", retval); } } /* Report errors. */ void errrpt() { sword rv; text msg[1024]; /* use oerhms to get error messages longer than 70 characters */ rv = oerhms(&lda, cda.rc, msg, (sword) sizeof (msg)); printf("ORACLE ERROR\n"); printf("%.*s\n", rv, msg); }