Tuesday, February 24, 2009
JRun Overview of filters
http://livedocs.adobe.com/jrun/4/Programmers_Guide/filters2.htm
Filters process request objects before they get to the server or process response objects after they leave the server and before they are returned to the client. You can use filters to do the following tasks:
Take flow-control logic out of web application components.
Examine and modify the request object before the server receives it from the client.
Examine and modify the response object before the client receives it from the server.
Change the content of the response.
...
Specifically, filters are often implemented as:
Request dispatchers
User authenticators and authorizers
Request and response loggers and auditors
Form validators
Image converters
Data compressors and decompressors
Data encryptors and decryptors
Response output tokenizers
Triggers for resource access
XML transformers
Content localizers
Filters process request objects before they get to the server or process response objects after they leave the server and before they are returned to the client. You can use filters to do the following tasks:
Take flow-control logic out of web application components.
Examine and modify the request object before the server receives it from the client.
Examine and modify the response object before the client receives it from the server.
Change the content of the response.
...
Specifically, filters are often implemented as:
Request dispatchers
User authenticators and authorizers
Request and response loggers and auditors
Form validators
Image converters
Data compressors and decompressors
Data encryptors and decryptors
Response output tokenizers
Triggers for resource access
XML transformers
Content localizers
Using the getResource method
http://livedocs.adobe.com/jrun/4/Programmers_Guide/techniques_servlet19.htm
You can use the ServletContext object's getResource method to include content in your servlet. The getResource method returns a URL object. Then you can use the URL object to access the content. One advantage of using the URL object is that you can parse the content before returning it to the browser. You can also use this technique to include content that is otherwise not accessible to the users directly, such as files in the /WEB-INF directory.
You can use the ServletContext object's getResource method to include content in your servlet. The getResource method returns a URL object. Then you can use the URL object to access the content. One advantage of using the URL object is that you can parse the content before returning it to the browser. You can also use this technique to include content that is otherwise not accessible to the users directly, such as files in the /WEB-INF directory.
JRun Passing control
Using the RequestDispatcher
Using the sendRedirect method
http://livedocs.adobe.com/jrun/4/Programmers_Guide/techniques_servlet17.htm
Using the sendRedirect method
http://livedocs.adobe.com/jrun/4/Programmers_Guide/techniques_servlet17.htm
Using databases - Understanding JDBC
http://livedocs.adobe.com/jrun/4/Programmers_Guide/techniques_servlet16.htm
JRun connection pooling mechanism...
import javax.naming.*;
import javax.sql.*;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
...
Connection dbConnection = null;
ResultSet dbResultSet = null;
ResultSetMetaData rsmd = null;
try {
��InitialContext ctx = new InitialContext();
��DataSource ds = (DataSource) ctx.lookup("compass");
��dbConnection = ds.getConnection();
��Statement stmt = dbConnection.createStatement();
��dbResultSet = stmt.executeQuery("SELECT * FROM user");
��rsmd = dbResultSet.getMetaData();
} catch (Exception e) {
}
...
//process your result set and result set metadata here
JRun Handling exceptions
http://livedocs.adobe.com/jrun/4/Programmers_Guide/techniques_servlet12.htm
Exceptions are errors detected within your servlet. Exceptions can occur at run-time, such as when a servlet processes form data, or at compile-time, such as when you pre-compile JSPs. You should catch compile-time exceptions before putting your web application into production. This section describes how to handle run-time exceptions in servlets and JSPs.
In a Java servlet, an exception is represented by an instance of the class javax.servlet.ServletException.
You can define how a web application handles errors using the error-page element in the WEB-INF/web.xml file. You can also define error handling for all web applications on the JRun server by adding error-page elements to the SERVER-INF/default-web.xml file.
The error-page element defines exceptions by exception type or by error code, as the following sections describe. The order of these elements in the web.xml file determines the error handler. JRun redirects the error processing to the location specified by the first error-page element that matches the error-code or exception-type.
��java.io.FileNotFoundException
��/error-pages/404.jsp
��500
��/error-pages/servererror.jsp
Exceptions are errors detected within your servlet. Exceptions can occur at run-time, such as when a servlet processes form data, or at compile-time, such as when you pre-compile JSPs. You should catch compile-time exceptions before putting your web application into production. This section describes how to handle run-time exceptions in servlets and JSPs.
In a Java servlet, an exception is represented by an instance of the class javax.servlet.ServletException.
You can define how a web application handles errors using the error-page element in the WEB-INF/web.xml file. You can also define error handling for all web applications on the JRun server by adding error-page elements to the SERVER-INF/default-web.xml file.
The error-page element defines exceptions by exception type or by error code, as the following sections describe. The order of these elements in the web.xml file determines the error handler. JRun redirects the error processing to the location specified by the first error-page element that matches the error-code or exception-type.
��
��
��
��
JRun Writing results back to the client
Working with special characters
Setting headers
Using the PrintWriter
Using the ServletOutputStream
http://livedocs.adobe.com/jrun/4/Programmers_Guide/techniques_servlet10.htm
Setting headers
Using the PrintWriter
Using the ServletOutputStream
http://livedocs.adobe.com/jrun/4/Programmers_Guide/techniques_servlet10.htm
Writing to the web application's root directory
Writing to the web application's temporary directory
http://livedocs.adobe.com/jrun/4/Programmers_Guide/techniques_servlet11.htm
Processing requests
http://livedocs.adobe.com/jrun/4/Programmers_Guide/techniques_servlet9.htm
Servlet requests can come in a variety of ways. Your servlets are responsible for accepting those requests, parsing client input, and then generating a response. The methods of passing data to a servlet include:
Query string parameters
Form input
Request headers
Servlet requests can come in a variety of ways. Your servlets are responsible for accepting those requests, parsing client input, and then generating a response. The methods of passing data to a servlet include:
Query string parameters
Form input
Request headers
Understanding servlet mappings
http://livedocs.adobe.com/jrun/4/Programmers_Guide/techniques_servlet6.htm
To access any servlet on a JRun server, you can use the implicit /servlet mapping as long as you store the servlet in the /WEB-INF/classes directory. For example, if you store the MyServlet.class file in /WEB-INF/classes, you can request http://yourhost/servlet/MyServlet to request that servlet.
This mapping is predefined in the default-web.xml file, as the following example shows:
��ServletInvoker
��/servlet/
To access any servlet on a JRun server, you can use the implicit /servlet mapping as long as you store the servlet in the /WEB-INF/classes directory. For example, if you store the MyServlet.class file in /WEB-INF/classes, you can request http://yourhost/servlet/MyServlet to request that servlet.
This mapping is predefined in the default-web.xml file, as the following example shows:
��
��
JRun security architecture
Using a customized security implementation
http://livedocs.adobe.com/jrun/4/JRun_Administrators_Guide/authentic5.htm
http://livedocs.adobe.com/jrun/4/JRun_Administrators_Guide/authentic.htm
Using HttpServlet
http://livedocs.adobe.com/jrun/4/Programmers_Guide/techniques_servlet4.htm
http://livedocs.adobe.com/jrun/4/JRun_Administrators_Guide/authentic5.htm
http://livedocs.adobe.com/jrun/4/JRun_Administrators_Guide/authentic.htm
Using HttpServlet
http://livedocs.adobe.com/jrun/4/Programmers_Guide/techniques_servlet4.htm
The JAAS-based JRun 4 security architecture is incompatible with the proprietary JRun 3.x security architecture
http://livedocs.adobe.com/jrun/4/JRun_Service_Pack_1_Guide/4relnotes9.htm
http://livedocs.adobe.com/jrun/4/JRun_Service_Pack_1_Guide/4relnotes9.htm#1177288
To use a custom JRun 3.x security implementation class with JRun 4:
Confirm that your customized security implementation can be used in JRun 4 and modify as necessary, as described in "Usage notes".
Open the JRun server's SERVER-INF/jrun.xml file.
Comment out the JRunUserManager service.
Add the following JRunUserManager service, specifying the fully qualified class name of your customized JRun 3.x security implementation in the authenticationManager and authenticationInterface attributes:
true
authentication.ClassName
authentication.ClassName
Save the jrun.xml file.
Copy your customized security implementation to the jrun_root/servers/lib directory.
http://livedocs.adobe.com/jrun/4/JRun_Service_Pack_1_Guide/4relnotes9.htm#1177288
To use a custom JRun 3.x security implementation class with JRun 4:
Confirm that your customized security implementation can be used in JRun 4 and modify as necessary, as described in "Usage notes".
Open the JRun server's SERVER-INF/jrun.xml file.
Comment out the JRunUserManager service.
Add the following JRunUserManager service, specifying the fully qualified class name of your customized JRun 3.x security implementation in the authenticationManager and authenticationInterface attributes:
authentication.ClassName
Save the jrun.xml file.
Copy your customized security implementation to the jrun_root/servers/lib directory.
Using multiple JVM combinations
http://livedocs.adobe.com/jrun/4/JRun_Service_Pack_1_Guide/4relnotes7.htm
You can use more than one set of JVM configuration properties for the JRun servers in a JRun installation. This feature is documented in Installing JRun, and is available from the command line and when running JRun as a Windows service.
For the following procedures, you can put the custom configuration file in the jrun_root/bin directory, or you can specify a complete path to the file.
To set up and use a custom JVM configuration from the command line:
Copy the jrun_root/bin/jvm.config file to a new filename.
Modify the new .config file to meet your needs.
At a command prompt or shell, start a JRun server using the following command:
jrun -config custom_jvm.config -start jrun_server
where custom_jvm.config is the name of your JVM configuration file, and jrun_server is the name of your JRun server. You can specify one or more server names separated by commas.
To use a custom JVM configuration when starting JRun as a Windows service:
Install the service using the following command:
jrunsvc -install jrun_server service-name service-display service-description
-config custom_jvm.config
You can use more than one set of JVM configuration properties for the JRun servers in a JRun installation. This feature is documented in Installing JRun, and is available from the command line and when running JRun as a Windows service.
For the following procedures, you can put the custom configuration file in the jrun_root/bin directory, or you can specify a complete path to the file.
To set up and use a custom JVM configuration from the command line:
Copy the jrun_root/bin/jvm.config file to a new filename.
Modify the new .config file to meet your needs.
At a command prompt or shell, start a JRun server using the following command:
jrun -config custom_jvm.config -start jrun_server
where custom_jvm.config is the name of your JVM configuration file, and jrun_server is the name of your JRun server. You can specify one or more server names separated by commas.
To use a custom JVM configuration when starting JRun as a Windows service:
Install the service using the following command:
jrunsvc -install jrun_server service-name service-display service-description
-config custom_jvm.config
Sunday, February 22, 2009
DBMS_JAVA Package
Using the SAVEPOINT Statement
http://www.csee.umbc.edu/help/oracle8/server.815/a68022/trans.htm#388
http://www.oracle.com.cn/other/9ionlinedoc/appdev.920/a97269/toc.htm
EXEC SQL SAVEPOINT start_delete1;
EXEC SQL DELETE FROM mail_list
WHERE stat = 'INACTIVES';
if (sqlca.sqlerrd[2] < 25) /* check number of rows deleted */
printf("Number of rows deleted is %d\n", sqlca.sqlerrd[2]);
else
{
printf("Undoing deletion %d rows\n", sqlca.sqlerrd[2]);
EXEC SQL WHENEVER SQLERROR GOTO sql_error;
EXEC SQL ROLLBACK TO SAVEPOINT start_delete1;
}
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL COMMIT WORK RELEASE;
http://www.oracle.com.cn/other/9ionlinedoc/appdev.920/a97269/toc.htm
EXEC SQL SAVEPOINT start_delete1;
EXEC SQL DELETE FROM mail_list
WHERE stat = 'INACTIVES';
if (sqlca.sqlerrd[2] < 25) /* check number of rows deleted */
printf("Number of rows deleted is %d\n", sqlca.sqlerrd[2]);
else
{
printf("Undoing deletion %d rows\n", sqlca.sqlerrd[2]);
EXEC SQL WHENEVER SQLERROR GOTO sql_error;
EXEC SQL ROLLBACK TO SAVEPOINT start_delete1;
}
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL COMMIT WORK RELEASE;
Saturday, February 14, 2009
C Programming Tips!
int a,b,c,d;
a=b=c=d=10;
(a>b?a:b)
while(i++>10)a=a+10;
for(i=0;i++<10;)a=a+10;
for(i=0,j=0;i++<10;)a=a+10;
for(;;) infinate loop
for(;a=="";)
break;
continue;
switch(i)
{
case 1:
printf(...
break;
case 2:
....
default:
...
}
goto sos;
sos:
....;
Pointers
========
int i=3,*j,**k;
j=&i;
k=&j;
value 3 of obtained from
i, *(&i), *j, **k
**k = 3+1;
printf(i) gives 4
header file
===========
trigger init and exit functions.
#pragma startup func1
#pragma exit func2
passing an array to a function
==============================
int num[]={1,2,3,4,5};
disp(&num[0],5);//or disp(num,5);//*num or *(num+0) gives zeroth element.
disp(int *j, int n){
for(i=0;i<=n-1;i++)
{printf("%d", *j);j++;}
}
array pointers
==============
s[2][1] equals to
*(s[2] + 1)
*(*(s + 2) + 1)
a=b=c=d=10;
(a>b?a:b)
while(i++>10)a=a+10;
for(i=0;i++<10;)a=a+10;
for(i=0,j=0;i++<10;)a=a+10;
for(;;) infinate loop
for(;a=="";)
break;
continue;
switch(i)
{
case 1:
printf(...
break;
case 2:
....
default:
...
}
goto sos;
sos:
....;
Pointers
========
int i=3,*j,**k;
j=&i;
k=&j;
value 3 of obtained from
i, *(&i), *j, **k
**k = 3+1;
printf(i) gives 4
header file
===========
trigger init and exit functions.
#pragma startup func1
#pragma exit func2
passing an array to a function
==============================
int num[]={1,2,3,4,5};
disp(&num[0],5);//or disp(num,5);//*num or *(num+0) gives zeroth element.
disp(int *j, int n){
for(i=0;i<=n-1;i++)
{printf("%d", *j);j++;}
}
array pointers
==============
s[2][1] equals to
*(s[2] + 1)
*(*(s + 2) + 1)
Sunday, February 8, 2009
VARCHAR Usage in Pro*C
VARCHAR Index[UNAME_LEN];
VARCHAR Path[PATH_LEN];
VARCHAR Name[NAME_LEN];
strncpy((char *) Index.arr, Index, INDEX_LEN);
Index.len = (unsigned short) strlen((char *)Index.arr);
strncpy((char *) Path.arr, pPath, PATH_LEN);
Path.len = (unsigned short) strlen((char *) Path.arr);
strncpy((char *) Name.arr, pName, NAME_LEN);
Name.len = (unsigned short) strlen((char *) Name.arr);
EXEC SQL INSERT INTO TABLE (Index,File,Name)
VALUES(:Index, :File, :Name);
VARCHAR Path[PATH_LEN];
VARCHAR Name[NAME_LEN];
strncpy((char *) Index.arr, Index, INDEX_LEN);
Index.len = (unsigned short) strlen((char *)Index.arr);
strncpy((char *) Path.arr, pPath, PATH_LEN);
Path.len = (unsigned short) strlen((char *) Path.arr);
strncpy((char *) Name.arr, pName, NAME_LEN);
Name.len = (unsigned short) strlen((char *) Name.arr);
EXEC SQL INSERT INTO TABLE (Index,File,Name)
VALUES(:Index, :File, :Name);
Date in Pro*C
char another_dt[21];
EXEC SQL VAR another_dt IS STRING(21);
EXEC SQL BEGIN DECLARE SECTION;
varchar dt[21];
EXEC SQL END DECLARE SECTION;
strcpy(user,"XXXXX@xxx.xxx");
strcpy(passwd,"XXXXX");
EXEC SQL WHENEVER SQLERROR DO print_error_msg();
EXEC SQL WHENEVER SQLWARNING DO print_warning_msg();
EXEC SQL CONNECT :user IDENTIFIED BY :passwd;
memset(dt.arr,'',21);
EXEC SQL SELECT TO_CHAR(sysdate,'DD/MON/YYYY HH24:MI:SS') into :dt from dual;
EXEC SQL SELECT TO_CHAR(sysdate,'DD/MON/YYYY HH24:MI:SS') into :another_dt from dual;
dt.len = strlen(dt.arr);
printf("Date is :%sn",dt.arr);
printf("Another Date is :%sn",another_dt);
EXEC SQL VAR another_dt IS STRING(21);
EXEC SQL BEGIN DECLARE SECTION;
varchar dt[21];
EXEC SQL END DECLARE SECTION;
strcpy(user,"XXXXX@xxx.xxx");
strcpy(passwd,"XXXXX");
EXEC SQL WHENEVER SQLERROR DO print_error_msg();
EXEC SQL WHENEVER SQLWARNING DO print_warning_msg();
EXEC SQL CONNECT :user IDENTIFIED BY :passwd;
memset(dt.arr,'',21);
EXEC SQL SELECT TO_CHAR(sysdate,'DD/MON/YYYY HH24:MI:SS') into :dt from dual;
EXEC SQL SELECT TO_CHAR(sysdate,'DD/MON/YYYY HH24:MI:SS') into :another_dt from dual;
dt.len = strlen(dt.arr);
printf("Date is :%sn",dt.arr);
printf("Another Date is :%sn",another_dt);
Host Arrays and Structs in Stored Procedures
#include
#include
#include
#include
#include
#include
#DEFINE SQL_LEN 300
#DEFINE REC_LEN 30
#DEFINE MAX(A,B) ((A) > (B) ? (A) : (B))
EXEC SQL BEGIN DECLARE SECTION;
struct record {
VARCHAR npa[3];
VARCHAR npa[3];
...
}
typedef struct record recorddata;
VARCHAR host_string[SQL_LEN];
EXEC SQL END DECLARE SECTION;
strcpy((char*)host_string.arr, "BEGIN ICVC.SP_LOAD_TTC (:npa, :npx, ...); END;");
host_string.len = strlen((char*)host_string.arr);
void main()
{
insertdata();
}
void insertdata()
{
int i, cnt;
char *str;
recorddata rec_in[REC_LEN];
str = (char *)malloc (25 * sizeof(char));
for (i = 0; i < REC_LEN; i++)
{
sprintf(str, "001");
strcpy (rec_in[i].npx.arr, str);
rec_in[i].npx.len = strlen (rec_in[i].npx.arr);
rec_in[i].npx.arr[rec_in[i].npx.len] = '\0';
sprintf(str, "001");
strcpy (rec_in[i].npa.arr, str);
rec_in[i].npa.len = strlen (rec_in[i].npa.arr);
rec_in[i].npa.arr[rec_in[i].npa.len] = '\0';
...
}
free (str);
/*
EXEC SQL EXECUTE
BEGIN
ICVC.SP_LOAD_TTC (:rec_in,, :ret_code);
END;
END-EXEC;
OR
EXEC SQL ARRAYLEN int_tab (REC_LEN) EXECUTE;
char *stmt3 = "begin pkg.proc1(:v1, :v2, :v3); end; ";
EXEC SQL PREPARE s3 FROM :host_string;
EXEC SQL EXECUTE s3 USING :rec_in, :REC_LEN, :rec_in;
OR
*/
EXEC SQL CALL ICVC.SP_LOAD_TTC (:rec_in, :status :ret_code);
if(status==0){
}
==============================================================
Default Value
char v_location[12] = {'\0'};
CREATE OR REPLACE PACKAGE pkg AS
TYPE tab IS TABLE OF NUMBER(5) INDEX BY BINARY_INTEGER;
PROCEDURE proc1 (parm1 tab, parm2 NUMBER, parm3 tab);
END;
The following Pro*C/C++ function demonstrates how host arrays can be used to determine how many times a given PL/SQL block is executed. In this case, the PL/SQL block will be executed 3 times resulting in 3 new rows in the emp table.
func1()
{
int empno_arr[5] = {1111, 2222, 3333, 4444, 5555};
char *ename_arr[3] = {"MICKEY", "MINNIE", "GOOFY"};
char *stmt1 = "BEGIN INSERT INTO emp(empno, ename) VALUES :b1, :b2; END;";
EXEC SQL PREPARE s1 FROM :stmt1;
EXEC SQL EXECUTE s1 USING :empno_arr, :ename_arr;
}
The following Pro*C/C++ function demonstrates how to bind a host array to a PL/SQL index table through dynamic method 2. Note the presence of the ARRAYLEN...EXECUTE statement for all host arrays specified in the EXEC SQL EXECUTE statement.
func2()
{
int ii = 2;
int int_tab[3] = {1,2,3};
int dim = 3;
EXEC SQL ARRAYLEN int_tab (dim) EXECUTE;
char *stmt2 = "begin pkg.proc1(:v1, :v2, :v3); end; ";
EXEC SQL PREPARE s2 FROM :stmt2;
EXEC SQL EXECUTE s2 USING :int_tab, :ii, :int_tab;
}
However the following Pro*C/C++ function will result in a precompile-time warning because there is no ARRAYLEN...EXECUTE statement for int_arr.
func3()
{
int int_arr[3];
int int_tab[3] = {1,2,3};
int dim = 3;
EXEC SQL ARRAYLEN int_tab (dim) EXECUTE;
char *stmt3 = "begin pkg.proc1(:v1, :v2, :v3); end; ";
EXEC SQL PREPARE s3 FROM :stmt3;
EXEC SQL EXECUTE s3 USING :int_tab, :int_arr, :int_tab;
}
#include
#include
#include
#include
#include
#DEFINE SQL_LEN 300
#DEFINE REC_LEN 30
#DEFINE MAX(A,B) ((A) > (B) ? (A) : (B))
EXEC SQL BEGIN DECLARE SECTION;
struct record {
VARCHAR npa[3];
VARCHAR npa[3];
...
}
typedef struct record recorddata;
VARCHAR host_string[SQL_LEN];
EXEC SQL END DECLARE SECTION;
strcpy((char*)host_string.arr, "BEGIN ICVC.SP_LOAD_TTC (:npa, :npx, ...); END;");
host_string.len = strlen((char*)host_string.arr);
void main()
{
insertdata();
}
void insertdata()
{
int i, cnt;
char *str;
recorddata rec_in[REC_LEN];
str = (char *)malloc (25 * sizeof(char));
for (i = 0; i < REC_LEN; i++)
{
sprintf(str, "001");
strcpy (rec_in[i].npx.arr, str);
rec_in[i].npx.len = strlen (rec_in[i].npx.arr);
rec_in[i].npx.arr[rec_in[i].npx.len] = '\0';
sprintf(str, "001");
strcpy (rec_in[i].npa.arr, str);
rec_in[i].npa.len = strlen (rec_in[i].npa.arr);
rec_in[i].npa.arr[rec_in[i].npa.len] = '\0';
...
}
free (str);
/*
EXEC SQL EXECUTE
BEGIN
ICVC.SP_LOAD_TTC (:rec_in,, :ret_code);
END;
END-EXEC;
OR
EXEC SQL ARRAYLEN int_tab (REC_LEN) EXECUTE;
char *stmt3 = "begin pkg.proc1(:v1, :v2, :v3); end; ";
EXEC SQL PREPARE s3 FROM :host_string;
EXEC SQL EXECUTE s3 USING :rec_in, :REC_LEN, :rec_in;
OR
*/
EXEC SQL CALL ICVC.SP_LOAD_TTC (:rec_in, :status :ret_code);
if(status==0){
}
==============================================================
Default Value
char v_location[12] = {'\0'};
CREATE OR REPLACE PACKAGE pkg AS
TYPE tab IS TABLE OF NUMBER(5) INDEX BY BINARY_INTEGER;
PROCEDURE proc1 (parm1 tab, parm2 NUMBER, parm3 tab);
END;
The following Pro*C/C++ function demonstrates how host arrays can be used to determine how many times a given PL/SQL block is executed. In this case, the PL/SQL block will be executed 3 times resulting in 3 new rows in the emp table.
func1()
{
int empno_arr[5] = {1111, 2222, 3333, 4444, 5555};
char *ename_arr[3] = {"MICKEY", "MINNIE", "GOOFY"};
char *stmt1 = "BEGIN INSERT INTO emp(empno, ename) VALUES :b1, :b2; END;";
EXEC SQL PREPARE s1 FROM :stmt1;
EXEC SQL EXECUTE s1 USING :empno_arr, :ename_arr;
}
The following Pro*C/C++ function demonstrates how to bind a host array to a PL/SQL index table through dynamic method 2. Note the presence of the ARRAYLEN...EXECUTE statement for all host arrays specified in the EXEC SQL EXECUTE statement.
func2()
{
int ii = 2;
int int_tab[3] = {1,2,3};
int dim = 3;
EXEC SQL ARRAYLEN int_tab (dim) EXECUTE;
char *stmt2 = "begin pkg.proc1(:v1, :v2, :v3); end; ";
EXEC SQL PREPARE s2 FROM :stmt2;
EXEC SQL EXECUTE s2 USING :int_tab, :ii, :int_tab;
}
However the following Pro*C/C++ function will result in a precompile-time warning because there is no ARRAYLEN...EXECUTE statement for int_arr.
func3()
{
int int_arr[3];
int int_tab[3] = {1,2,3};
int dim = 3;
EXEC SQL ARRAYLEN int_tab (dim) EXECUTE;
char *stmt3 = "begin pkg.proc1(:v1, :v2, :v3); end; ";
EXEC SQL PREPARE s3 FROM :stmt3;
EXEC SQL EXECUTE s3 USING :int_tab, :int_arr, :int_tab;
}
Pro*C Documentation
Some Good References
http://wtcis.wtamu.edu/oracle/win.102/b14321.pdf
http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28427/pc_08arr.htm
http://www.ibm.com/developerworks/data/library/techarticle/0309greenstein/0309greenstein.html
http://www.sc.ehu.es/siwebso/KZCC/Oracle_10g_Documentacion/appdev.101/a97269/pc_07pls.htm
http://wtcis.wtamu.edu/oracle/win.102/b14321.pdf
http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28427/pc_08arr.htm
http://www.ibm.com/developerworks/data/library/techarticle/0309greenstein/0309greenstein.html
http://www.sc.ehu.es/siwebso/KZCC/Oracle_10g_Documentacion/appdev.101/a97269/pc_07pls.htm
Inserting and Fetching Rows by Using the Array and loading into Stored Procedure in Pro*C
http://infolab.stanford.edu/~ullman/fcdb/oracle/or-proc.html
http://www.lsbu.ac.uk/oracle/oracle7/api/doc/PC_22/ch03a.htm
http://forums.oracle.com/forums/thread.jspa?messageID=1661451
http://asktom.oracle.com/pls/asktom/
f?p=100:11:0::::P11_QUESTION_ID:208012348074
http://www.filibeto.org/sun/lib/nonsun/oracle/
11.1.0.6.0/B28359_01/appdev.111/b28427/pc_08arr.htm
how to compile?
&
int emp_number[50];
char name[50][11];
/* ... */
EXEC SQL INSERT INTO emp(emp_number, name)
VALUES (:emp_number, :emp_name);
which will insert all the 50 tuples in one go.
*/
#DEFINE SQL_LEN 300
EXEC SQL BEGIN DECLARE SECTION;
struct record {
VARCHAR npa[50][3];
VARCHAR npa[50][3];
...
}
typedef struct record recorddata;
VARCHAR host_string[SQL_LEN];
EXEC SQL END DECLARE SECTION;
strcpy((char*)host_string.arr, "SCHEMA.PROCEDURENAME(:records[5].npa, :records[5].npx, ...)");
host_string.len = strlen((char*)host_string.arr);
EXEC SQL PREPARE stmt FROM :host_string;
/*
EXEC SQL EXECUTE stmt USING :npa, :npx, ...;
OR
rows_to_insert = 25; /* set FOR-clause variable */
EXEC SQL FOR :rows_to_insert EXECUTE stmt USING :npa, :npx, ...;
===============================================================
void insertdata()
{
int i, cnt, file_cnt=0, temp_cnt=0;
char *str;
recorddata rec_in;
while(loopFile){
file_cnt = file_cnt + 1;
/* To store temporary strings */
str = (char *)malloc (25 * sizeof(char));
/* Fill the array elements to insert */
for (i = 0; i < 50; i++)
{
temp_cnt = tmp_cnt +1;
sprintf(str, "001");
strcpy (rec_in.npx[i].arr, str);
rec_in.npx[i].len = strlen (rec_in.npx[i].arr);
rec_in.npx[i].arr[rec_in.npx[i].len] = '\0';
sprintf(str, "001");
strcpy (rec_in.npa[i].arr, str);
rec_in.npa[i].len = strlen (rec_in.npa[i].arr);
rec_in.npa[i].arr[rec_in.npa[i].len] = '\0';
...
}
if (temp_cnt == 50){
free (str);
EXEC SQL EXECUTE SCHEMA.PROCEDURENAME(:npa, :npx, ...) USING :rec_in.npa, :rec_in.npx, ...;
temp_cnt=0;
}
}end while
http://www.lsbu.ac.uk/oracle/oracle7/api/doc/PC_22/ch03a.htm
http://forums.oracle.com/forums/thread.jspa?messageID=1661451
http://asktom.oracle.com/pls/asktom/
f?p=100:11:0::::P11_QUESTION_ID:208012348074
http://www.filibeto.org/sun/lib/nonsun/oracle/
11.1.0.6.0/B28359_01/appdev.111/b28427/pc_08arr.htm
how to compile?
&
int emp_number[50];
char name[50][11];
/* ... */
EXEC SQL INSERT INTO emp(emp_number, name)
VALUES (:emp_number, :emp_name);
which will insert all the 50 tuples in one go.
*/
#DEFINE SQL_LEN 300
EXEC SQL BEGIN DECLARE SECTION;
struct record {
VARCHAR npa[50][3];
VARCHAR npa[50][3];
...
}
typedef struct record recorddata;
VARCHAR host_string[SQL_LEN];
EXEC SQL END DECLARE SECTION;
strcpy((char*)host_string.arr, "SCHEMA.PROCEDURENAME(:records[5].npa, :records[5].npx, ...)");
host_string.len = strlen((char*)host_string.arr);
EXEC SQL PREPARE stmt FROM :host_string;
/*
EXEC SQL EXECUTE stmt USING :npa, :npx, ...;
OR
rows_to_insert = 25; /* set FOR-clause variable */
EXEC SQL FOR :rows_to_insert EXECUTE stmt USING :npa, :npx, ...;
===============================================================
void insertdata()
{
int i, cnt, file_cnt=0, temp_cnt=0;
char *str;
recorddata rec_in;
while(loopFile){
file_cnt = file_cnt + 1;
/* To store temporary strings */
str = (char *)malloc (25 * sizeof(char));
/* Fill the array elements to insert */
for (i = 0; i < 50; i++)
{
temp_cnt = tmp_cnt +1;
sprintf(str, "001");
strcpy (rec_in.npx[i].arr, str);
rec_in.npx[i].len = strlen (rec_in.npx[i].arr);
rec_in.npx[i].arr[rec_in.npx[i].len] = '\0';
sprintf(str, "001");
strcpy (rec_in.npa[i].arr, str);
rec_in.npa[i].len = strlen (rec_in.npa[i].arr);
rec_in.npa[i].arr[rec_in.npa[i].len] = '\0';
...
}
if (temp_cnt == 50){
free (str);
EXEC SQL EXECUTE SCHEMA.PROCEDURENAME(:npa, :npx, ...) USING :rec_in.npa, :rec_in.npx, ...;
temp_cnt=0;
}
}end while
Dynamic SQL/Oracle Tutorial
http://www.cs.ubc.ca/~ramesh/cpsc304/tutorial/DynamicSQL/dynamicSQL1.html
PREPARE:
VARCHAR host_string[64];
char *examCount = "SELECT driver_sin, count(exam_score) FROM exam WHERE exam_type = :typ GROUP BY driver_sin";
strcpy((char*)host_string.arr, "INSERT INTO branch VALUES (:bid, :bname, :baddr, :bcity, :bphone)");
host_string.len = strlen((char*)host_string.arr);
EXEC SQL PREPARE stmt FROM :host_string;
EXEC SQL PREPARE stmt2 FROM "INSERT INTO branch VALUES (:bid, :bname, :baddr, :bcity, :bphone)";
EXEC SQL PREPARE stmt3 FROM :examCount;
EXECUTE:
int branchID;
char branchName[20];
char branchAddr[50];
char branchCity[20];
int branchPhone;
short int branchAddr_ind;
short int branchPhone_ind;
int branchID2;
char branchName2[20];
char branchAddr2[50];
char branchCity2[20];
int branchPhone2;
short int branchAddr2_ind;
short int branchPhone2_ind;
/* get values for your host variables */
EXEC SQL EXECUTE stmt USING :branchID, :branchName, :branchAddr:branchAddr_ind, :branchCity, :branchPhone:branchPhone_ind;
EXEC SQL EXECUTE stmt USING :branchID2, :branchName2, :branchAddr2:branchAddr2_ind, :branchCity2, :branchPhone2:branchPhone2_ind;
A statement can be re-executed using different host variables without needing a re-PREPARE. A re-PREPARE is only necessary when you want to associate a statement name with another statement.
PREPARE:
VARCHAR host_string[64];
char *examCount = "SELECT driver_sin, count(exam_score) FROM exam WHERE exam_type = :typ GROUP BY driver_sin";
strcpy((char*)host_string.arr, "INSERT INTO branch VALUES (:bid, :bname, :baddr, :bcity, :bphone)");
host_string.len = strlen((char*)host_string.arr);
EXEC SQL PREPARE stmt FROM :host_string;
EXEC SQL PREPARE stmt2 FROM "INSERT INTO branch VALUES (:bid, :bname, :baddr, :bcity, :bphone)";
EXEC SQL PREPARE stmt3 FROM :examCount;
EXECUTE:
int branchID;
char branchName[20];
char branchAddr[50];
char branchCity[20];
int branchPhone;
short int branchAddr_ind;
short int branchPhone_ind;
int branchID2;
char branchName2[20];
char branchAddr2[50];
char branchCity2[20];
int branchPhone2;
short int branchAddr2_ind;
short int branchPhone2_ind;
/* get values for your host variables */
EXEC SQL EXECUTE stmt USING :branchID, :branchName, :branchAddr:branchAddr_ind, :branchCity, :branchPhone:branchPhone_ind;
EXEC SQL EXECUTE stmt USING :branchID2, :branchName2, :branchAddr2:branchAddr2_ind, :branchCity2, :branchPhone2:branchPhone2_ind;
A statement can be re-executed using different host variables without needing a re-PREPARE. A re-PREPARE is only necessary when you want to associate a statement name with another statement.
Saturday, February 7, 2009
Using the Object Type Translator in Pro*C
http://www.cs.umbc.edu/help/oracle8.bak/server803/A54661_01/ott.htm#420181
CREATE TYPE my_varray AS VARRAY(5) of integer;
CREATE TYPE object_type AS OBJECT
(object_name VARCHAR2(20));
CREATE TYPE my_table AS TABLE OF object_type;
CREATE TYPE many_types AS OBJECT
( the_varchar VARCHAR2(30),
the_char CHAR(3),
the_blob BLOB,
the_clob CLOB,
the_object object_type,
another_ref REF other_type,
the_ref REF many_types,
the_varray my_varray,
the_table my_table,
the_date DATE,
the_num NUMBER,
the_raw RAW(255));
and an intype file that includes:
CASE = LOWER
TYPE many_types
CREATE TYPE my_varray AS VARRAY(5) of integer;
CREATE TYPE object_type AS OBJECT
(object_name VARCHAR2(20));
CREATE TYPE my_table AS TABLE OF object_type;
CREATE TYPE many_types AS OBJECT
( the_varchar VARCHAR2(30),
the_char CHAR(3),
the_blob BLOB,
the_clob CLOB,
the_object object_type,
another_ref REF other_type,
the_ref REF many_types,
the_varray my_varray,
the_table my_table,
the_date DATE,
the_num NUMBER,
the_raw RAW(255));
and an intype file that includes:
CASE = LOWER
TYPE many_types
EXEC SQL FOR
http://www.cs.umbc.edu/help/oracle8.bak/server803/A54661_01/arr.htm#390
rows_to_insert = 25; /* set FOR-clause variable */
EXEC SQL FOR :rows_to_insert /* will process only 25 rows */
INSERT INTO emp (ename, sal)
VALUES (:emp_name, :salary);
rows_to_insert = 25; /* set FOR-clause variable */
EXEC SQL FOR :rows_to_insert /* will process only 25 rows */
INSERT INTO emp (ename, sal)
VALUES (:emp_name, :salary);
Arrays in Pro*C
#include
#include
#include
#define NAME_LENGTH 20
#define ARRAY_LENGTH 5
/* Another way to connect. */
char *username = "SCOTT";
char *password = "TIGER";
/* Declare a host structure tag. */
struct
{
int emp_number[ARRAY_LENGTH];
char emp_name[ARRAY_LENGTH][NAME_LENGTH];
float salary[ARRAY_LENGTH];
} emp_rec;
/* Declare this program's functions. */
void print_rows(); /* produces program output */
void sql_error(); /* handles unrecoverable errors */
main()
{
int num_ret; /* number of rows returned */
/* Connect to ORACLE. */
EXEC SQL WHENEVER SQLERROR DO sql_error("Connect error:");
EXEC SQL CONNECT :username IDENTIFIED BY :password;
printf("\nConnected to ORACLE as user: %s\n", username);
EXEC SQL WHENEVER SQLERROR DO sql_error("Oracle error:");
/* Declare a cursor for the FETCH. */
EXEC SQL DECLARE c1 CURSOR FOR
SELECT empno, ename, sal FROM emp;
EXEC SQL OPEN c1;
/* Initialize the number of rows. */
num_ret = 0;
/* Array fetch loop - ends when NOT FOUND becomes true. */
EXEC SQL WHENEVER NOT FOUND DO break;
for (;;)
{
EXEC SQL FETCH c1 INTO :emp_rec;
/* Print however many rows were returned. */
print_rows(sqlca.sqlerrd[2] - num_ret);
num_ret = sqlca.sqlerrd[2]; /* Reset the number. */
}
/* Print remaining rows from last fetch, if any. */
if ((sqlca.sqlerrd[2] - num_ret) > 0)
print_rows(sqlca.sqlerrd[2] - num_ret);
EXEC SQL CLOSE c1;
printf("\nAu revoir.\n\n\n");
/* Disconnect from the database. */
EXEC SQL COMMIT WORK RELEASE;
exit(0);
}
void
print_rows(n)
int n;
{
int i;
printf("\nNumber Employee Salary");
printf("\n------ -------- ------\n");
for (i = 0; i < n; i++)
printf("%-9d%-15.15s%9.2f\n", emp_rec.emp_number[i],
emp_rec.emp_name[i], emp_rec.salary[i]);
}
void
sql_error(msg)
char *msg;
{
EXEC SQL WHENEVER SQLERROR CONTINUE;
printf("\n%s", msg);
printf("\n% .70s \n", sqlca.sqlerrm.sqlerrmc);
EXEC SQL ROLLBACK WORK RELEASE;
exit(1);
}
#include
#include
#define NAME_LENGTH 20
#define ARRAY_LENGTH 5
/* Another way to connect. */
char *username = "SCOTT";
char *password = "TIGER";
/* Declare a host structure tag. */
struct
{
int emp_number[ARRAY_LENGTH];
char emp_name[ARRAY_LENGTH][NAME_LENGTH];
float salary[ARRAY_LENGTH];
} emp_rec;
/* Declare this program's functions. */
void print_rows(); /* produces program output */
void sql_error(); /* handles unrecoverable errors */
main()
{
int num_ret; /* number of rows returned */
/* Connect to ORACLE. */
EXEC SQL WHENEVER SQLERROR DO sql_error("Connect error:");
EXEC SQL CONNECT :username IDENTIFIED BY :password;
printf("\nConnected to ORACLE as user: %s\n", username);
EXEC SQL WHENEVER SQLERROR DO sql_error("Oracle error:");
/* Declare a cursor for the FETCH. */
EXEC SQL DECLARE c1 CURSOR FOR
SELECT empno, ename, sal FROM emp;
EXEC SQL OPEN c1;
/* Initialize the number of rows. */
num_ret = 0;
/* Array fetch loop - ends when NOT FOUND becomes true. */
EXEC SQL WHENEVER NOT FOUND DO break;
for (;;)
{
EXEC SQL FETCH c1 INTO :emp_rec;
/* Print however many rows were returned. */
print_rows(sqlca.sqlerrd[2] - num_ret);
num_ret = sqlca.sqlerrd[2]; /* Reset the number. */
}
/* Print remaining rows from last fetch, if any. */
if ((sqlca.sqlerrd[2] - num_ret) > 0)
print_rows(sqlca.sqlerrd[2] - num_ret);
EXEC SQL CLOSE c1;
printf("\nAu revoir.\n\n\n");
/* Disconnect from the database. */
EXEC SQL COMMIT WORK RELEASE;
exit(0);
}
void
print_rows(n)
int n;
{
int i;
printf("\nNumber Employee Salary");
printf("\n------ -------- ------\n");
for (i = 0; i < n; i++)
printf("%-9d%-15.15s%9.2f\n", emp_rec.emp_number[i],
emp_rec.emp_name[i], emp_rec.salary[i]);
}
void
sql_error(msg)
char *msg;
{
EXEC SQL WHENEVER SQLERROR CONTINUE;
printf("\n%s", msg);
printf("\n% .70s \n", sqlca.sqlerrm.sqlerrmc);
EXEC SQL ROLLBACK WORK RELEASE;
exit(1);
}
Calling a stored procedure in Pro*C
#include
#include
EXEC SQL INCLUDE sqlca.h;
typedef char asciz[20];
typedef char vc2_arr[11];
EXEC SQL BEGIN DECLARE SECTION;
/* User-defined type for null-terminated strings */
EXEC SQL TYPE asciz IS STRING(20) REFERENCE;
/* User-defined type for a VARCHAR array element. */
EXEC SQL TYPE vc2_arr IS VARCHAR2(11) REFERENCE;
asciz username;
asciz password;
int dept_no; /* which department to query? */
vc2_arr emp_name[10]; /* array of returned names */
vc2_arr job[10];
float salary[10];
int done_flag;
int array_size;
int num_ret; /* number of rows returned */
EXEC SQL END DECLARE SECTION;
long SQLCODE;
void print_rows(); /* produces program output */
void sql_error(); /* handles unrecoverable errors */
main()
{
int i;
char temp_buf[32];
/* Connect to ORACLE. */
EXEC SQL WHENEVER SQLERROR DO sql_error();
strcpy(username, "scott");
strcpy(password, "tiger");
EXEC SQL CONNECT :username IDENTIFIED BY :password;
printf("\nConnected to ORACLE as user: %s\n\n", username);
printf("Enter department number: ");
gets(temp_buf);
dept_no = atoi(temp_buf);/* Print column headers. */
printf("\n\n");
printf("%-10.10s%-10.10s%s\n", "Employee", "Job", "Salary");
printf("%-10.10s%-10.10s%s\n", "--------", "---", "------");
/* Set the array size. */
array_size = 10;
done_flag = 0;
num_ret = 0;
/* Array fetch loop.
* The loop continues until the OUT parameter done_flag is set.
* Pass in the department number, and the array size--
* get names, jobs, and salaries back.
*/
for (;;)
{
EXEC SQL EXECUTE
BEGIN calldemo.get_employees
(:dept_no, :array_size, :num_ret, :done_flag,
:emp_name, :job, :salary);
END;
END-EXEC;
print_rows(num_ret);
if (done_flag)
break;
}
/* Disconnect from the database. */
EXEC SQL COMMIT WORK RELEASE;
exit(0);
}
void
print_rows(n)
int n;
{
int i;
if (n == 0)
{
printf("No rows retrieved.\n");
return;
}
for (i = 0; i < n; i++)
printf("%10.10s%10.10s%6.2f\n",
emp_name[i], job[i], salary[i]);
}
/* Handle errors. Exit on any error. */
void
sql_error()
{
char msg[512];
int buf_len, msg_len;
EXEC SQL WHENEVER SQLERROR CONTINUE;
buf_len = sizeof(msg);
sqlglm(msg, &buf_len, &msg_len);
printf("\nORACLE error detected:");
printf("\n%.*s \n", msg_len, msg);
EXEC SQL ROLLBACK WORK RELEASE;
exit(1);
}
#include
EXEC SQL INCLUDE sqlca.h;
typedef char asciz[20];
typedef char vc2_arr[11];
EXEC SQL BEGIN DECLARE SECTION;
/* User-defined type for null-terminated strings */
EXEC SQL TYPE asciz IS STRING(20) REFERENCE;
/* User-defined type for a VARCHAR array element. */
EXEC SQL TYPE vc2_arr IS VARCHAR2(11) REFERENCE;
asciz username;
asciz password;
int dept_no; /* which department to query? */
vc2_arr emp_name[10]; /* array of returned names */
vc2_arr job[10];
float salary[10];
int done_flag;
int array_size;
int num_ret; /* number of rows returned */
EXEC SQL END DECLARE SECTION;
long SQLCODE;
void print_rows(); /* produces program output */
void sql_error(); /* handles unrecoverable errors */
main()
{
int i;
char temp_buf[32];
/* Connect to ORACLE. */
EXEC SQL WHENEVER SQLERROR DO sql_error();
strcpy(username, "scott");
strcpy(password, "tiger");
EXEC SQL CONNECT :username IDENTIFIED BY :password;
printf("\nConnected to ORACLE as user: %s\n\n", username);
printf("Enter department number: ");
gets(temp_buf);
dept_no = atoi(temp_buf);/* Print column headers. */
printf("\n\n");
printf("%-10.10s%-10.10s%s\n", "Employee", "Job", "Salary");
printf("%-10.10s%-10.10s%s\n", "--------", "---", "------");
/* Set the array size. */
array_size = 10;
done_flag = 0;
num_ret = 0;
/* Array fetch loop.
* The loop continues until the OUT parameter done_flag is set.
* Pass in the department number, and the array size--
* get names, jobs, and salaries back.
*/
for (;;)
{
EXEC SQL EXECUTE
BEGIN calldemo.get_employees
(:dept_no, :array_size, :num_ret, :done_flag,
:emp_name, :job, :salary);
END;
END-EXEC;
print_rows(num_ret);
if (done_flag)
break;
}
/* Disconnect from the database. */
EXEC SQL COMMIT WORK RELEASE;
exit(0);
}
void
print_rows(n)
int n;
{
int i;
if (n == 0)
{
printf("No rows retrieved.\n");
return;
}
for (i = 0; i < n; i++)
printf("%10.10s%10.10s%6.2f\n",
emp_name[i], job[i], salary[i]);
}
/* Handle errors. Exit on any error. */
void
sql_error()
{
char msg[512];
int buf_len, msg_len;
EXEC SQL WHENEVER SQLERROR CONTINUE;
buf_len = sizeof(msg);
sqlglm(msg, &buf_len, &msg_len);
printf("\nORACLE error detected:");
printf("\n%.*s \n", msg_len, msg);
EXEC SQL ROLLBACK WORK RELEASE;
exit(1);
}
VARCHAR Variables and Pointers in Pro*C
VARCHAR emp_name1[10]; /* VARCHAR variable */
VARCHAR *emp_name2; /* pointer to VARCHAR */
strcpy(emp_name1.arr, "VAN HORN");
emp_name1.len = strlen(emp_name1.arr);
emp_name2 = malloc(sizeof(short) + 10) /* len + arr */
strcpy(emp_name2->arr, "MILLER");
emp_name2->len = strlen(emp_name2->arr);
Or, to make emp_name2 point to an existing VARCHAR (emp_name1 in this case), you could code the assignment
emp_name2 = &emp_name1;
VARCHAR *emp_name2; /* pointer to VARCHAR */
strcpy(emp_name1.arr, "VAN HORN");
emp_name1.len = strlen(emp_name1.arr);
emp_name2 = malloc(sizeof(short) + 10) /* len + arr */
strcpy(emp_name2->arr, "MILLER");
emp_name2->len = strlen(emp_name2->arr);
Or, to make emp_name2 point to an existing VARCHAR (emp_name1 in this case), you could code the assignment
emp_name2 = &emp_name1;
Character Pointer in Pro*C
http://www.cs.umbc.edu/help/oracle8.bak/server803/A54661_01/dev.htm#2416
...
char *p_name1;
char *p_name2;
...
p_name1 = (char *) malloc(11);
p_name2 = (char *) malloc(11);
strcpy(p_name1, " ");
strcpy(p_name2, "0123456789");
...
char *p_name1;
char *p_name2;
...
p_name1 = (char *) malloc(11);
p_name2 = (char *) malloc(11);
strcpy(p_name1, " ");
strcpy(p_name2, "0123456789");
Trailing Blanks Error in Pro*C
http://www.cs.umbc.edu/help/oracle8.bak/server803/A54661_01/dev.htm#2416
char emp_name[10];
...
strcpy(emp_name, "MILLER"); /* WRONG! Note no blank-padding */
EXEC SQL INSERT INTO emp (empno, ename, deptno) VALUES
(1234, :emp_name, 20);
you will find that the string "MILLER" was inserted as "MILLER\0\0\0\0" (with four null bytes appended to it). This value does not meet the following search condition:
. . . WHERE ename = 'MILLER';
To INSERT the character array when DBMS is set to V6 or CHAR_MAP is set to VARCHAR2, you should execute the statements
strncpy(emp_name, "MILLER ", 10); /* 4 trailing blanks */
EXEC SQL INSERT INTO emp (empno, ename, deptno) VALUES
(1234, :emp_name, 20);
input data in a character array must be null-terminated. So, make sure that your data ends with a null.
char emp_name[11]; /* Note: one greater than column size of 10 */
...
strcpy(emp_name, "MILLER"); /* No blank-padding required */
EXEC SQL INSERT INTO emp (empno, ename, deptno) VALUES
(1234, :emp_name, 20);
char emp_name[10];
...
strcpy(emp_name, "MILLER"); /* WRONG! Note no blank-padding */
EXEC SQL INSERT INTO emp (empno, ename, deptno) VALUES
(1234, :emp_name, 20);
you will find that the string "MILLER" was inserted as "MILLER\0\0\0\0" (with four null bytes appended to it). This value does not meet the following search condition:
. . . WHERE ename = 'MILLER';
To INSERT the character array when DBMS is set to V6 or CHAR_MAP is set to VARCHAR2, you should execute the statements
strncpy(emp_name, "MILLER ", 10); /* 4 trailing blanks */
EXEC SQL INSERT INTO emp (empno, ename, deptno) VALUES
(1234, :emp_name, 20);
input data in a character array must be null-terminated. So, make sure that your data ends with a null.
char emp_name[11]; /* Note: one greater than column size of 10 */
...
strcpy(emp_name, "MILLER"); /* No blank-padding required */
EXEC SQL INSERT INTO emp (empno, ename, deptno) VALUES
(1234, :emp_name, 20);
Usage of the CHAR_MAP in Pro*C
char ch_array[5];
strncpy(ch_array, "12345", 5);
/* char_map=charz is the default in Oracle7 and Oracle8 */
EXEC ORACLE OPTION (char_map=charz);
/* Select retrieves a string "AB" from the database */
SQL SELECT ... INTO :ch_array FROM ... WHERE ... ;
/* ch_array == { 'A', 'B', ' ', ' ', '\0' } */
strncpy (ch_array, "12345", 5);
EXEC ORACLE OPTION (char_map=string) ;
/* Select retrieves a string "AB" from the database */
EXEC SQL SELECT ... INTO :ch_array FROM ... WHERE ... ;
/* ch_array == { 'A', 'B', '\0', '4', '5' } */
strcpy( ch_array, "12345", 5);
EXEC ORACLE OPTION (char_map=charf);
/* Select retrieves a string "AB" from the database */
EXEC SQL SELECT ... INTO :ch_array FROM ... WHERE ... ;
/* ch_array == { 'A', 'B', ' ', ' ', ' ' } */
strncpy(ch_array, "12345", 5);
/* char_map=charz is the default in Oracle7 and Oracle8 */
EXEC ORACLE OPTION (char_map=charz);
/* Select retrieves a string "AB" from the database */
SQL SELECT ... INTO :ch_array FROM ... WHERE ... ;
/* ch_array == { 'A', 'B', ' ', ' ', '\0' } */
strncpy (ch_array, "12345", 5);
EXEC ORACLE OPTION (char_map=string) ;
/* Select retrieves a string "AB" from the database */
EXEC SQL SELECT ... INTO :ch_array FROM ... WHERE ... ;
/* ch_array == { 'A', 'B', '\0', '4', '5' } */
strcpy( ch_array, "12345", 5);
EXEC ORACLE OPTION (char_map=charf);
/* Select retrieves a string "AB" from the database */
EXEC SQL SELECT ... INTO :ch_array FROM ... WHERE ... ;
/* ch_array == { 'A', 'B', ' ', ' ', ' ' } */
Passing VARCHAR Variables to a Function in Pro*C
VARCHAR emp_name[20];
...
emp_name.len = 20;
SELECT ename INTO :emp_name FROM emp
WHERE empno = 7499;
...
print_employee_name(&emp_name); /* pass by pointer */
...
print_employee_name(name)
VARCHAR *name;
{
...
printf("name is %.*s\n", name->len, name->arr);
...
}
...
emp_name.len = 20;
SELECT ename INTO :emp_name FROM emp
WHERE empno = 7499;
...
print_employee_name(&emp_name); /* pass by pointer */
...
print_employee_name(name)
VARCHAR *name;
{
...
printf("name is %.*s\n", name->len, name->arr);
...
}
Structure Pointers
struct EMP_REC
{
int emp_number;
float salary;
};
char *name = "HINAULT";
...
struct EMP_REC *sal_rec;
sal_rec = (struct EMP_REC *) malloc(sizeof (struct EMP_REC));
...
EXEC SQL SELECT empno, sal INTO :sal_rec
FROM emp
WHERE ename = :name;
printf("Employee number and salary for %s: ", name);
printf("%d, %g\n", sal_rec->emp_number, sal_rec->salary);
{
int emp_number;
float salary;
};
char *name = "HINAULT";
...
struct EMP_REC *sal_rec;
sal_rec = (struct EMP_REC *) malloc(sizeof (struct EMP_REC));
...
EXEC SQL SELECT empno, sal INTO :sal_rec
FROM emp
WHERE ename = :name;
printf("Employee number and salary for %s: ", name);
printf("%d, %g\n", sal_rec->emp_number, sal_rec->salary);
Pointer Variables in Pro*C
struct
{
int i;
char c;
} structvar;
int *i_ptr;
char *c_ptr;
...
main()
{
i_ptr = &structvar.i;
c_ptr = &structvar.c;
/* Use i_ptr and c_ptr in SQL statements. */
...
{
int i;
char c;
} structvar;
int *i_ptr;
char *c_ptr;
...
main()
{
i_ptr = &structvar.i;
c_ptr = &structvar.c;
/* Use i_ptr and c_ptr in SQL statements. */
...
Cursor and a Structure in Pro*C
http://www.cs.umbc.edu/help/oracle8.bak/server803/A54661_01/dev.htm#2416
/*
* sample2.pc
*
* This program connects to ORACLE, declares and opens a cursor,
* fetches the names, salaries, and commissions of all
* salespeople, displays the results, then closes the cursor.
*/
#include
#include
#define UNAME_LEN 20
#define PWD_LEN 40
/*
* Use the precompiler typedef'ing capability to create
* null-terminated strings for the authentication host
* variables. (This isn't really necessary--plain char *'s
* does work as well. This is just for illustration.)
*/
typedef char asciiz[PWD_LEN];
EXEC SQL TYPE asciiz IS STRING(PWD_LEN) REFERENCE;
asciiz username;
asciiz password;
struct emp_info
{
asciiz emp_name;
float salary;
float commission;
};
/* Declare function to handle unrecoverable errors. */
void sql_error();
main()
{
struct emp_info *emp_rec_ptr;
/* Allocate memory for emp_info struct. */
if ((emp_rec_ptr =
(struct emp_info *) malloc(sizeof(struct emp_info))) == 0)
{
fprintf(stderr, "Memory allocation error.\n");
exit(1);
}
/* Connect to ORACLE. */
strcpy(username, "SCOTT");
strcpy(password, "TIGER");
EXEC SQL WHENEVER SQLERROR DO sql_error("ORACLE error--");
EXEC SQL CONNECT :username IDENTIFIED BY :password;
printf("\nConnected to ORACLE as user: %s\n", username);
/* Declare the cursor. All static SQL explicit cursors
* contain SELECT commands. 'salespeople' is a SQL identifier,
* not a (C) host variable.
*/
EXEC SQL DECLARE salespeople CURSOR FOR
SELECT ENAME, SAL, COMM
FROM EMP
WHERE JOB LIKE 'SALES%';
/* Open the cursor. */
EXEC SQL OPEN salespeople;
/* Get ready to print results. */
printf("\n\nThe company's salespeople are--\n\n");
printf("Salesperson Salary Commission\n");
printf("----------- ------ ----------\n");
/* Loop, fetching all salesperson's statistics.
* Cause the program to break the loop when no more
* data can be retrieved on the cursor.
*/
EXEC SQL WHENEVER NOT FOUND DO break;
for (;;)
{
EXEC SQL FETCH salespeople INTO :emp_rec_ptr;
printf("%-11s%9.2f%13.2f\n", emp_rec_ptr->emp_name,
emp_rec_ptr->salary, emp_rec_ptr->commission);
}
/* Close the cursor. */
EXEC SQL CLOSE salespeople;
printf("\nArrivederci.\n\n");
EXEC SQL COMMIT WORK RELEASE;
exit(0);
}
void
sql_error(msg)
char *msg;
{
char err_msg[512];
int buf_len, msg_len;
EXEC SQL WHENEVER SQLERROR CONTINUE;
printf("\n%s\n", msg);
/* Call sqlglm() to get the complete text of the
* error message.
*/
buf_len = sizeof (err_msg);
sqlglm(err_msg, &buf_len, &msg_len);
printf("%.*s\n", msg_len, err_msg);
EXEC SQL ROLLBACK RELEASE;
exit(1);
}
/*
* sample2.pc
*
* This program connects to ORACLE, declares and opens a cursor,
* fetches the names, salaries, and commissions of all
* salespeople, displays the results, then closes the cursor.
*/
#include
#include
#define UNAME_LEN 20
#define PWD_LEN 40
/*
* Use the precompiler typedef'ing capability to create
* null-terminated strings for the authentication host
* variables. (This isn't really necessary--plain char *'s
* does work as well. This is just for illustration.)
*/
typedef char asciiz[PWD_LEN];
EXEC SQL TYPE asciiz IS STRING(PWD_LEN) REFERENCE;
asciiz username;
asciiz password;
struct emp_info
{
asciiz emp_name;
float salary;
float commission;
};
/* Declare function to handle unrecoverable errors. */
void sql_error();
main()
{
struct emp_info *emp_rec_ptr;
/* Allocate memory for emp_info struct. */
if ((emp_rec_ptr =
(struct emp_info *) malloc(sizeof(struct emp_info))) == 0)
{
fprintf(stderr, "Memory allocation error.\n");
exit(1);
}
/* Connect to ORACLE. */
strcpy(username, "SCOTT");
strcpy(password, "TIGER");
EXEC SQL WHENEVER SQLERROR DO sql_error("ORACLE error--");
EXEC SQL CONNECT :username IDENTIFIED BY :password;
printf("\nConnected to ORACLE as user: %s\n", username);
/* Declare the cursor. All static SQL explicit cursors
* contain SELECT commands. 'salespeople' is a SQL identifier,
* not a (C) host variable.
*/
EXEC SQL DECLARE salespeople CURSOR FOR
SELECT ENAME, SAL, COMM
FROM EMP
WHERE JOB LIKE 'SALES%';
/* Open the cursor. */
EXEC SQL OPEN salespeople;
/* Get ready to print results. */
printf("\n\nThe company's salespeople are--\n\n");
printf("Salesperson Salary Commission\n");
printf("----------- ------ ----------\n");
/* Loop, fetching all salesperson's statistics.
* Cause the program to break the loop when no more
* data can be retrieved on the cursor.
*/
EXEC SQL WHENEVER NOT FOUND DO break;
for (;;)
{
EXEC SQL FETCH salespeople INTO :emp_rec_ptr;
printf("%-11s%9.2f%13.2f\n", emp_rec_ptr->emp_name,
emp_rec_ptr->salary, emp_rec_ptr->commission);
}
/* Close the cursor. */
EXEC SQL CLOSE salespeople;
printf("\nArrivederci.\n\n");
EXEC SQL COMMIT WORK RELEASE;
exit(0);
}
void
sql_error(msg)
char *msg;
{
char err_msg[512];
int buf_len, msg_len;
EXEC SQL WHENEVER SQLERROR CONTINUE;
printf("\n%s\n", msg);
/* Call sqlglm() to get the complete text of the
* error message.
*/
buf_len = sizeof (err_msg);
sqlglm(err_msg, &buf_len, &msg_len);
printf("%.*s\n", msg_len, err_msg);
EXEC SQL ROLLBACK RELEASE;
exit(1);
}
Structures and Arrays in Pro*C
struct
{
char emp_name[3][10];
int emp_number[3];
int dept_number[3];
} emp_rec;
...
strcpy(emp_rec.emp_name[0], "ANQUETIL");
strcpy(emp_rec.emp_name[1], "MERCKX");
strcpy(emp_rec.emp_name[2], "HINAULT");
emp_rec.emp_number[0] = 1964; emp_rec.dept_number[0] = 5;
emp_rec.emp_number[1] = 1974; emp_rec.dept_number[1] = 5;
emp_rec.emp_number[2] = 1985; emp_rec.dept_number[2] = 5;
EXEC SQL INSERT INTO emp (ename, empno, deptno)
VALUES (:emp_rec);
{
char emp_name[3][10];
int emp_number[3];
int dept_number[3];
} emp_rec;
...
strcpy(emp_rec.emp_name[0], "ANQUETIL");
strcpy(emp_rec.emp_name[1], "MERCKX");
strcpy(emp_rec.emp_name[2], "HINAULT");
emp_rec.emp_number[0] = 1964; emp_rec.dept_number[0] = 5;
emp_rec.emp_number[1] = 1974; emp_rec.dept_number[1] = 5;
emp_rec.emp_number[2] = 1985; emp_rec.dept_number[2] = 5;
EXEC SQL INSERT INTO emp (ename, empno, deptno)
VALUES (:emp_rec);
Structures in Pro*C
typedef struct
{
char emp_name[11]; /* one greater than column length */
int emp_number;
int dept_number;
float salary;
} emp_record;
/* define a new structure of type "emp_record" */
emp_record new_employee;
strcpy(new_employee.emp_name, "CHEN");
new_employee.emp_number = 9876;
new_employee.dept_number = 20;
new_employee.salary = 4250.00;
EXEC SQL INSERT INTO emp (ename, empno, deptno, sal)
VALUES (:new_employee);
{
char emp_name[11]; /* one greater than column length */
int emp_number;
int dept_number;
float salary;
} emp_record;
/* define a new structure of type "emp_record" */
emp_record new_employee;
strcpy(new_employee.emp_name, "CHEN");
new_employee.emp_number = 9876;
new_employee.dept_number = 20;
new_employee.salary = 4250.00;
EXEC SQL INSERT INTO emp (ename, empno, deptno, sal)
VALUES (:new_employee);
Pro*C Examples
http://www.cs.umbc.edu/help/oracle8.bak/server803/A54661_01/dev.htm#1609
http://www.cs.umbc.edu/help/oracle8.bak/server803/A54661_01/toc.htm
Using C Structures
=================
#include
typedef emptype myemp;
myemp *employee;
ORA_PROC Macro
=================
the precompiler never reads the file.
The following example uses the ORA_PROC macro to exclude the irrelevant.h file:
#ifndef ORA_PROC
#include
#endif
OR
EXEC ORACLE IFNDEF ORA_PROC;
EXEC ORACLE ENDIF;
#define MAX(A,B) ((A) > (B) ? (A) : (B))
VARCHAR name_loc_temp[MAX(ENAME_LEN, LOCATION_LEN)];
You can use the #include, #ifdef and #endif preprocessor directives to conditionally include a file that the precompiler requires. For example:
#ifdef ORACLE_MODE
# include
#else
long SQLCODE;
#endif
TYPE and VAR statements
========================
#define STR_LEN 40
...
typedef char asciiz[STR_LEN];
...
EXEC SQL TYPE asciiz IS STRING(STR_LEN) REFERENCE;
...
EXEC SQL VAR password IS STRING(STR_LEN) REFERENCE;
UNIX systems, you can compile the generated C source file using the command
----------------------------------------------------------------------------------------------------------------------
cc -o progname -I$ORACLE_HOME/sqllib/public ... filename.c ...
switch
---------
ch = getchar();
switch (ch)
{
case 'U': update(); break;
case 'I': insert(); break;
...
Using Numeric Constants in Pro*C/C++
===================================
In Pro*C/C++, normal C scoping rules are used to find and locate the declaration of a numeric constant declaration.
const int g = 30; /* Global declaration to both function_1()
and function_2() */
void function_1()
{
const int a = 10; /* Local declaration only to function_1() */
char x[a];
exec sql select ename into :x from emp where job = 'PRESIDENT';
}
void function_2()
{
const int a = 20; /* Local declaration only to function_2() */
VARCHAR v[a];
exec sql select ename into :v from emp where job = 'PRESIDENT';
}
void main()
{
char m[g]; /* The global g */
exec sql select ename into :m from emp where job = 'PRESIDENT';
}
http://www.cs.umbc.edu/help/oracle8.bak/server803/A54661_01/toc.htm
Using C Structures
=================
#include
typedef emptype myemp;
myemp *employee;
ORA_PROC Macro
=================
the precompiler never reads the file.
The following example uses the ORA_PROC macro to exclude the irrelevant.h file:
#ifndef ORA_PROC
#include
#endif
OR
EXEC ORACLE IFNDEF ORA_PROC;
EXEC ORACLE ENDIF;
#define MAX(A,B) ((A) > (B) ? (A) : (B))
VARCHAR name_loc_temp[MAX(ENAME_LEN, LOCATION_LEN)];
You can use the #include, #ifdef and #endif preprocessor directives to conditionally include a file that the precompiler requires. For example:
#ifdef ORACLE_MODE
# include
#else
long SQLCODE;
#endif
TYPE and VAR statements
========================
#define STR_LEN 40
...
typedef char asciiz[STR_LEN];
...
EXEC SQL TYPE asciiz IS STRING(STR_LEN) REFERENCE;
...
EXEC SQL VAR password IS STRING(STR_LEN) REFERENCE;
UNIX systems, you can compile the generated C source file using the command
----------------------------------------------------------------------------------------------------------------------
cc -o progname -I$ORACLE_HOME/sqllib/public ... filename.c ...
switch
---------
ch = getchar();
switch (ch)
{
case 'U': update(); break;
case 'I': insert(); break;
...
Using Numeric Constants in Pro*C/C++
===================================
In Pro*C/C++, normal C scoping rules are used to find and locate the declaration of a numeric constant declaration.
const int g = 30; /* Global declaration to both function_1()
and function_2() */
void function_1()
{
const int a = 10; /* Local declaration only to function_1() */
char x[a];
exec sql select ename into :x from emp where job = 'PRESIDENT';
}
void function_2()
{
const int a = 20; /* Local declaration only to function_2() */
VARCHAR v[a];
exec sql select ename into :v from emp where job = 'PRESIDENT';
}
void main()
{
char m[g]; /* The global g */
exec sql select ename into :m from emp where job = 'PRESIDENT';
}
Defining an object type in Pro*C
--Defining an object type...
CREATE TYPE employee_type AS OBJECT(
name VARCHAR2(20),
id NUMBER,
MEMBER FUNCTION get_id(name VARCHAR2) RETURN NUMBER);
/
--Creating an object table...
CREATE TABLE employees OF employee_type;
--Instantiating an object, using a constructor...
INSERT INTO employees VALUES (
employee_type('JONES', 10042));
--LONG, LONG RAW, NCLOB, NCHAR and NCHAR Varying are not allowed as datatypes in attributes of
objects
REFs=====CREATE TYPE employee_t AS OBJECT(
empname CHAR(20),
empno INTEGER,
manager REF employee_t);
/
CREATE TABLE employee_tab OF employee_t;
Accessing Objects Using the Associative Interface============================================person *per_p;EXEC SQL ALLOCATE :per_p;EXEC SQL SELECT INTO :per_p FROM person_tab WHERE ...EXEC SQL INSERT INTO person_tab VALUES(:per_p);EXEC SQL FREE :per_p;
Using Objects in Pro*C/C++=========================Let us examine a simple object example. You create a type person and a table person_tab, which has a column
that is also an object, address:
create type person as object (
lastname varchar2(20),
firstname char(20),
age int,
addr address
)
/
create table person_tab of person;
Associative Access================char *new_name = "Smythe";
person *person_p
...
EXEC SQL ALLOCATE :person_p;
EXEC SQL SELECT INTO :person_p FROM person_tab WHERE lastname = 'Smith';
EXEC SQL OBJECT SET lastname OF :person_p TO :new_name;
EXEC SQL INSERT INTO person_tab VALUES(:person_p);
EXEC SQL FREE :person_p;
Navigational Access===================
person *person_p;
person_ref *per_ref_p;
...
EXEC SQL ALLOCATE :per_ref_p;
EXEC SQL SELECT ... INTO :per_ref_p;
EXEC SQL OBJECT DEREF :per_ref_p INTO :person_p;
/* lname is a C variable to hold the result */
EXEC SQL OBJECT GET lastname FROM :person_p INTO :lname;
...
EXEC SQL OBJECT SET lastname OF :person_p TO :new_name;
/* Mark the changed object as changed with OBJECT UPDATE command */;
EXEC SQL OBJECT UPDATE :person_p;
EXEC SQL FREE :per_ref_p;To make the changes permanent in the database:
EXEC SQL OBJECT FLUSH :person_p;
EXEC SQL OBJECT RELEASE :person_p;
CREATE TYPE employee_type AS OBJECT(
name VARCHAR2(20),
id NUMBER,
MEMBER FUNCTION get_id(name VARCHAR2) RETURN NUMBER);
/
--Creating an object table...
CREATE TABLE employees OF employee_type;
--Instantiating an object, using a constructor...
INSERT INTO employees VALUES (
employee_type('JONES', 10042));
--LONG, LONG RAW, NCLOB, NCHAR and NCHAR Varying are not allowed as datatypes in attributes of
objects
REFs=====CREATE TYPE employee_t AS OBJECT(
empname CHAR(20),
empno INTEGER,
manager REF employee_t);
/
CREATE TABLE employee_tab OF employee_t;
Accessing Objects Using the Associative Interface============================================person *per_p;EXEC SQL ALLOCATE :per_p;EXEC SQL SELECT INTO :per_p FROM person_tab WHERE ...EXEC SQL INSERT INTO person_tab VALUES(:per_p);EXEC SQL FREE :per_p;
Using Objects in Pro*C/C++=========================Let us examine a simple object example. You create a type person and a table person_tab, which has a column
that is also an object, address:
create type person as object (
lastname varchar2(20),
firstname char(20),
age int,
addr address
)
/
create table person_tab of person;
Associative Access================char *new_name = "Smythe";
person *person_p
...
EXEC SQL ALLOCATE :person_p;
EXEC SQL SELECT INTO :person_p FROM person_tab WHERE lastname = 'Smith';
EXEC SQL OBJECT SET lastname OF :person_p TO :new_name;
EXEC SQL INSERT INTO person_tab VALUES(:person_p);
EXEC SQL FREE :person_p;
Navigational Access===================
person *person_p;
person_ref *per_ref_p;
...
EXEC SQL ALLOCATE :per_ref_p;
EXEC SQL SELECT ... INTO :per_ref_p;
EXEC SQL OBJECT DEREF :per_ref_p INTO :person_p;
/* lname is a C variable to hold the result */
EXEC SQL OBJECT GET lastname FROM :person_p INTO :lname;
...
EXEC SQL OBJECT SET lastname OF :person_p TO :new_name;
/* Mark the changed object as changed with OBJECT UPDATE command */;
EXEC SQL OBJECT UPDATE :person_p;
EXEC SQL FREE :per_ref_p;To make the changes permanent in the database:
EXEC SQL OBJECT FLUSH :person_p;
EXEC SQL OBJECT RELEASE :person_p;
Subscribe to:
Posts
(
Atom
)