diff --git a/ADDRESS.java b/ADDRESS.java new file mode 100644 index 0000000..a11d50c --- /dev/null +++ b/ADDRESS.java @@ -0,0 +1,94 @@ +/* $Header: ADDRESS.java 15-mar-00.09:06:06 rbhyrava Exp $ */ + +/* Copyright (c) Oracle Corporation 2000. All Rights Reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + rbhyrava 03/15/00 - AQ API demo -Jpub generated class for ADDRESS Type + rbhyrava 03/15/00 - Creation + */ + +/** + * @version $Header: ADDRESS.java 15-mar-00.09:06:06 rbhyrava Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ + +/**** + * Jpub generated class for for ADDRESS object type + * Used in aqorademo02.java + ***/ +import java.sql.SQLException; +import java.sql.Connection; +import oracle.jdbc.OracleTypes; +import oracle.sql.ORAData; +import oracle.sql.ORADataFactory; +import oracle.sql.Datum; +import oracle.sql.STRUCT; +import oracle.jpub.runtime.MutableStruct; + +public class ADDRESS implements ORAData, ORADataFactory +{ + public static final String _SQL_NAME = "AQJAVA.ADDRESS"; + public static final int _SQL_TYPECODE = OracleTypes.STRUCT; + + protected MutableStruct _struct; + + private static int[] _sqlType = { 12,12 }; + private static ORADataFactory[] _factory = new ORADataFactory[2]; +protected static final ADDRESS _ADDRESSFactory = new ADDRESS(false); + + public static ORADataFactory getORADataFactory() + { return _ADDRESSFactory; } + /* constructor */ + protected ADDRESS(boolean init) + { if(init) _struct = new MutableStruct(new Object[2], _sqlType, _factory); } + public ADDRESS() + { this(true); } + public ADDRESS(String street, String city) throws SQLException + { this(true); + setStreet(street); + setCity(city); + } + + /* ORAData interface */ + public Datum toDatum(Connection c) throws SQLException + { + return _struct.toDatum(c, _SQL_NAME); + } + + + /* ORADataFactory interface */ + public ORAData create(Datum d, int sqlType) throws SQLException + { return create(null, d, sqlType); } + protected ORAData create(ADDRESS o, Datum d, int sqlType) throws SQLException + { + if (d == null) return null; + if (o == null) o = new ADDRESS(false); + o._struct = new MutableStruct((STRUCT) d, _sqlType, _factory); + return o; + } + /* accessor methods */ + public String getStreet() throws SQLException + { return (String) _struct.getAttribute(0); } + + public void setStreet(String street) throws SQLException + { _struct.setAttribute(0, street); } + + + public String getCity() throws SQLException + { return (String) _struct.getAttribute(1); } + + public void setCity(String city) throws SQLException + { _struct.setAttribute(1, city); } + +} diff --git a/AQDemoServlet.java b/AQDemoServlet.java new file mode 100644 index 0000000..de72b35 --- /dev/null +++ b/AQDemoServlet.java @@ -0,0 +1,127 @@ +/* $Header: AQDemoServlet.java 27-oct-2004.17:29:35 rbhyrava Exp $ */ + +/* Copyright (c) 2001, 2004, Oracle. All rights reserved. */ + +/* + DESCRIPTION + AQ Demo Servlet for OC4J configuration + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + rbhyrava 10/27/04 - enable tracing ; oc4j support + rbhyrava 09/13/04 - Pass host,port,sid as arguments + rbhyrava 03/11/02 - fix typo + rbhyrava 02/20/02 - set host/port etc + rbhyrava 04/12/01 - Merged rbhyrava_aqxmldemos + rbhyrava 04/02/01 - Creation + */ + +/** + * @version $Header: AQDemoServlet.java 27-oct-2004.17:29:35 rbhyrava Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ + +import java.io.*; +import javax.servlet.*; +import javax.servlet.http.*; +import oracle.AQ.*; +import oracle.AQ.xml.*; +import java.sql.*; +import oracle.jms.*; +import javax.jms.*; +import java.io.*; +import oracle.jdbc.pool.*; + +/** + * This is a sample AQ Servlet for OC4J webserver configuration. + */ +public class AQDemoServlet extends oracle.AQ.xml.AQxmlServlet +{ + + public FileOutputStream ostream = null; + //======================================================================== + /* + * getDBDrv - specify the database to which the servlet will connect + */ + + public AQxmlDataSource createAQDataSource() throws AQxmlException + { + + //String sid = "aq2"; + //String port = "1521"; + //String host = "stacj31"; + + AQxmlDataSource db_drv = null; + String sid = System.getProperty("MYDB_SID"); + String port = System.getProperty("MYDB_PORT"); + String host = System.getProperty("MYDB_HOST"); + + System.out.println("AQDemoServlet - setting db driver using"); + System.out.println("sid:" + sid + " port:" + port + " host:" + host ) ; + + db_drv = new AQxmlDataSource("scott", "tiger", sid, host, port); + System.out.print("sid: "+ db_drv.getSid() ) ; + System.out.print(" host: "+ db_drv.getHost() ) ; + System.out.print(" port: "+ db_drv.getPort() ) ; + System.out.print(" cachesize: "+ db_drv.getCacheSize() ) ; + System.out.println(" cachescheme: "+ db_drv.getCacheScheme() ) ; + + return db_drv; + } + + //======================================================================== + public void init(ServletConfig cfg) + { + AQxmlDataSource db_drv = null; + + try + { + super.init(cfg); + + // Remove the comment below to enable tracing + /* + ostream = new FileOutputStream(fname) ; + AQxmlDebug.setTraceLevel(5); + AQxmlDebug.setDebug(true); + + //to write debug output to a file + String fname = "/tmp/wsdemoservletdebug.log" ; + File f = new File(fname) ; + AQxmlDebug.setLogStream(ostream); + + // or to write debug output to standard err + AQxmlDebug.setLogStream(System.err); + */ + + /* + AQjmsOracleDebug.setLogStream(System.err); + AQjmsOracleDebug.setTraceLevel(5); + AQjmsOracleDebug.setDebug(true); + */ + + db_drv = this.createAQDataSource(); + setAQDataSource(db_drv); + + setManualInvalidation(false); + setSessionMaxInactiveTime(30); + } + catch (AQxmlException aq_ex) + { + System.out.println("AQ exception: " + aq_ex); + aq_ex.printStackTrace(); + + aq_ex.getNextException().printStackTrace(); + } + catch (Exception ex) + { + System.out.println("Exception: " + ex); + ex.printStackTrace(); + } + } +} diff --git a/AQHttp.java b/AQHttp.java new file mode 100644 index 0000000..5040f28 --- /dev/null +++ b/AQHttp.java @@ -0,0 +1,275 @@ +/* $Header: AQHttp.java 02-nov-2004.13:47:08 rbhyrava Exp $ */ + +/* Copyright (c) 2001, 2004, Oracle. All rights reserved. */ + +/* + DESCRIPTION + AQxml HTTP/HTTPS POST an AQ XML Request using HTTP Client + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + rbhyrava 11/02/04 - demossl + lzhao 08/28/01 - merge rbhyrava's changes-setContentType + rbhyrava 07/23/01 - use s_oracleHome as per bug1895434 + rbhyrava 07/20/01 - + rbhyrava 07/20/01 - https + rbhyrava 04/12/01 - Merged rbhyrava_aqxmldemos + rbhyrava 04/09/01 - Creation + */ + +/** + * @version $Header: AQHttp.java 02-nov-2004.13:47:08 rbhyrava Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ + +/* Helper class to Post AQ XML request */ +import HTTPClient.*; +import java.util.*; +import java.io.*; +import java.lang.reflect.*; + +public abstract class AQHttp { + private String server_name; // server name + private int port_number; // port number + private String protocol_type ; + private String fs = File.separator ; + private String demossl_crt_file = System.getProperty("CERT"); + private HTTPConnection con = null; // HTTP connection + private String userPass = null; + + + String oc4jcert = +"MIIB0jCCATsCBEAIDP0wDQYJKoZIhvcNAQEEBQAwMDELMAkGA1UEBhMCVVMxDzANBgNVBAoTBk9y"+ +"YWNsZTEQMA4GA1UEAxMHc29tZW9uZTAeFw0wNDAxMTYxNjEwMzdaFw0xNDAxMTMxNjEwMzdaMDAx"+ +"CzAJBgNVBAYTAlVTMQ8wDQYDVQQKEwZPcmFjbGUxEDAOBgNVBAMTB3NvbWVvbmUwgZ8wDQYJKoZI"+ +"hvcNAQEBBQADgY0AMIGJAoGBAMfTBEKasCvuWVLQZocEACMt7S03j64NBCAGBG8XAKq5gbAOAyat"+ +"fOnoV/fSeNVgBv7XuNmtysOCBCGCrNnrdGdup8CjTkfrHxFrq5cWjfLZammrFjlebIY6BPkTX4I4"+ +"zBkEyCjyFpTh1y/SzRzdsiGSPIIML2OuCpLsZCet1i67AgMBAAEwDQYJKoZIhvcNAQEEBQADgYEA"+ +"MUQy8siUiFhXJ7q7W3HThQ0pi3jO+ryJz/TjfH+RCjPPwh2Ipq5oMDoXsoBoUzc7oiYj8GM+angE"+ +"0XSkLLayqidmcXYCki92D4Wqemx90bhxVvCz6wUyG4yPm9VhKBwqiwKrw3np8RtDjD5HFEvk2Icb"+ +"3OoWB2Z/MxN0Upl/Ki4="; + + + + public AQHttp() {} + public void setProtocolType(String prot) { + try { + protocol_type = prot.toLowerCase() ; + + } catch (Exception e) { + e.printStackTrace(); + System.out.println("setProtocolType:" + e); + } + } + public void setServerPort(String sname, String pnumber ) { + try { + server_name = sname ; + port_number = Integer.parseInt(pnumber); + + } catch (Exception e) { + e.printStackTrace(); + System.out.println("setServerPort:" + e); + } + } + + // make connection + public void connect(String username, String password) { + if (con != null) con = null; + userPass = username + ":" + password ; + con = newConnection(username, password); + } + // close connection + public void close() { + try { + if (con != null) + con.stop() ; + } catch (Exception e ) { + System.out.println("Close Connection : "+ e) ; + } + } + + // This method returns a new instance of HTTPConnection + public HTTPConnection newConnection(String username, String password) { + HTTPConnection returnValue = null; + + try { + returnValue = + new HTTPConnection(protocol_type, server_name, port_number); + returnValue.addBasicAuthorization("aqxmldemo_web", username, password); + if ( protocol_type.compareTo("https") == 0) { + //cert=readFile(demossl_crt_file) ; + //System.out.println(cert) ; + returnValue.addTrustPoint(oc4jcert); + } + + NVPair[] hdrs = returnValue.getDefaultHeaders() ; + int idx =0; + for (idx=0; idx< hdrs.length ; idx++) { + System.out.println(hdrs[idx].getName()); + if (hdrs[idx].getName().equalsIgnoreCase("content-type")) { + hdrs[idx] = new NVPair("Content-Type", "text/xml") ; + } + } + if (hdrs.length == 0) { + hdrs = new NVPair[1]; + hdrs[0] = new NVPair("Content-Type", "text/xml") ; + } + returnValue.setDefaultHeaders(hdrs) ; + + } catch (Exception e) { + e.printStackTrace(); + System.out.println("Fail to connect to " + server_name + ":" + port_number); + } + return returnValue; + } + + // get response from webserver + public int getStatusCode(String urlPath) { + int code = 0; + try { + HTTPResponse resp = con.Get(urlPath); + code = resp.getStatusCode(); + } catch (Exception e) { + e.printStackTrace(); + System.out.println("Fail to get the status code"); + } + return code; + } + + public String getStringResponse(String urlPath) { + String str = null; + try { + HTTPResponse resp = con.Get(urlPath); + str = new String(resp.getData()); + } catch (Exception e) { + e.printStackTrace(); + System.out.println("Fail to get a String response "); + } + return str; + } + + public String postStringResponse(String urlPath, String[] xmlfiles) { + String str = ""; + String data = null; + String cookie = null; + String ret_cookie = null; + try { + for ( int i =0 ; i < xmlfiles.length ; i++) { + + if (cookie != null ) { + AuthorizationInfo au1 = AuthorizationInfo.getAuthorization( + server_name, port_number, "Basic", "aqxmldemo_web") ; + au1.setCookie(cookie) ; + } + if (xmlfiles[i] != null ) + { + data = readFile(xmlfiles[i]) ; + HTTPResponse resp = con.Post(urlPath, data.getBytes(), null); + if (i == 0) { + str = str +"URL: " +protocol_type +"://" + server_name + ":"+ + port_number+ urlPath + "\n"; + } else { + str = str + "\n" ; + } + str = str + "Setting User:: " + userPass + "\n"; + str = str + "Setting Encoded:: " + resp.getHeader("Content-Encoding") + "\n"; + if ( i != 0 ) { + str = str + "Setting cookie " + cookie + "\n"; + } + + str = str + "POSTing file: " + xmlfiles[i] + "\n"; + AuthorizationInfo au = AuthorizationInfo.getAuthorization(server_name, port_number, "Basic", "aqxmldemo_web") ; + ret_cookie = au.getCookie() ; + if (ret_cookie != null) { + cookie = ret_cookie ; + } + str = str + "Cookie " + cookie + "\n"; + str = str + "HTTP response code is " + resp.getStatusCode() + "\n"; + String con_len = resp.getHeader("Content-Length") ; + str = str+"HTTP Content Length: "+ ((con_len != null) ? con_len : "-1" ) +"\n"; + str = str+"HTTP Content Type: " + resp.getHeader("Content-Type") + "\n"; + str = str + "HTTP Content: " + "\n"; + String respdata = new String(resp.getData()) ; + str = str + respdata ; + + } + } + } catch (Exception e) { + e.printStackTrace(); + System.out.println("Fail to POST a String response "); + } + return str; + } + + /** + * This class defines a CookiePolicyHandler that + * accepts and sends all cookie without dicretion. + *@see setCookieAcceptance + */ + protected class MaxPolicyHandler implements HTTPClient.CookiePolicyHandler { + public boolean acceptCookie(Cookie cookie, RoRequest req, RoResponse resp) + { return true; } + + public boolean sendCookie(Cookie cookie, RoRequest req) + { return true; } + } + + /** + * This class defines a CookiePolicyHandler that + * rejects all cookie without dicretion. + *@see setCookieAcceptance + */ + protected class MinPolicyHandler implements HTTPClient.CookiePolicyHandler { + public boolean acceptCookie(Cookie cookie, RoRequest req, RoResponse resp) + { return false; } + + public boolean sendCookie(Cookie cookie, RoRequest req) + { return false; } + } + + protected void setCookieAcceptance(boolean accept) { + setCookieAcceptance(con, accept); + } + + protected void setCookieAcceptance(HTTPConnection con, boolean accept) { + try { + Class []c = con.getModules(); + int i; + for (i=0; i < c.length; i++) { + //System.out.println("module "+ i +" : " + c[i]); + if (c[i].equals(CookieModule.class)) break; + } + Method m = c[i].getMethod("setCookiePolicyHandler", new Class[] {CookiePolicyHandler.class}); + if (accept) + m.invoke(null, new Object[] {new MaxPolicyHandler()}); + else + m.invoke(null, new Object[] {new MinPolicyHandler()}); + } catch (Exception e) { + e.printStackTrace(); + System.out.println("Exception thrown in setCookieAcceptance"); + } + } + + public static String readFile(String fname) throws Exception + { + FileReader fReader; + BufferedReader bReader; + String line= null; + StringBuffer data; + + fReader = new FileReader(fname); + bReader = new BufferedReader(fReader); + data = new StringBuffer(); + while ((line = bReader.readLine()) != null) + { + data.append(line + "\n"); + } + return data.toString(); + } +} diff --git a/AQHttpRq.java b/AQHttpRq.java new file mode 100644 index 0000000..2c581fd --- /dev/null +++ b/AQHttpRq.java @@ -0,0 +1,102 @@ +/* $Header: AQHttpRq.java 20-jul-2001.16:50:36 rbhyrava Exp $ */ + +/* Copyright (c) 2001, Oracle Corporation. All rights reserved. */ + +/* + DESCRIPTION + + AQXml-HTTP/HTTPS POST an AQ XML Request using HTTP Client + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + rbhyrava 07/20/01 - + rbhyrava 07/20/01 - Protocol + rbhyrava 04/12/01 - Merged rbhyrava_aqxmldemos + rbhyrava 04/04/01 - Creation + */ + +/** + * @version $Header: AQHttpRq.java 20-jul-2001.16:50:36 rbhyrava Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ + +//Post an AQ XML Request +public class AQHttpRq extends AQHttp { + + static String URL = null; + static String[] xmlfiles = new String[3]; + static String username = null; + static String password = null; + static String server = null; + static String method = null; + static String port_number = null; + static String protocol = null; + + public static void main(String args[]) + { + try + { + if(args.length < 6) + { + System.out.println ("Not enough parameters. " + + "Usage: java AQHttpRq [SERVER] [PORT] [GET/POST] [PROTOCOL] [URL] [USERNAME] [PASSWORD] [XMLFILE1] [XMLFILE2] ..\n"); + + return; + } + server = args[0] ; + port_number = args[1] ; + method = args[2] ; + protocol = args[3]; + URL = args[4] ; + username = args[5] ; + password = args[6] ; + + if (method.equals("POST") ) { + xmlfiles = new String [args.length -7] ; + for ( int i= 7 ; i < args.length ; i++) { + xmlfiles[i -7 ] = args[i] ; + } + if (xmlfiles.length == 0) { + System.out.println("Error:XMLFiles should be specified for POST"); + } + } + System.out.println("server: " + server ) ; + System.out.println("port : " + port_number ) ; + System.out.println("method " + method ) ; + System.out.println("protocol " + protocol ) ; + System.out.println("URL " + URL ) ; + System.out.println("username " + username ) ; + System.out.println("password " + password ) ; + for ( int i= 0 ; i < xmlfiles.length ; i++) { + System.out.println("xmlfiles " + xmlfiles[i] ) ; + } + new AQHttpRq().performAction() ; + } + catch (Exception ex) + { + System.out.println("MAIN : " + ex); + } + finally {} + + } + + public void performAction() { + setProtocolType(protocol) ; + setServerPort(server, port_number) ; + connect(username, password); + setCookieAcceptance(true); + if (method.equals("POST")) { + System.out.println(postStringResponse(URL, xmlfiles)); + } else { + System.out.println(getStringResponse(URL)) ; + close() ; + } + } +} diff --git a/AQPropServlet.java b/AQPropServlet.java new file mode 100644 index 0000000..9dfc181 --- /dev/null +++ b/AQPropServlet.java @@ -0,0 +1,100 @@ +/* $Header: AQPropServlet.java 27-oct-2004.17:30:12 rbhyrava Exp $ */ + +/* Copyright (c) 2001, 2004, Oracle. All rights reserved. */ + +/* + DESCRIPTION + AQ propagation using http/https. + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + rbhyrava 10/27/04 - oc4j support;enable tracing + rbhyrava 10/26/04 - DBPort + rbhyrava 09/13/04 - Pass host,port,sid as arguments + rbhyrava 02/20/02 - set host,port,sid + rbhyrava 05/09/01 - Init for Jserv + rbhyrava 04/12/01 - Merged rbhyrava_aqxmldemos + rbhyrava 04/10/01 - comments + rbhyrava 03/30/01 - Creation + */ + +/** + * @version $Header: AQPropServlet.java 27-oct-2004.17:30:12 rbhyrava Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ + +/* + AQ Propagation Servlet +*/ +import java.io.*; +import javax.servlet.*; +import javax.servlet.http.*; +import oracle.AQ.*; +import oracle.AQ.xml.*; +import java.sql.*; +import oracle.jms.*; +import javax.jms.*; +import java.io.*; +import oracle.jdbc.pool.*; + +/** + * This is a AQ Propagation Servlet. + */ +public class AQPropServlet extends oracle.AQ.xml.AQxmlServlet +{ + + /*====================================================================* + * getDBDrv - specify the database to which the servlet will connect * + *====================================================================*/ + public AQxmlDataSource createAQDataSource() throws AQxmlException + { + AQxmlDataSource db_drv = null; + + //String sid = "%s_oracleSid%"; + //String port = "1521"; + //String host = "%s_oracleHost%"; + + String sid = System.getProperty("MYDB_SID"); + String port = System.getProperty("MYDB_PORT"); + String host = System.getProperty("MYDB_HOST"); + + System.err.println("AQPropServlet - setting db driver using"); + System.err.println("sid:" + sid + " port:" + port + " host:" + host ) ; + + System.err.println("AQPropServlet - setting db driver"); + db_drv = new AQxmlDataSource("scott", "tiger", sid, host, port); + System.err.print("sid: "+ db_drv.getSid() ) ; + System.err.print(" host: "+ db_drv.getHost() ) ; + System.err.print(" port: "+ db_drv.getPort() ) ; + System.err.print(" cachesize: "+ db_drv.getCacheSize() ) ; + System.err.println(" cachescheme: "+ db_drv.getCacheScheme() ) ; + return db_drv; + } + + public void init(ServletConfig cfg) + { + try + { + super.init(cfg) ; + + AQxmlDebug.setTraceLevel(5); + AQxmlDebug.setDebug(true); + AQxmlDebug.setLogStream(System.err); + + AQxmlDataSource dt_src = this.createAQDataSource(); + setAQDataSource(dt_src); + setSessionMaxInactiveTime(180) ; + } + catch (Exception ex) + { + System.err.println("Exception in init: " + ex); + } + } +} + diff --git a/Cars.java b/Cars.java new file mode 100644 index 0000000..21c92fd --- /dev/null +++ b/Cars.java @@ -0,0 +1,119 @@ +/* $Header: Cars.java 01-mar-2002.14:56:41 rbhyrava Exp $ */ + +/* Copyright (c) 2000, 2002, Oracle Corporation. All rights reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + rbhyrava 03/01/02 - + rbhyrava 03/15/00 - AQ jms demo -Jpub generated class for CARS Type + rbhyrava 03/15/00 - Creation + */ + +/** + * @version $Header: Cars.java 01-mar-2002.14:56:41 rbhyrava Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ + +/**** + * Jpub generated class for for CARS object type + * Used in aqjmsdemo05.java, aqjmsdemo06.java + ***/ +import java.sql.SQLException; +import java.sql.Connection; +import oracle.jdbc.OracleTypes; +import oracle.sql.ORAData; +import oracle.sql.ORADataFactory; +import oracle.sql.Datum; +import oracle.sql.STRUCT; +import oracle.jpub.runtime.MutableStruct; + +public class Cars implements ORAData, ORADataFactory +{ + public static final String _SQL_NAME = "JMSUSER.CARS"; + public static final int _SQL_TYPECODE = OracleTypes.STRUCT; + + protected MutableStruct _struct; + + private static int[] _sqlType = { 2,12,2,2,12 }; + private static ORADataFactory[] _factory = new ORADataFactory[5]; +protected static final Cars _CarsFactory = new Cars(false); + + public static ORADataFactory getORADataFactory() + { return _CarsFactory; } + /* constructor */ + protected Cars(boolean init) + { if(init) _struct = new MutableStruct(new Object[5], _sqlType, _factory); } + public Cars() + { this(true); } + public Cars(java.math.BigDecimal carno, String make, java.math.BigDecimal year, java.math.BigDecimal price, String color) throws SQLException + { this(true); + setCarno(carno); + setMake(make); + setYear(year); + setPrice(price); + setColor(color); + } + + /* ORAData interface */ + public Datum toDatum(Connection c) throws SQLException + { + return _struct.toDatum(c, _SQL_NAME); + } + + + /* ORADataFactory interface */ + public ORAData create(Datum d, int sqlType) throws SQLException + { return create(null, d, sqlType); } + protected ORAData create(Cars o, Datum d, int sqlType) throws SQLException + { + if (d == null) return null; + if (o == null) o = new Cars(false); + o._struct = new MutableStruct((STRUCT) d, _sqlType, _factory); + return o; + } + /* accessor methods */ + public java.math.BigDecimal getCarno() throws SQLException + { return (java.math.BigDecimal) _struct.getAttribute(0); } + + public void setCarno(java.math.BigDecimal carno) throws SQLException + { _struct.setAttribute(0, carno); } + + + public String getMake() throws SQLException + { return (String) _struct.getAttribute(1); } + + public void setMake(String make) throws SQLException + { _struct.setAttribute(1, make); } + + + public java.math.BigDecimal getYear() throws SQLException + { return (java.math.BigDecimal) _struct.getAttribute(2); } + + public void setYear(java.math.BigDecimal year) throws SQLException + { _struct.setAttribute(2, year); } + + + public java.math.BigDecimal getPrice() throws SQLException + { return (java.math.BigDecimal) _struct.getAttribute(3); } + + public void setPrice(java.math.BigDecimal price) throws SQLException + { _struct.setAttribute(3, price); } + + + public String getColor() throws SQLException + { return (String) _struct.getAttribute(4); } + + public void setColor(String color) throws SQLException + { _struct.setAttribute(4, color); } + +} diff --git a/Emp.java b/Emp.java new file mode 100644 index 0000000..629bc75 --- /dev/null +++ b/Emp.java @@ -0,0 +1,122 @@ +/* $Header: Emp.java 15-mar-00.09:08:33 rbhyrava Exp $ */ + +/* Copyright (c) Oracle Corporation 2000. All Rights Reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + rbhyrava 03/15/00 - AQ jms demo -Jpub generated class for Emp Type + rbhyrava 03/15/00 - Creation + */ + +/** + * @version $Header: Emp.java 15-mar-00.09:08:33 rbhyrava Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ + +/**** + * Jpub generated class for for EMP object type + * Used in aqjmsdemo05.java + ***/ +import java.sql.SQLException; +import java.sql.Connection; +import oracle.jdbc.OracleTypes; +import oracle.sql.ORAData; +import oracle.sql.ORADataFactory; +import oracle.sql.Datum; +import oracle.sql.STRUCT; +import oracle.jpub.runtime.MutableStruct; + +public class Emp implements ORAData, ORADataFactory +{ + public static final String _SQL_NAME = "JMSUSER.EMP"; + public static final int _SQL_TYPECODE = OracleTypes.STRUCT; + + protected MutableStruct _struct; + + private static int[] _sqlType = { 2,12,2002,2,12 }; + private static ORADataFactory[] _factory = new ORADataFactory[5]; + static + { + _factory[2] = Cars.getORADataFactory(); + } +protected static final Emp _EmpFactory = new Emp(false); + + public static ORADataFactory getORADataFactory() + { return _EmpFactory; } + /* constructor */ + protected Emp(boolean init) + { if(init) _struct = new MutableStruct(new Object[5], _sqlType, _factory); } + public Emp() + { this(true); } + public Emp(java.math.BigDecimal id, String name, Cars carown, java.math.BigDecimal rank, String zip) throws SQLException + { this(true); + setId(id); + setName(name); + setCarown(carown); + setRank(rank); + setZip(zip); + } + + /* ORAData interface */ + public Datum toDatum(Connection c) throws SQLException + { + return _struct.toDatum(c, _SQL_NAME); + } + + + /* ORADataFactory interface */ + public ORAData create(Datum d, int sqlType) throws SQLException + { return create(null, d, sqlType); } + protected ORAData create(Emp o, Datum d, int sqlType) throws SQLException + { + if (d == null) return null; + if (o == null) o = new Emp(false); + o._struct = new MutableStruct((STRUCT) d, _sqlType, _factory); + return o; + } + /* accessor methods */ + public java.math.BigDecimal getId() throws SQLException + { return (java.math.BigDecimal) _struct.getAttribute(0); } + + public void setId(java.math.BigDecimal id) throws SQLException + { _struct.setAttribute(0, id); } + + + public String getName() throws SQLException + { return (String) _struct.getAttribute(1); } + + public void setName(String name) throws SQLException + { _struct.setAttribute(1, name); } + + + public Cars getCarown() throws SQLException + { return (Cars) _struct.getAttribute(2); } + + public void setCarown(Cars carown) throws SQLException + { _struct.setAttribute(2, carown); } + + + public java.math.BigDecimal getRank() throws SQLException + { return (java.math.BigDecimal) _struct.getAttribute(3); } + + public void setRank(java.math.BigDecimal rank) throws SQLException + { _struct.setAttribute(3, rank); } + + + public String getZip() throws SQLException + { return (String) _struct.getAttribute(4); } + + public void setZip(String zip) throws SQLException + { _struct.setAttribute(4, zip); } + +} diff --git a/MesgListener.java b/MesgListener.java new file mode 100644 index 0000000..172dbbb --- /dev/null +++ b/MesgListener.java @@ -0,0 +1,68 @@ +/* $Header: MesgListener.java 16-mar-00.13:11:30 rbhyrava Exp $ */ + +/* Copyright (c) Oracle Corporation 2000. All Rights Reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + rbhyrava 03/15/00 - AQ jms demo -Message Listener + rbhyrava 03/15/00 - Creation + */ + +/** + * @version $Header: MesgListener.java 16-mar-00.13:11:30 rbhyrava Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ +/* + * Message Listener to listen messages asynchronously. + * Setup Message Listener for a Queue Receiver to receive the messages + * Refer to aqjmsdemo03.java + */ +import oracle.AQ.*; +import oracle.jms.*; +import javax.jms.*; +import java.lang.*; +import java.math.*; +import java.util.*; + +public class MesgListener implements MessageListener +{ + int mesgno=0; + + Session mysess; + String myname; + + MesgListener(Session sess) { + mysess = sess; + } + public void onMessage(javax.jms.Message m) + { + MapMessage mm = (MapMessage) m ; + try { + mesgno++; + System.out.println("Retrieved message " + + mesgno + " with correlation: " + mm.getJMSCorrelationID()); + System.out.println (" "+ mm.getStringProperty ("color") + + " " + mm.getStringProperty("make") + + " " + mm.getIntProperty("year") + + " " + mm.getDoubleProperty("price")) ; + try { + mysess.commit() ; + } catch (Exception e) { + System.out.println("Exception on Message Listener Commit " + e) ; + } + + } catch (JMSException e) { + System.out.println("Exception onMessage:" + e) ; + } + } +} diff --git a/Message.java b/Message.java new file mode 100644 index 0000000..f27ce95 --- /dev/null +++ b/Message.java @@ -0,0 +1,95 @@ +/* $Header: Message.java 15-mar-00.09:10:14 rbhyrava Exp $ */ + +/* Copyright (c) Oracle Corporation 2000. All Rights Reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + rbhyrava 03/15/00 - AQ jms demo -Message Object Type + rbhyrava 03/15/00 - Creation + */ + +/** + * @version $Header: Message.java 15-mar-00.09:10:14 rbhyrava Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ + +/* +** Definition of Serial Object for Object Message tests +** simple object definition, extends serializable +** Refer to aqjmsdemo01.java +*/ +import java.io.*; +import oracle.AQ.*; +import oracle.jms.*; +import javax.jms.*; +import java.lang.*; +import java.math.*; +import java.util.*; + +class Message implements Serializable +{ + String name; + int id; + int num_entries; + int[] data_points; + + Message() + { + name = null; + id = -99; + num_entries = 0; + data_points = null; + } + + public String getName() + { + return name; + } + + public int getId() + { + return id; + } + + public int getNumEntries() + { + return num_entries; + } + + public int[] getData() + { + return data_points; + } + + public void setName(String nam) + { + name = nam; + } + + public void setId(int ID) + { + id = ID; + } + + public void setData(int n) + { + int i = 0; + data_points = new int[n]; + for ( i=0; i < n; i++ ) + { + data_points[i] = i; + } + num_entries = data_points.length; + } +} + diff --git a/PERSON.java b/PERSON.java new file mode 100644 index 0000000..3b42fac --- /dev/null +++ b/PERSON.java @@ -0,0 +1,99 @@ +/* $Header: PERSON.java 15-mar-00.09:06:53 rbhyrava Exp $ */ + +/* Copyright (c) Oracle Corporation 2000. All Rights Reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + rbhyrava 03/15/00 - AQ API demo -Jpub generated class for PERSON Type + rbhyrava 03/15/00 - Creation + */ + +/** + * @version $Header: PERSON.java 15-mar-00.09:06:53 rbhyrava Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ + +/**** + * Jpub generated class for for ADDRESS object type + * Used in aqorademo02.java + ***/ + +import java.sql.SQLException; +import java.sql.Connection; +import oracle.jdbc.OracleTypes; +import oracle.sql.ORAData; +import oracle.sql.ORADataFactory; +import oracle.sql.Datum; +import oracle.sql.STRUCT; +import oracle.jpub.runtime.MutableStruct; + +public class PERSON implements ORAData, ORADataFactory +{ + public static final String _SQL_NAME = "AQJAVA.PERSON"; + public static final int _SQL_TYPECODE = OracleTypes.STRUCT; + + protected MutableStruct _struct; + + private static int[] _sqlType = { 12,2002 }; + private static ORADataFactory[] _factory = new ORADataFactory[2]; + static + { + _factory[1] = ADDRESS.getORADataFactory(); + } +protected static final PERSON _PERSONFactory = new PERSON(false); + + public static ORADataFactory getORADataFactory() + { return _PERSONFactory; } + /* constructor */ + protected PERSON(boolean init) + { if(init) _struct = new MutableStruct(new Object[2], _sqlType, _factory); } + public PERSON() + { this(true); } + public PERSON(String name, ADDRESS home) throws SQLException + { this(true); + setName(name); + setHome(home); + } + + /* ORAData interface */ + public Datum toDatum(Connection c) throws SQLException + { + return _struct.toDatum(c, _SQL_NAME); + } + + + /* ORADataFactory interface */ + public ORAData create(Datum d, int sqlType) throws SQLException + { return create(null, d, sqlType); } + protected ORAData create(PERSON o, Datum d, int sqlType) throws SQLException + { + if (d == null) return null; + if (o == null) o = new PERSON(false); + o._struct = new MutableStruct((STRUCT) d, _sqlType, _factory); + return o; + } + /* accessor methods */ + public String getName() throws SQLException + { return (String) _struct.getAttribute(0); } + + public void setName(String name) throws SQLException + { _struct.setAttribute(0, name); } + + + public ADDRESS getHome() throws SQLException + { return (ADDRESS) _struct.getAttribute(1); } + + public void setHome(ADDRESS home) throws SQLException + { _struct.setAttribute(1, home); } + +} diff --git a/aadvdemo.sql b/aadvdemo.sql new file mode 100644 index 0000000..43fce14 --- /dev/null +++ b/aadvdemo.sql @@ -0,0 +1,1602 @@ +-- +-- $Header: aadvdemo.sql 29-may-2007.13:15:19 achoi Exp $ +-- +-- aadvdemo.sql +-- +-- Copyright (c) 2003, 2007, Oracle. All rights reserved. +-- +-- NAME +-- aadvdemo.sql - SQLAccess Advisor documentation examples +-- +-- DESCRIPTION +-- Runs documentation examples pertaining to the SQLAccess Advisor. +-- Chapter 17 in the Data Warehousing Guide. +-- +-- NOTES +-- Before running this script, the directories ADVISOR_RESULTS +-- and TUNE_RESULTS need to be defined as first described in +-- Section 17.2.23. If they are not setup, the dbms_advisor.create_file +-- calls will not succeed. +-- +-- MODIFIED (MM/DD/YY) +-- achoi 05/29/07 - fix order by +-- gssmith 02/09/07 - Remove Summary Advisor +-- gvincent 11/02/06 - downcase connects for secure verifiers +-- gssmith 05/09/06 - STS conversion +-- pabingha 02/02/05 - BUG 4148628 - disable search parameter +-- mmoy 09/01/04 - Add order by. +-- gssmith 07/20/04 - Add utlxaa to the script +-- lburgess 06/07/04 - add order by clause +-- gssmith 04/30/04 - Add demonstration of 10gR2 features +-- gssmith 04/20/04 - Adjust FAILED count +-- lburgess 11/04/03 - bug 3164691 fixed, uncomment testcase +-- lburgess 10/28/03 - lburgess_doc_examples +-- lburgess 09/17/03 - Created +--------------------------------------------------------------------------- +-- +-- RUNS_STANDALONE Yes +-- +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 + + +---------------------------------------------------------------------- +-- Data Warehousing Guide Examples from Chapter 17 - SQLAccess Advisor +---------------------------------------------------------------------- + +-- Section 17.2.2 SQLAccess Advisor Privileges +---------------------------------------------- +-- Grant the ADVISOR privilege to the user. + +connect /as sysdba; +grant ADVISOR to sh; + +-- Connect to user +connect sh/sh; + + +-- Section 17.2.3 Creating Tasks +-------------------------------- + +VARIABLE task_id NUMBER; +VARIABLE task_name VARCHAR2(255); +EXECUTE :task_name := 'MYTASK'; +EXECUTE DBMS_ADVISOR.CREATE_TASK ('SQL Access Advisor', :task_id, :task_name); + + + +-- Section 17.2.5 Creating Templates +------------------------------------ + +-- 1. Create a template called MY_TEMPLATE + +VARIABLE template_id NUMBER; +VARIABLE template_name VARCHAR2(255); +EXECUTE :template_name := 'MY_TEMPLATE'; +EXECUTE DBMS_ADVISOR.CREATE_TASK('SQL Access Advisor',:template_id, - + :template_name, is_template => 'TRUE'); + + +-- 2. Set template parameters. + + +-- set naming conventions for recommended indexes/mvs +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER ( - + :template_name, 'INDEX_NAME_TEMPLATE', 'SH_IDX$$_'); + +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER ( - + :template_name, 'MVIEW_NAME_TEMPLATE', 'SH_MV$$_'); + + +-- First create the tablespaces used in SET_TASK_PARAMETER +-- doc example. + +connect /as sysdba; + +create tablespace sh_indexes datafile 'shidx.f' size 2m reuse +autoextend on default storage (initial 2k next 2k pctincrease 0 +maxextents unlimited); + +create tablespace sh_mviews datafile 'shmv.f' size 2m reuse +autoextend on default storage (initial 2k next 2k pctincrease 0 +maxextents unlimited); + + +-- Now continue with the SET_TASK_PARAMETER example. + +connect sh/sh; + +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER ( - + :template_name, 'DEF_INDEX_TABLESPACE', 'SH_INDEXES'); + +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER ( - + :template_name, 'DEF_MVIEW_TABLESPACE', 'SH_MVIEWS'); + + + +-- 3. This template can now be used as a starting point +-- to create a task as follows: + + +EXECUTE DBMS_ADVISOR.DELETE_TASK('MYTASK'); + +VARIABLE task_id NUMBER; +VARIABLE task_name VARCHAR2(255); +EXECUTE :task_name := 'MYTASK'; +EXECUTE DBMS_ADVISOR.CREATE_TASK('SQL Access Advisor', :task_id, - + :task_name, template=>'MY_TEMPLATE'); + + + +-- Use pre-defined template SQLACCESS_WAREHOUSE + +EXECUTE DBMS_ADVISOR.DELETE_TASK('MYTASK'); + +EXECUTE DBMS_ADVISOR.CREATE_TASK('SQL Access Advisor', - + :task_id, :task_name, template=>'SQLACCESS_WAREHOUSE'); + + + + + +-- Example 17-1 Creating a Workload +----------------------------------- + +VARIABLE workload_name VARCHAR2(255); +EXECUTE :workload_name := 'MYWORKLOAD'; +EXECUTE DBMS_ADVISOR.CREATE_SQLWKLD(:workload_name,'This is my first workload'); + + +-- Example 17-2 Creating a Workload from a Template +--------------------------------------------------- + +-- 1. Create the variables. + +VARIABLE template_id NUMBER; +VARIABLE template_name VARCHAR2(255); + + +-- 2. Create a template called MY_WK_TEMPLATE. + +EXECUTE :template_name := 'MY_WK_TEMPLATE'; +EXECUTE DBMS_ADVISOR.CREATE_SQLWKLD(:template_name, is_template=>'TRUE'); + + +-- 3. Set template parameters. For example, the following sets the filter so only tables in the sh schema are tuned: + +-- set USERNAME_LIST filter to SH +EXECUTE DBMS_ADVISOR.SET_SQLWKLD_PARAMETER( - + :template_name, 'USERNAME_LIST', 'SH'); + + +-- 4. Now create a workload using the template: + +EXECUTE DBMS_ADVISOR.DELETE_SQLWKLD('MYWORKLOAD'); + +VARIABLE workload_name VARCHAR2(255); +EXECUTE :workload_name := 'MYWORKLOAD'; +EXECUTE DBMS_ADVISOR.CREATE_SQLWKLD ( - + :workload_name, 'This is my first workload', 'MY_WK_TEMPLATE'); + + + +-- Section 17.2.8 Linking a Task and a Workload +----------------------------------------------- + +EXECUTE DBMS_ADVISOR.ADD_SQLWKLD_REF('MYTASK', 'MYWORKLOAD'); + + + + +-- Section 17.2.9.1 SQL Tuning Set +---------------------------------- + +-- First create a SQL Tuning Set called MY_STS_WORKLOAD + +declare + sql_stmt varchar2(1000); +begin + +sql_stmt := +'SELECT /* Query */ + t.week_ending_day, p.prod_subcategory, + sum(s.amount_sold) AS dollars, + s.channel_id, s.promo_id + FROM sales s, times t, products p + WHERE s.time_id = t.time_id + AND s.prod_id = p.prod_id + AND s.prod_id > 10 AND s.prod_id < 50 + GROUP BY t.week_ending_day, p.prod_subcategory, + s.channel_id, s.promo_id'; + + execute immediate sql_stmt; +end; +/ + + +-- Grant privilege to sh for using sql tuning set + +connect /as sysdba; +grant ADMINISTER SQL TUNING SET to sh; + +connect sh/sh; + + + +DECLARE + sqlsetname VARCHAR2(30); + sqlsetcur dbms_sqltune.sqlset_cursor; + refid NUMBER; +BEGIN + sqlsetname := 'MY_STS_WORKLOAD'; + + dbms_sqltune.create_sqlset(sqlsetname, 'Test loading from cursor cache'); + + OPEN sqlsetcur FOR + SELECT VALUE(P) + FROM TABLE( + dbms_sqltune.select_cursor_cache( + 'sql_text like ''SELECT /* Query%''', + NULL, + NULL, + NULL, + NULL, + NULL, + null) + ) P; + + dbms_sqltune.load_sqlset(sqlsetname, sqlsetcur); + +end; +/ + + +-- Now create a workload from the SQL Tuning Set. + +VARIABLE sqlsetname VARCHAR2(30); +VARIABLE workload_name VARCHAR2(30); +VARIABLE saved_stmts NUMBER; +VARIABLE failed_stmts NUMBER; + +EXECUTE :sqlsetname := 'MY_STS_WORKLOAD'; +EXECUTE :workload_name := 'MY_WORKLOAD'; + +EXECUTE DBMS_ADVISOR.CREATE_SQLWKLD (:workload_name); +EXECUTE DBMS_ADVISOR.IMPORT_SQLWKLD_STS (:workload_name , - + :sqlsetname, 'NEW', 1, :saved_stmts, :failed_stmts); + + + + +-- Section 17.2.9.2 Loading a User-Defined Workload +--------------------------------------------------- + +-- +-- Create a user-workload table that will contain SQL statements. +-- + +set echo off + +@utlxaa + +CREATE INDEX aadv_uwk_idx_01 + ON user_workload (module); + +CREATE INDEX aadv_uwk_idx_02 + ON user_workload (username); + +-- +-- Clean up any prior activity data +-- + +truncate table user_workload; + +-- +-- Insert sample SQL statements into the user-workload table +-- + +-- +-- query 1: aggregation with selection +-- + +INSERT INTO user_workload +(username, module, action, priority, elapsed_time, cpu_time, buffer_gets, + disk_reads, rows_processed, executions, optimizer_cost, last_execution_date, + stat_period, sql_text) +VALUES ('SH', 'Example1', 'Action', 2, 1, 1, 1, 1, 1, 1000, 1, SYSDATE, 1, +'SELECT t.week_ending_day, p.prod_subcategory, + sum(s.amount_sold) AS dollars, + s.channel_id, s.promo_id + FROM sales s, times t, products p + WHERE s.time_id = t.time_id + AND s.prod_id = p.prod_id + AND s.prod_id > 10 AND s.prod_id < 50 + GROUP BY t.week_ending_day, p.prod_subcategory, + s.channel_id, s.promo_id +'); + +-- +-- query 2: aggregation with selection +-- + +INSERT INTO user_workload +(username, module, action, priority, elapsed_time, cpu_time, buffer_gets, + disk_reads, rows_processed, executions, optimizer_cost, last_execution_date, + stat_period, sql_text) +VALUES ('SH', 'Example1', 'Action', 2, 1, 1, 1, 1, 1, 1000, 1, SYSDATE, 1, +' SELECT t.calendar_month_desc, sum(s.amount_sold) AS dollars +FROM sales s , times t +WHERE s.time_id = t.time_id + AND s.time_id between TO_DATE(''01-JAN-2000'', ''DD-MON-YYYY'') + AND TO_DATE(''01-JUL-2000'', ''DD-MON-YYYY'') +GROUP BY t.calendar_month_desc +'); + +-- +-- query 3: star query +-- + +INSERT INTO user_workload +(username, module, action, priority, elapsed_time, cpu_time, buffer_gets, + disk_reads, rows_processed, executions, optimizer_cost, last_execution_date, + stat_period, sql_text) +VALUES ('SH', 'Example1', 'Action', 2, 1, 1, 1, 1, 1, 1000, 1, SYSDATE, 1, +'SELECT ch.channel_class, c.cust_city, t.calendar_quarter_desc, + SUM(s.amount_sold) sales_amount +FROM sales s, times t, customers c, channels ch +WHERE s.time_id = t.time_id +AND s.cust_id = c.cust_id +AND s.channel_id = ch.channel_id +AND c.cust_state_province = ''CA'' +AND ch.channel_desc in (''Internet'',''Catalog'') +AND t.calendar_quarter_desc IN (''1999-Q1'',''1999-Q2'') +GROUP BY ch.channel_class, c.cust_city, t.calendar_quarter_desc +'); + +-- +-- query 4: order by +-- + +INSERT INTO user_workload +(username, module, action, priority, elapsed_time, cpu_time, buffer_gets, + disk_reads, rows_processed, executions, optimizer_cost, last_execution_date, + stat_period, sql_text) +VALUES ('SH', 'Example1', 'Action', 2, 1, 1, 1, 1, 1, 1000, 1, SYSDATE, 1, +' SELECT c.country_id, c.cust_city, c.cust_last_name +FROM customers c +WHERE c.country_id in (''US'', ''UK'') +ORDER BY c.country_id, c.cust_city, c.cust_last_name +'); + +commit; + + +-- now load the user-defined workload + +VARIABLE saved_stmts NUMBER; +VARIABLE failed_stmts NUMBER; +EXECUTE DBMS_ADVISOR.IMPORT_SQLWKLD_USER( - + 'MYWORKLOAD', 'NEW', 'SH', 'USER_WORKLOAD', :saved_stmts, :failed_stmts); + + + +-- Section 17.2.9.3 Loading a SQL Cache Workload +------------------------------------------------ + +VARIABLE saved_stmts NUMBER; +VARIABLE failed_stmts NUMBER; + +EXECUTE DBMS_ADVISOR.IMPORT_SQLWKLD_SQLCACHE (- + 'MYWORKLOAD', 'APPEND', 2, :saved_stmts, :failed_stmts); + + + +-- Section 17.2.9.4 Using a Hypothetical Workload +------------------------------------------------- + + +VARIABLE workload_name VARCHAR2(255); +VARIABLE saved_stmts NUMBER; +VARIABLE failed_stmts NUMBER; +EXECUTE :workload_name := 'SCHEMA_WKLD'; +EXECUTE DBMS_ADVISOR.CREATE_SQLWKLD(:workload_name); +EXECUTE DBMS_ADVISOR.SET_SQLWKLD_PARAMETER (:workload_name, - + 'USERNAME_LIST', 'SH'); +EXECUTE DBMS_ADVISOR.IMPORT_SQLWKLD_SCHEMA ( - + :workload_name, 'NEW', 2, :saved_stmts, :failed_stmts); + + + + +-- Section 17.2.9.5 Using a 9i Workload +--------------------------------------- + + +-- Before the example in the documentation can be run, an Oracle9i +-- workload must first be created. + +-- Run some SQL statements so we have something in the cache + +set echo off +connect / as sysdba; +alter system flush shared_pool; +connect sh/sh; +set echo off +SELECT SUM(amount_sold), promo_id FROM sales where promo_id < 8 group by promo_id order by promo_id; +SELECT SUM(amount_sold), channel_id FROM sales group by channel_id order by channel_id; +set echo on + +-- load the SQL CACHE workload and check that it is there + +VARIABLE collection_id NUMBER; +VARIABLE no_recs NUMBER; + +-- The setup is complete, now the documentation example can be shown. + +-- 1. Create some variables. + +VARIABLE workload_name VARCHAR2(255); +VARIABLE saved_stmts NUMBER; +VARIABLE failed_stmts NUMBER; + + +-- Section 17.2.9.6 SQLAccess Advisor Workload Parameters +--------------------------------------------------------- + +-- Order statements by OPTIMIZER_COST +EXECUTE DBMS_ADVISOR.SET_SQLWKLD_PARAMETER ( - + 'MYWORKLOAD', 'ORDER_LIST', 'OPTIMIZER_COST'); + +-- Max number of statements 3 +EXECUTE DBMS_ADVISOR.SET_SQLWKLD_PARAMETER('MYWORKLOAD', 'SQL_LIMIT', 3); + + + +-- Section 17.2.10 SQL Workload Journal +--------------------------------------- + +-- You can turn journaling off before importing workload as follows: + +EXECUTE DBMS_ADVISOR.SET_SQLWKLD_PARAMETER('MYWORKLOAD', 'JOURNALING', 0); + + +-- To view only fatal messages: + +EXECUTE DBMS_ADVISOR.SET_SQLWKLD_PARAMETER('MYWORKLOAD', 'JOURNALING', 4); + + + + +-- Section 17.2.11 Adding SQL Statements to a Workload +------------------------------------------------------ + +VARIABLE sql_text VARCHAR2(400); +EXECUTE :sql_text := 'SELECT AVG(amount_sold) FROM sales'; +EXECUTE DBMS_ADVISOR.ADD_SQLWKLD_STATEMENT ( - + 'MYWORKLOAD', 'MONTHLY', 'ROLLUP', priority=>1, executions=>10, - + username => 'SH', sql_text => :sql_text); + + + +-- Section 17.2.12 Deleting SQL Statements from a Workload +---------------------------------------------------------- + +-- Delete using sql_id + +EXECUTE DBMS_ADVISOR.DELETE_SQLWKLD_STATEMENT('MYWORKLOAD', 10); + + + +-- Section 17.2.13 Changing SQL Statements in a Workload +-------------------------------------------------------- + + +EXECUTE DBMS_ADVISOR.UPDATE_SQLWKLD_STATEMENT( - + 'MYWORKLOAD', 2, priority=>3); + + + + +-- Section 17.2.14.1 Setting Workload Attributes +------------------------------------------------ + +EXECUTE DBMS_ADVISOR.UPDATE_SQLWKLD_ATTRIBUTES ( - + 'MYWORKLOAD', read_only=> 'TRUE'); + + + + +-- Section 17.2.14.2 Resetting Workloads +---------------------------------------- + + +-- need to first set it to be readable +EXECUTE DBMS_ADVISOR.UPDATE_SQLWKLD_ATTRIBUTES ( - + 'MYWORKLOAD', read_only=> 'FALSE'); + + +EXECUTE DBMS_ADVISOR.RESET_SQLWKLD('MYWORKLOAD'); + + + + +-- Section 17.2.14.3 Removing a Link Between a Workload and a Task +------------------------------------------------------------------ + + +EXECUTE DBMS_ADVISOR.DELETE_SQLWKLD_REF('MYTASK', 'MYWORKLOAD'); + + + +-- Section 17.2.15 Removing Workloads +------------------------------------- + + +EXECUTE DBMS_ADVISOR.DELETE_SQLWKLD('MYWORKLOAD'); + + + +-- Section 17.2.16 Recommendation Options +----------------------------------------- + +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER('MYTASK','STORAGE_CHANGE', 100); + + +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER ( - + 'MYTASK', 'VALID_TABLE_LIST', 'SH.SALES, SH.CUSTOMERS'); + + +-- clean-up +EXECUTE dbms_advisor.delete_task('MYTASK'); + + + +-- Section 17.2.17 Generating Recommendations +--------------------------------------------- + + +-- Steps 1 through 6 are the required setup steps to be able to execute a +-- task and have some worthwhile data to view after its execution. + +-- Step 1 Prepare the USER_WORKLOAD table + +-- The USER_WORKLOAD table is loaded with SQL statements as follows: + +connect sh/sh; +-- aggregation with selection +INSERT INTO user_workload (username, module, action, priority, sql_text) +VALUES ('SH', 'Example1', 'Action', 2, +'SELECT t.week_ending_day, p.prod_subcategory, + SUM(s.amount_sold) AS dollars, s.channel_id, s.promo_id + FROM sales s, times t, products p WHERE s.time_id = t.time_id + AND s.prod_id = p.prod_id AND s.prod_id > 10 AND s.prod_id < 50 + GROUP BY t.week_ending_day, p.prod_subcategory, + s.channel_id, s.promo_id') +/ + +-- aggregation with selection +INSERT INTO user_workload (username, module, action, priority, sql_text) +VALUES ('SH', 'Example1', 'Action', 2, + 'SELECT t.calendar_month_desc, SUM(s.amount_sold) AS dollars + FROM sales s , times t + WHERE s.time_id = t.time_id + AND s.time_id between TO_DATE(''01-JAN-2000'', ''DD-MON-YYYY'') + AND TO_DATE(''01-JUL-2000'', ''DD-MON-YYYY'') +GROUP BY t.calendar_month_desc') +/ + +--Load all SQL queries. +INSERT INTO user_workload (username, module, action, priority, sql_text) +VALUES ('SH', 'Example1', 'Action', 2, +'SELECT ch.channel_class, c.cust_city, t.calendar_quarter_desc, + SUM(s.amount_sold) sales_amount +FROM sales s, times t, customers c, channels ch +WHERE s.time_id = t.time_id AND s.cust_id = c.cust_id +AND s.channel_id = ch.channel_id AND c.cust_state_province = ''CA'' +AND ch.channel_desc IN (''Internet'',''Catalog'') +AND t.calendar_quarter_desc IN (''1999-Q1'',''1999-Q2'') +GROUP BY ch.channel_class, c.cust_city, t.calendar_quarter_desc') +/ + + +-- order by +INSERT INTO user_workload (username, module, action, priority, sql_text) +VALUES ('SH', 'Example1', 'Action', 2, + 'SELECT c.country_id, c.cust_city, c.cust_last_name +FROM customers c WHERE c.country_id in (''US'', ''UK'') +ORDER BY c.country_id, c.cust_city, c.cust_last_name') +/ +COMMIT; + +connect sh/sh; +set serveroutput on; + +VARIABLE task_id NUMBER; +VARIABLE task_name VARCHAR2(255); +VARIABLE workload_name VARCHAR2(255); +VARIABLE saved_stmts NUMBER; +VARIABLE failed_stmts NUMBER; + + +-- Step 2 Create a workload named MYWORKLOAD + +EXECUTE :workload_name := 'MYWORKLOAD'; + +EXECUTE DBMS_ADVISOR.CREATE_SQLWKLD(:workload_name); + +-- Step 3 Load the workload from user-defined table SH.USER_WORKLOAD + +EXECUTE DBMS_ADVISOR.IMPORT_SQLWKLD_USER (:workload_name, 'APPEND', 'SH', - + 'USER_WORKLOAD', :saved_stmts, :failed_stmts); +PRINT :saved_stmts; +PRINT :failed_stmts; + + +-- Step 4 Create a task named MYTASK + +EXECUTE :task_name := 'MYTASK'; + +EXECUTE DBMS_ADVISOR.CREATE_TASK('SQL Access Advisor', :task_id, :task_name); + +-- Step 5 Set task parameters + +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER(:task_name, 'STORAGE_CHANGE', 100); + +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER ( - + :task_name, 'EXECUTION_TYPE', 'INDEX_ONLY'); + +-- Step 6 Create a link between workload and task + +EXECUTE DBMS_ADVISOR.ADD_SQLWKLD_REF(:task_name, :workload_name); + + + + + +-- Now execute the task for section 17.2.17.1 + +EXECUTE DBMS_ADVISOR.EXECUTE_TASK('MYTASK'); + + + + +-- Section 17.2.18 Viewing the Recommendations +---------------------------------------------- + + +VARIABLE workload_name VARCHAR2(255); +VARIABLE task_name VARCHAR2(255); +EXECUTE :task_name := 'MYTASK'; +EXECUTE :workload_name := 'MYWORKLOAD'; + +SELECT REC_ID, RANK, BENEFIT +FROM USER_ADVISOR_RECOMMENDATIONS WHERE TASK_NAME = :task_name; + + +SELECT sql_id, rec_id, precost, postcost, + (precost-postcost)*100/precost AS percent_benefit +FROM USER_ADVISOR_SQLA_WK_STMTS +WHERE TASK_NAME = :task_name +order by sql_id; + + + +SELECT 'Action Count', COUNT(DISTINCT action_id) cnt +FROM user_advisor_actions WHERE task_name = :task_name; + + +-- see the actions for each recommendations + +SELECT rec_id, action_id, SUBSTR(command,1,30) AS command +FROM user_advisor_actions WHERE task_name = :task_name +ORDER BY rec_id, action_id; + + +-- The following PL/SQL procedure can be used to print out some of +-- the attributes of the recommendations. + +connect sh/sh; +CREATE OR REPLACE PROCEDURE show_recm (in_task_name IN VARCHAR2) IS +CURSOR curs IS + SELECT DISTINCT action_id, command, attr1, attr2, attr3, attr4 + FROM user_advisor_actions + WHERE task_name = in_task_name + ORDER BY action_id; + v_action number; + v_command VARCHAR2(32); + v_attr1 VARCHAR2(4000); + v_attr2 VARCHAR2(4000); + v_attr3 VARCHAR2(4000); + v_attr4 VARCHAR2(4000); + v_attr5 VARCHAR2(4000); +BEGIN + OPEN curs; + DBMS_OUTPUT.PUT_LINE('========================================='); + DBMS_OUTPUT.PUT_LINE('Task_name = ' || in_task_name); + LOOP + FETCH curs INTO + v_action, v_command, v_attr1, v_attr2, v_attr3, v_attr4 ; + EXIT when curs%NOTFOUND; + DBMS_OUTPUT.PUT_LINE('Action ID: ' || v_action); + DBMS_OUTPUT.PUT_LINE('Command : ' || v_command); + DBMS_OUTPUT.PUT_LINE('Attr1 (name) : ' || SUBSTR(v_attr1,1,30)); + DBMS_OUTPUT.PUT_LINE('Attr2 (tablespace): ' || SUBSTR(v_attr2,1,30)); + DBMS_OUTPUT.PUT_LINE('Attr3 : ' || SUBSTR(v_attr3,1,30)); + DBMS_OUTPUT.PUT_LINE('Attr4 : ' || v_attr4); + DBMS_OUTPUT.PUT_LINE('Attr5 : ' || v_attr5); + DBMS_OUTPUT.PUT_LINE('----------------------------------------'); + END LOOP; + CLOSE curs; + DBMS_OUTPUT.PUT_LINE('=========END RECOMMENDATIONS============'); +END show_recm; +/ + + +-- see what the actions are using sample procedure + +set serveroutput on size 99999 +EXECUTE show_recm(:task_name); + + + +-- Section 17.2.19 Access Advisor Journal +----------------------------------------- + +-- This section moved to the end of section 17.2.28 since +-- it requires the task to be reset. + + + +-- Section 17.2.20 Stopping the recommendation Process +------------------------------------------------------ + + +-- Note, a task must be executing for this to succeed. This +-- testcase just proves the syntax is correct. Expect an error +-- such as "task must be executing to be cancelled". + +EXECUTE DBMS_ADVISOR.CANCEL_TASK('MYTASK'); + + + +-- Section 17.2.21 Marking Recommendations +------------------------------------------ + +EXECUTE DBMS_ADVISOR.MARK_RECOMMENDATION('MYTASK', 2, 'REJECT'); + + + +-- Section 17.2.22 Modifying Recommendations +-------------------------------------------- + +-- Before the TABLESPACE recommendation attribute can be updated, +-- recommendations of the CREATE type must exist. Steps 1 through 6 +-- do the required setup for this. + +-- 1. Create task + +VARIABLE task_id2 NUMBER; +VARIABLE task_name2 VARCHAR2(255); +EXECUTE :task_name2 := 'MYTASK2'; +EXECUTE DBMS_ADVISOR.CREATE_TASK ('SQL Access Advisor', :task_id2, - + :task_name2); + +-- 2. Create workload + +VARIABLE workload_name2 VARCHAR2(255); +EXECUTE :workload_name2 := 'MYWORKLOAD2'; +EXECUTE DBMS_ADVISOR.CREATE_SQLWKLD(:workload_name2,'This is my test workload'); + +-- 3. Link workload and task + +EXECUTE DBMS_ADVISOR.ADD_SQLWKLD_REF(:task_name2, :workload_name2); + + +-- 4. Add a sql statement to the workload + +VARIABLE sql_text2 VARCHAR2(400); +EXECUTE :sql_text2 := 'SELECT AVG(amount_sold) FROM sales'; +EXECUTE DBMS_ADVISOR.ADD_SQLWKLD_STATEMENT ( - + :workload_name2, 'MONTHLY', 'ROLLUP', priority=>1, executions=>10, - + username => 'SH', sql_text => :sql_text2); + + +-- 5. Execute the task + +EXECUTE DBMS_ADVISOR.EXECUTE_TASK(:task_name2); + +-- 6. See the actions recommended + +SELECT rec_id, action_id, SUBSTR(command,1,30) AS command +FROM user_advisor_actions WHERE task_name = :task_name2 +ORDER BY rec_id, action_id; + + + +-- The following example modifies the attribute TABLESPACE for recommendation +-- ID 1, action ID 1 to SH_MVIEWS. + +EXECUTE DBMS_ADVISOR.UPDATE_REC_ATTRIBUTES(:task_name2, 1, 2, 'TABLESPACE', - + 'SH_MVIEWS'); + + + + +-- Section 17.2.23 Generating SQL Scripts +----------------------------------------- + + +-- Define a directory "ADVISOR_RESULTS" and grant permissions to +-- read/write to it. +-- +-- connect sh/sh; +-- CREATE DIRECTORY ADVISOR_RESULTS AS '/mydir'; +-- GRANT READ ON DIRECTORY ADVISOR_RESULTS TO PUBLIC; +-- GRANT WRITE ON DIRECTORY ADVISOR_RESULTS TO PUBLIC; + + +-- save script CLOB to file + + +-- Note: When "get_task_script" passed in as a parameter you get the error +-- 'invalid file script'. This is a problem with how SQLPlus handles +-- CLOBs. Doc changed to call GET_TASK_SCRIPT directly in CREATE_FILE. + +-- generate script as a CLOB +--variable scriptbuf CLOB; +--EXECUTE :scriptbuf := 'DBMS_ADVISOR.GET_TASK_SCRIPT(''MYTASK'')'; + + +-- doesn't work +--EXECUTE DBMS_ADVISOR.CREATE_FILE(:scriptbuf, 'ADVISOR_RESULTS',- +-- 'advscript.sql'); + +-- works +EXECUTE DBMS_ADVISOR.CREATE_FILE(DBMS_ADVISOR.GET_TASK_SCRIPT('MYTASK'), 'ADVISOR_RESULTS','advscript.sql'); + + + +-- Section 17.2.24 When Recommendations are No Longer Required +-------------------------------------------------------------- + + +EXECUTE DBMS_ADVISOR.RESET_TASK('MYTASK'); + + + +-- Section 17.2.25 Performing a Quick Tune +------------------------------------------ + + +VARIABLE task_name VARCHAR2(255); +VARIABLE sql_stmt VARCHAR2(4000); +EXECUTE :sql_stmt := 'SELECT COUNT(*) FROM customers - + WHERE cust_state_province=''CA'''; +EXECUTE :task_name := 'MY_QUICKTUNE_TASK'; + +EXECUTE DBMS_ADVISOR.QUICK_TUNE(DBMS_ADVISOR.SQLACCESS_ADVISOR, - + :task_name, :sql_stmt); + + + +-- Section 17.2.26.1 Updating Task Attributes +--------------------------------------------- + +EXECUTE DBMS_ADVISOR.UPDATE_TASK_ATTRIBUTES('MYTASK', 'TUNING1'); + + +-- The following example marks the task TUNING1 to read only + +EXECUTE DBMS_ADVISOR.UPDATE_TASK_ATTRIBUTES('TUNING1', read_only => 'TRUE'); + + +-- The following example marks the task MYTASK as a template. + +EXECUTE DBMS_ADVISOR.UPDATE_TASK_ATTRIBUTES('TUNING1', is_template=>'TRUE'); + + + +-- Section 17.2.26.2 Deleting Tasks +----------------------------------- +-- need an existing task to delete, use TUNING1 instead of MYTASK +-- but first make it readable. + +EXECUTE DBMS_ADVISOR.UPDATE_TASK_ATTRIBUTES('TUNING1', read_only => 'FALSE'); + +EXECUTE DBMS_ADVISOR.DELETE_TASK('TUNING1'); + + +------------------------------------------------------------------------- +--Section 17.2.28 Examples of Using the SQLAccess Advisor +------------------------------------------------------------------------- + +-- cleanup from previous example + +EXECUTE DBMS_ADVISOR.DELETE_SQLWKLD('MYWORKLOAD'); + + +-- Section 17.2.28.1 Recommendations From a User-Defined Workload +----------------------------------------------------------------- + +-- The following example imports workload from a user-defined table, +-- SH.USER_WORKLOAD. It then creates a task called MYTASK, sets the +-- storage budget to 100 MB and runs the task. The recommendations +-- are printed out using a PL/SQL procedure. Finally, it generates a +-- script, which can be used to implement the recommendations. + +-- Step 1 Prepare the USER_WORKLOAD table + +-- The USER_WORKLOAD table is loaded with SQL statements as follows: + +connect sh/sh; +-- aggregation with selection +INSERT INTO user_workload (username, module, action, priority, sql_text) +VALUES ('SH', 'Example1', 'Action', 2, +'SELECT t.week_ending_day, p.prod_subcategory, + SUM(s.amount_sold) AS dollars, s.channel_id, s.promo_id + FROM sales s, times t, products p WHERE s.time_id = t.time_id + AND s.prod_id = p.prod_id AND s.prod_id > 10 AND s.prod_id < 50 + GROUP BY t.week_ending_day, p.prod_subcategory, + s.channel_id, s.promo_id') +/ + +-- aggregation with selection +INSERT INTO user_workload (username, module, action, priority, sql_text) +VALUES ('SH', 'Example1', 'Action', 2, + 'SELECT t.calendar_month_desc, SUM(s.amount_sold) AS dollars + FROM sales s , times t + WHERE s.time_id = t.time_id + AND s.time_id between TO_DATE(''01-JAN-2000'', ''DD-MON-YYYY'') + AND TO_DATE(''01-JUL-2000'', ''DD-MON-YYYY'') +GROUP BY t.calendar_month_desc') +/ + +--Load all SQL queries. +INSERT INTO user_workload (username, module, action, priority, sql_text) +VALUES ('SH', 'Example1', 'Action', 2, +'SELECT ch.channel_class, c.cust_city, t.calendar_quarter_desc, + SUM(s.amount_sold) sales_amount +FROM sales s, times t, customers c, channels ch +WHERE s.time_id = t.time_id AND s.cust_id = c.cust_id +AND s.channel_id = ch.channel_id AND c.cust_state_province = ''CA'' +AND ch.channel_desc IN (''Internet'',''Catalog'') +AND t.calendar_quarter_desc IN (''1999-Q1'',''1999-Q2'') +GROUP BY ch.channel_class, c.cust_city, t.calendar_quarter_desc') +/ + +-- order by +INSERT INTO user_workload (username, module, action, priority, sql_text) +VALUES ('SH', 'Example1', 'Action', 2, + 'SELECT c.country_id, c.cust_city, c.cust_last_name +FROM customers c WHERE c.country_id in (''US'', ''UK'') +ORDER BY c.country_id, c.cust_city, c.cust_last_name') +/ +COMMIT; + +connect sh/sh; +set serveroutput on; + +VARIABLE task_id NUMBER; +VARIABLE task_name VARCHAR2(255); +VARIABLE workload_name VARCHAR2(255); +VARIABLE saved_stmts NUMBER; +VARIABLE failed_stmts NUMBER; + + +EXECUTE :workload_name := 'MYWORKLOAD'; + + +EXECUTE DBMS_ADVISOR.CREATE_SQLWKLD(:workload_name); + +-- Step 3 Load the workload from user-defined table SH.USER_WORKLOAD + +EXECUTE DBMS_ADVISOR.IMPORT_SQLWKLD_USER (:workload_name, 'APPEND', 'SH', - + 'USER_WORKLOAD', :saved_stmts, :failed_stmts); +PRINT :saved_stmts; +PRINT :failed_stmts; + +-- Step 4 Create a task named MYTASK + +EXECUTE :task_name := 'MYTASK'; + +EXECUTE DBMS_ADVISOR.CREATE_TASK('SQL Access Advisor', :task_id, :task_name); + +-- Step 5 Set task parameters + +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER(:task_name, 'STORAGE_CHANGE', 100); + +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER ( - + :task_name, 'EXECUTION_TYPE', 'INDEX_ONLY'); + +-- Step 6 Create a link between workload and task + +EXECUTE DBMS_ADVISOR.ADD_SQLWKLD_REF(:task_name, :workload_name); + +-- Step 7 Execute the task + +EXECUTE DBMS_ADVISOR.EXECUTE_TASK(:task_name); + +-- Step 8 View the recommendations + +-- See the number of recommendations and the status of the task. + +SELECT rec_id, rank, benefit +FROM user_advisor_recommendations WHERE task_name = :task_name +order by rec_id; + + +-- See "Viewing the Recommendations" for further details. + +-- See recommendation for each query. +SELECT sql_id, rec_id, precost, postcost, + (precost-postcost)*100/precost AS percent_benefit +FROM user_advisor_sqla_wk_stmts +WHERE task_name = :task_name +order by sql_id; + +-- See the actions for each recommendations. +SELECT rec_id, action_id, substr(command,1,30) AS command +FROM user_advisor_actions +WHERE task_name = :task_name +ORDER BY rec_id, action_id; + +-- See what the actions are using sample procedure. +SET SERVEROUTPUT ON SIZE 99999 +EXECUTE show_recm(:task_name); + +-- Step 9 Generate a Script to Implement the Recommendations + +EXECUTE DBMS_ADVISOR.CREATE_FILE(DBMS_ADVISOR.GET_TASK_SCRIPT(:task_name),- + 'ADVISOR_RESULTS', 'Example1_script.sql'); + + + +-- Cleanup +EXECUTE dbms_advisor.delete_task(:task_name); +EXECUTE dbms_advisor.delete_sqlwkld(:workload_name); +EXECUTE DBMS_ADVISOR.DELETE_TASK('MY_TEMPLATE'); + + + +-- Section 17.2.28.2 Generate Recommendations Using a Task Template +------------------------------------------------------------------- + +-- The following example creates a template and then uses it to create +-- a task. It then uses this task to generate recommendations from a +-- user-defined table, similar to "Recommendations From a User-Defined +-- Workload". + +connect sh/sh; +VARIABLE template_id NUMBER; +VARIABLE template_name VARCHAR2(255); + + +-- Step 1 Create a template called MY_TEMPLATE + +EXECUTE :template_name := 'MY_TEMPLATE'; + + + +EXECUTE DBMS_ADVISOR.CREATE_TASK ( - + 'SQL Access Advisor',:template_id, :template_name, is_template=>'TRUE'); + +-- Step 2 Set template parameters + +--Set naming conventions for recommended indexes/materialized views. +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER ( - + :template_name, 'INDEX_NAME_TEMPLATE', 'SH_IDX$$_'); +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER ( - + :template_name, 'MVIEW_NAME_TEMPLATE', 'SH_MV$$_'); + +--Set default owners for recommended indexes/materialized views. +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER ( - + :template_name, 'DEF_INDEX_OWNER', 'SH'); +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER ( - + :template_name, 'DEF_MVIEW_OWNER', 'SH'); + +--Set default tablespace for recommended indexes/materialized views. +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER ( - + :template_name, 'DEF_INDEX_TABLESPACE', 'SH_INDEXES'); +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER ( - + :template_name, 'DEF_MVIEW_TABLESPACE', 'SH_MVIEWS'); + +-- Step 3 Create a task using the template + +VARIABLE task_id NUMBER; + +VARIABLE task_name VARCHAR2(255); +EXECUTE :task_name := 'MYTASK'; +EXECUTE DBMS_ADVISOR.CREATE_TASK ( - + 'SQL Access Advisor', :task_id, :task_name, template => 'MY_TEMPLATE'); + +--See the parameter settings for task +SELECT parameter_name, parameter_value +FROM user_advisor_parameters +WHERE task_name = :task_name AND (parameter_name LIKE '%MVIEW%' + OR parameter_name LIKE '%INDEX%') order by 1,2; + +-- Step 4 Create a workload named MYWORKLOAD + +VARIABLE workload_name VARCHAR2(255); + +VARIABLE saved_stmts NUMBER; +VARIABLE failed_stmts NUMBER; +EXECUTE :workload_name := 'MYWORKLOAD'; +EXECUTE DBMS_ADVISOR.CREATE_SQLWKLD(:workload_name); + +-- Step 5 Load the workload from user-defined table SH.USER_WORKLOAD + +EXECUTE DBMS_ADVISOR.IMPORT_SQLWKLD_USER ( - + :workload_name, 'APPEND', 'SH', 'USER_WORKLOAD', :saved_stmts,:failed_stmts); + +-- Step 6 Create a link between the workload and the task + +EXECUTE DBMS_ADVISOR.ADD_SQLWKLD_REF(:task_name, :workload_name); + +-- Step 7 Execute the task + +EXECUTE DBMS_ADVISOR.EXECUTE_TASK(:task_name); + + +-- Step 8 Generate a script + + +EXECUTE DBMS_ADVISOR.CREATE_FILE(DBMS_ADVISOR.GET_TASK_SCRIPT(:task_name),- + 'ADVISOR_RESULTS', 'Example2_script.sql'); + + +-- Clean-up + +EXECUTE dbms_advisor.delete_task(:task_name); +EXECUTE dbms_advisor.delete_sqlwkld(:workload_name); + + + + +-- Section 17.2.28.3 Filter a Workload from the SQL Cache +--------------------------------------------------------- + +-- The following example illustrates collection of a workload from a +-- SQL cache. We first load the cache with a bunch of SQL statements. +-- We then setup some filters to pick only a subset of those statements +-- and import them into a SQLAccess Advisor workload. The workload is +-- then used to generate recommendations. + +-- Step 1 Loading the SQL cache + +--The following statements are executed so they will be in the SQL cache: + +CONNECT /AS SYSDBA; + +--Clear any prior contents of the cache. +ALTER SYSTEM FLUSH SHARED_POOL; +connect sh/sh; + + + +SELECT t.calendar_month_desc, SUM(s.amount_sold) AS dollars +FROM sales s, times t WHERE s.time_id = t.time_id +AND s.time_id between TO_DATE('01-JAN-2000', 'DD-MON-YYYY') + AND TO_DATE('01-JUL-2000', 'DD-MON-YYYY') +GROUP BY t.calendar_month_desc +ORDER BY t.calendar_month_desc; + + +-- Order by +SELECT c.country_id, c.cust_city, c.cust_last_name +FROM customers c WHERE c.country_id IN ('US', 'UK') AND ROWNUM<20 +ORDER BY c.country_id, c.cust_city, c.cust_last_name; + +-- Queries to illustrate filtering +connect scott/tiger; +SELECT e.ename, d.dname +FROM emp e, dept d WHERE e.deptno = d.deptno +order by e.ename; + +SELECT COUNT(*) FROM dept; + +connect sh/sh; + +VARIABLE task_id NUMBER; +VARIABLE task_name VARCHAR2(255); +VARIABLE workload_name VARCHAR2(255); +VARIABLE saved_stmts NUMBER; +VARIABLE failed_stmts NUMBER; + +-- Step 2 Create a workload named MY_CACHE_WORKLOAD + +EXECUTE :workload_name := 'MY_CACHE_WORKLOAD'; + +EXECUTE DBMS_ADVISOR.CREATE_SQLWKLD(:workload_name); + +-- Step 3 Set up filters + +--Load only SQL statements containing SH tables + +EXECUTE DBMS_ADVISOR.SET_SQLWKLD_PARAMETER ( - + :workload_name, 'USERNAME_LIST', 'SH'); + +-- Step 4 Load the workload from SQL Cache +-- +-- NOTE: Because the SQL cache contains internal or recursive SQL +-- statements, the failed count is somewhat unpredictable in +-- this context. Therefore, we typically don't pay much +-- attention to its value. A more interesting view of the +-- results occurs in the journal, where detail statistics +-- describe the filtering results. + +EXECUTE DBMS_ADVISOR.IMPORT_SQLWKLD_SQLCACHE ( - + :workload_name, 'APPEND', 2, :saved_stmts, :failed_stmts); +PRINT :saved_stmts; + +--See the workload statements in catalog views +--Note, create_date removed from query since results would be non-deterministic +SELECT num_select_stmt +FROM user_advisor_sqlw_sum +WHERE workload_name = :workload_name; + +SELECT sql_id, username, optimizer_cost, SUBSTR(sql_text, 1, 30) +FROM user_advisor_sqlw_stmts +WHERE workload_name = :workload_name +ORDER BY sql_id; + +-- Step 5 Add a single statement to the workload + +EXECUTE DBMS_ADVISOR.ADD_SQLWKLD_STATEMENT (:workload_name, username => 'SH', - + priority => 1, executions => 10, sql_text => - + 'select count(*) from customers where cust_state_province=''CA'''); + +--Note, create_date removed from query since results would be non-deterministic +SELECT num_select_stmt +FROM user_advisor_sqlw_sum +WHERE workload_name = :workload_name; + +-- Step 6 Update a statement in the workload + +--VARIABLE updated_stmts NUMBER; + +--EXECUTE DBMS_ADVISOR.UPDATE_SQLWKLD_STATEMENT ( - +-- :workload_name, 'executions < 10', :updated_stmts, priority => 3); + +--PRINT :updated_stmts; + +--See that the change has been made. +--SELECT sql_id, username, executions, priority +--FROM user_advisor_sqlw_stmts +--WHERE workload_name = :workload_name +--ORDER BY sql_id; + +-- Step 7 Create a task named MYTASK + +EXECUTE :task_name := 'MYTASK'; + +EXECUTE DBMS_ADVISOR.CREATE_TASK ('SQL Access Advisor', :task_id, :task_name); + +-- Step 8 Create a link between a workload and a task + +EXECUTE DBMS_ADVISOR.ADD_SQLWKLD_REF(:task_name, :workload_name); + +-- Step 9 Execute the task + +EXECUTE DBMS_ADVISOR.EXECUTE_TASK(:task_name); + +-- Step 10 Generate a script + +EXECUTE DBMS_ADVISOR.CREATE_FILE(DBMS_ADVISOR.GET_TASK_SCRIPT(:task_name),- + 'ADVISOR_RESULTS', 'Example3_script.sql'); + + + + + +-- Section 17.2.28.4 Evaluate Current Usage of Indexes and Materialized Views +----------------------------------------------------------------------------- + +-- This example illustrates how SQLAccess Advisor may be used to evaluate +-- the utilization of existing indexes and materialized views. We assume +-- the workload is loaded into USER_WORKLOAD table as in "Recommendations +-- From a User-Defined Workload". The indexes and materialized views that +-- are being currently used (by the given workload) will appear as RETAIN +-- actions in the SQLAccess Advisor recommendations. + +connect sh/sh; +VARIABLE task_id NUMBER; +VARIABLE task_name VARCHAR2(255); +VARIABLE workload_name VARCHAR2(255); +VARIABLE saved_stmts NUMBER; +VARIABLE failed_stmts NUMBER; + + +-- Step 1 Create a workload named WORKLOAD + +EXECUTE :workload_name := 'MYWORKLOAD'; + +EXECUTE DBMS_ADVISOR.CREATE_SQLWKLD(:workload_name); + +-- Step 2 Load the workload from user-defined table SH.USER_WORKLOAD + +EXECUTE DBMS_ADVISOR.IMPORT_SQLWKLD_USER ( - + :workload_name, 'APPEND', 'SH','USER_WORKLOAD', :saved_stmts, :failed_stmts); + +PRINT :saved_stmts; +PRINT :failed_stmts; + +-- Step 3 Create a task named MY_EVAL_TASK + +EXECUTE :task_name := 'MY_EVAL_TASK'; + +EXECUTE DBMS_ADVISOR.CREATE_TASK ('SQL Access Advisor', :task_id, :task_name); + +-- Step 4 Create a link between workload and task + +EXECUTE DBMS_ADVISOR.ADD_SQLWKLD_REF(:task_name, :workload_name); + +-- Step 5 Set task parameters to indicate EVALUATION ONLY task + +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER (:task_name, 'EVALUATION_ONLY', 'TRUE'); + +-- Step 6 Execute the task + +EXECUTE DBMS_ADVISOR.EXECUTE_TASK(:task_name); + +-- Step 7 View evaluation results + +--See the number of recommendations and the status of the task. + +SELECT rec_id, rank, benefit +FROM user_advisor_recommendations WHERE task_name = :task_name; + +--See the actions for each recommendation. +SELECT rec_id, action_id, SUBSTR(command, 1, 30) AS command +FROM user_advisor_actions WHERE task_name = :task_name +ORDER BY rec_id, action_id; + + + + +-- Section 17.2.19 Access Advisor Journal +----------------------------------------- + +-- During the analysis process (execute_task), the Access Advisor will dump +-- useful information regarding the analysis to a journal. The journal can +-- be viewed using the view USER_ADVISOR_JOURNAL. The amount of information +-- output varies depending on the setting of task parameter journaling. + +-- setup, need to reset the task first + +EXECUTE DBMS_ADVISOR.RESET_TASK('MYTASK'); + +-- You can turn journaling off as follows: + +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER('MYTASK', 'JOURNALING', 0); + + +-- To view only informational messages: + +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER('MYTASK', 'JOURNALING', 4); + + + + +-- Section 17.3 Tuning Materialized Views for Fast Refresh and Query Rewrite +---------------------------------------------------------------------------- + +-- 17.3.1.4 Script Generation DBMS_ADVISOR Function and Procedure +----------------------------------------------------------------- + + +-- Define a directory "TUNE_RESULTS" and grant permissions to +-- read/write to it. + +-- CREATE DIRECTORY TUNE_RESULTS AS '/tmp/script_dir'; +-- GRANT READ, WRITE ON DIRECTORY TUNE_RESULTS TO PUBLIC; + + + +EXECUTE DBMS_ADVISOR.CREATE_FILE(DBMS_ADVISOR.GET_TASK_SCRIPT(:task_name), - + 'TUNE_RESULTS', 'mv_create.sql'); + +EXECUTE DBMS_ADVISOR.CREATE_FILE(DBMS_ADVISOR.GET_TASK_SCRIPT(:task_name, 'UNDO'), 'TUNE_RESULTS', 'mv_undo.sql'); + + + + +-- Example 17-3 Optimizing the Defining Query for Fast Refresh +-------------------------------------------------------------- + +VARIABLE task_cust_mv VARCHAR2(30); +VARIABLE create_mv_ddl VARCHAR2(4000); +EXECUTE :task_cust_mv := 'cust_mv'; +EXECUTE :create_mv_ddl := ' - +CREATE MATERIALIZED VIEW cust_mv - +REFRESH FAST - +DISABLE QUERY REWRITE AS - +SELECT s.prod_id, s.cust_id, SUM(s.amount_sold) sum_amount - +FROM sales s, customers cs - +WHERE s.cust_id = cs.cust_id - +GROUP BY s.prod_id, s.cust_id'; + +EXECUTE DBMS_ADVISOR.TUNE_MVIEW(:task_cust_mv, :create_mv_ddl); + + + +-- Example 17-4 Access IMPLEMENTATION Output Through USER_TUNE_MVIEW View +-------------------------------------------------------------------------- + +SELECT * FROM USER_TUNE_MVIEW +WHERE TASK_NAME= :task_cust_mv AND SCRIPT_TYPE='IMPLEMENTATION' +ORDER BY action_id; + + +-- Example 17-5 Save IMPLEMENTATION Output in a Script File +----------------------------------------------------------- + +-- Define a directory "TUNE_RESULTS" and grant permissions to +-- read/write to it. + +-- CREATE DIRECTORY TUNE_RESULTS AS '/myscript'; +-- GRANT READ, WRITE ON DIRECTORY TUNE_RESULTS TO PUBLIC; + + +EXECUTE DBMS_ADVISOR.CREATE_FILE(DBMS_ADVISOR.GET_TASK_SCRIPT(:task_cust_mv), - + 'TUNE_RESULTS', 'mv_create.sql'); + + + +-- Example 17-6 Enable Query Rewrite by Creating Multiple Materialized Views +---------------------------------------------------------------------------- + + +EXECUTE :task_cust_mv := 'cust_mv2'; + +EXECUTE :create_mv_ddl := ' - +CREATE MATERIALIZED VIEW cust_mv - +ENABLE QUERY REWRITE AS - +SELECT s.prod_id, s.cust_id, COUNT(*) cnt, SUM(s.amount_sold) sum_amount - +FROM sales s, customers cs, countries cn - +WHERE s.cust_id = cs.cust_id AND cs.country_id = cn.country_id - +AND cn.country_name IN (''USA'',''Canada'') - +GROUP BY s.prod_id, s.cust_id - +UNION - +SELECT s.prod_id, s.cust_id, COUNT(*) cnt, SUM(s.amount_sold) sum_amount - +FROM sales s, customers cs - +WHERE s.cust_id = cs.cust_id AND s.cust_id IN (1005,1010,1012) - +GROUP BY s.prod_id, s.cust_id'; + +EXECUTE DBMS_ADVISOR.TUNE_MVIEW(:task_cust_mv, :create_mv_ddl); + + +-- Example 17-7 Access IMPLEMENTATION Output Through USER_TUNE_MVIEW View +------------------------------------------------------------------------- + +SELECT * FROM USER_TUNE_MVIEW +WHERE TASK_NAME='cust_mv2' AND SCRIPT_TYPE='IMPLEMENTATION' +ORDER BY action_id; + + + +-- Example 17-8 Save IMPLEMENTATION Output in a Script File +----------------------------------------------------------- + +--save CREATE output in a script file + +-- Define a directory "TUNE_RESULTS" and grant permissions to +-- read/write to it. + +-- CREATE DIRECTORY TUNE_RESULTS AS '/tmp/script_dir'; +-- GRANT READ, WRITE ON DIRECTORY TUNE_RESULTS TO PUBLIC; + +EXECUTE DBMS_ADVISOR.CREATE_FILE(DBMS_ADVISOR.GET_TASK_SCRIPT('cust_mv2'),- +'TUNE_RESULTS', 'mv_create2.sql'); + + + +-- Example 17-9 Optimized Sub-Materialized View for Fast Refresh +---------------------------------------------------------------- +EXECUTE :task_cust_mv := 'cust_mv3'; + +EXECUTE :create_mv_ddl := '- +CREATE MATERIALIZED VIEW cust_mv - +REFRESH FAST ON DEMAND - +ENABLE QUERY REWRITE AS - +SELECT s.prod_id, s.cust_id, COUNT(*) cnt, SUM(s.amount_sold) sum_amount - +FROM sales s, customers cs - +WHERE s.cust_id = cs.cust_id AND s.cust_id IN (2005,1020) - +GROUP BY s.prod_id, s.cust_id UNION - +SELECT s.prod_id, s.cust_id, COUNT(*) cnt, SUM(s.amount_sold) sum_amount - +FROM sales s, customers cs - +WHERE s.cust_id = cs.cust_id AND s.cust_id IN (1005,1010,1012) - +GROUP BY s.prod_id, s.cust_id'; + +EXECUTE DBMS_ADVISOR.TUNE_MVIEW(:task_cust_mv, :create_mv_ddl); + + + + +-- Example 17-10 Access IMPLEMENTATION Output Through USER_TUNE_MVIEW View +-------------------------------------------------------------------------- + +-- The following query accesses the IMPLEMENTATION output through +-- USER_TUNE_MVIEW: + +SELECT * FROM USER_TUNE_MVIEW +WHERE TASK_NAME= 'cust_mv3' AND SCRIPT_TYPE='IMPLEMENTATION' +ORDER BY action_id; + + + +-- Example 17-11 Save IMPLEMENTATION Output in a Script File +------------------------------------------------------------ + +-- The following statements save the CREATE output in a script file +-- located at /myscript/mv_create3.sql: + + +EXECUTE DBMS_ADVISOR.CREATE_FILE(DBMS_ADVISOR.GET_TASK_SCRIPT('cust_mv3'), - + 'TUNE_RESULTS', 'mv_create3.sql'); + + +-- 10gR2 enhancements +------------------------------------------------------------ + +variable name varchar2(30); + +EXECUTE :name := 'MYWORKLOAD'; + +-- setup, need to recreate the task first + +EXECUTE DBMS_ADVISOR.DELETE_TASK('%'); +EXECUTE DBMS_ADVISOR.DELETE_SQLWKLD('%'); + +EXECUTE DBMS_ADVISOR.CREATE_TASK('SQL Access Advisor','MYTASK'); +EXECUTE DBMS_ADVISOR.CREATE_SQLWKLD(:name); +EXECUTE DBMS_ADVISOR.ADD_SQLWKLD_REF('MYTASK','MYWORKLOAD'); + +-- Add a special SQL statement that currently produces an +-- exact-text match materialized view + +EXECUTE DBMS_ADVISOR.ADD_SQLWKLD_STATEMENT ( - + 'MYWORKLOAD', 'MONTHLY', 'ROLLUP', 0,0,0,0,1,0,10,1,SYSDATE,1, - + 'SH', 'SELECT count(count(*)) FROM sales GROUP BY prod_id'); + +-- Disable exact-text match materialized views + +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER('MYTASK', 'RECOMMEND_MV_EXACT_TEXT_MATCH', 'TRUE'); + +-- Execute task + +EXECUTE DBMS_ADVISOR.EXECUTE_TASK('MYTASK'); + +-- We should have an exact-text-match MV that matches the special workload +-- statement that we added to the workload. +-- +-- Notice that ATTR5 contains the SELECT statement for the materialized view. +-- For exact-text match situations, ATTR5 will match the original SQL +-- statement from the workload. + +select task_name,command,attr5 from user_advisor_actions; + +-- setup, need to reset the task first + +EXECUTE DBMS_ADVISOR.RESET_TASK('MYTASK'); + +-- Disable exact-text match materialized views + +EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER('MYTASK', 'RECOMMEND_MV_EXACT_TEXT_MATCH', 'FALSE'); + +EXECUTE DBMS_ADVISOR.EXECUTE_TASK('MYTASK'); + +-- There should be no exact-text-match MV that matches the special workload +-- statement that we added to the workload + +select task_name,command,attr5 from user_advisor_actions; + + + + + diff --git a/anydata.sql b/anydata.sql new file mode 100644 index 0000000..4df76eb --- /dev/null +++ b/anydata.sql @@ -0,0 +1,317 @@ +Rem +Rem $Header: anydata.sql 31-oct-2006.13:41:28 ytsai Exp $ +Rem +Rem anydata.sql +Rem +Rem Copyright (c) 2006, Oracle. All rights reserved. +Rem +Rem NAME +Rem anydata.sql - Demonstrates Sys.AnyData feature. +Rem +Rem DESCRIPTION +Rem Sys.AnyData stores contains Type description as wells as +Rem a value . This demo shows its usage . +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ytsai 10/31/06 - fix connect +Rem sjanardh 05/02/01 - Merged sjanardh_trans_adddemo +Rem sjanardh 04/30/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +CONNECT system/manager; +GRANT CONNECT,RESOURCE,DBA TO ANYDATA_USER IDENTIFIED BY ANYDATA_USER ; +GRANT READ ON DIRECTORY GPFSD1 TO ANYDATA_USER WITH GRANT OPTION ; +CONNECT ANYDATA_USER/ANYDATA_USER + +SET ECHO ON +SET SERVEROUTPUT ON SIZE 200000 + +--*********************************************************** +-- This demonstrates the usage of Sys.AnyData +--*********************************************************** + +create type person_type as object ( +ssn number , +name varchar2(20), +job char(10) , +salary number(10,4) +); +/ +create type phone_list as varray(100) of number ; +/ +create type date_list as table of date; +/ +create table anydata_tab (col1 number , col2 Sys.AnyData ) ; + +--*********************************************************** +-- Creating AnyData type at one go using Convert functions +--*********************************************************** + +insert into anydata_tab values (10,Sys.AnyData.ConvertNumber(100.101)) ; +insert into anydata_tab values (20,Sys.AnyData.ConvertDate('01-JAN-1901')); +insert into anydata_tab values (30,Sys.AnyData.ConvertChar('thirty')) ; +insert into anydata_tab values (40,Sys.AnyData.ConvertVarchar('forty')) ; +insert into anydata_tab values (50,Sys.AnyData.ConvertVarchar2('fifty')); +insert into anydata_tab values (60,Sys.AnyData.ConvertRaw(utl_raw.cast_to_raw('0908FFGGA')) ); + +--Cannot insert an AnyData of lob type into a table . +insert into anydata_tab values (70,Sys.AnyData.ConvertBlob(to_blob('AABB98076'))) ; +insert into anydata_tab values (80,Sys.AnyData.ConvertClob('eighty') ) ; + + +insert into anydata_tab values (90,Sys.AnyData.ConvertBfile(BFILENAME('GPFSD1', 'gpfdf1.dat'))); +insert into anydata_tab values (100, + Sys.AnyData.ConvertObject(Person_Type(123456767,'Harry','Manager',1500.0909))); + +insert into anydata_tab values (110, + Sys.AnyData.ConvertCollection(phone_list(9774567878,4075689000,1238761020))); + +insert into anydata_tab values (120, + Sys.AnyData.ConvertCollection(date_list('01-JAN-1910','02-FEB-1920','03-MAR-1930')) ); + +commit ; + +--*********************************************************** +-- Procedures to display AnyData information. +--*********************************************************** + +--Procedure takes in two parameters , first is an AnyData , second +--is a number to indicate whether it has to be described piecewise +--or not . + +create or replace procedure display_anydata_value( ad in sys.AnyData,piece_wise in number ) as +an sys.AnyType ; +ad2 sys.AnyData ; +type_code pls_integer ; +type_name varchar2(30); +rtn_val pls_integer ; +n1 number ; +fl1 number(10,4) ; +vc1 varchar(10) ; +vc2 varchar2(30); +ch1 char(10) ; +d1 date ; +rw1 raw(10) ; +bl1 blob ; +cl1 clob ; +bf1 bfile ; +ob1 person_type ; +vry1 phone_list ; +nstd1 date_list ; +begin + +type_code := ad.GetType(an) ; +type_name := ad.GetTypeName() ; + +if (type_code = DBMS_TYPES.TYPECODE_NUMBER) then +begin + rtn_val := ad.GetNumber(n1) ; + dbms_output.put_line (' NUMBER : ' || n1) ; +end ; + +elsif (type_code = DBMS_TYPES.TYPECODE_VARCHAR) then +begin + rtn_val := ad.GetVarchar(vc1) ; + dbms_output.put_line (' VARCHAR : ' || vc1) ; +end ; + +elsif (type_code = DBMS_TYPES.TYPECODE_VARCHAR2) then +begin + rtn_val := ad.GetVarchar2(vc2) ; + dbms_output.put_line (' VARCHAR2 : ' || vc2) ; +end ; + +elsif (type_code = DBMS_TYPES.TYPECODE_CHAR) then +begin + rtn_val := ad.GetChar(ch1) ; + dbms_output.put_line (' CHAR : ' || ch1) ; +end ; + +elsif (type_code = DBMS_TYPES.TYPECODE_DATE) then +begin + rtn_val := ad.GetDate(d1) ; + dbms_output.put_line (' DATE : ' || d1 ) ; +end ; + +elsif (type_code = DBMS_TYPES.TYPECODE_RAW) then +begin + rtn_val := ad.GetRaw(rw1); + dbms_output.put_line (' RAW : ' || rw1 ) ; +end ; + +elsif (type_code = DBMS_TYPES.TYPECODE_BLOB) then +begin + rtn_val := ad.GetBlob(bl1); + dbms_output.put_line (' BLOB : ' || dbms_lob.substr(bl1) ); +end ; + +elsif (type_code = DBMS_TYPES.TYPECODE_CLOB) then +begin + rtn_val := ad.GetClob(cl1); + dbms_output.put_line (' CLOB : ' || dbms_lob.substr(cl1) ); +end ; + +elsif (type_code = DBMS_TYPES.TYPECODE_BFILE) then +declare + amt pls_integer ; + offset pls_integer := 1 ; + bff raw(100) ; +begin + + rtn_val := ad.GetBfile(bf1); + dbms_lob.fileopen(bf1,dbms_lob.file_readonly); + amt := dbms_lob.getlength(bf1) ; + dbms_lob.read(bf1,amt,offset,bff); + dbms_output.put_line (' BFILE : ' || utl_raw.cast_to_varchar2(bff) ); + dbms_lob.filecloseall; +end ; + +elsif (type_code = DBMS_TYPES.TYPECODE_OBJECT) then +begin + type_name := ad.GetTypeName() ; + if(type_name like '%PERSON_TYPE%' ) then + begin + if(piece_wise = 0 ) then + begin + dbms_output.put_line(' Accessing the whole ADT1 ' ) ; + rtn_val := ad.GetObject(ob1) ; + dbms_output.put_line('ADT1: ' || ob1.ssn || ' ' || ob1.name || + ' ' || ob1.job || ' ' || ob1.salary ) ; + end ; + elsif (piece_wise =1 ) then + begin + dbms_output.put_line(' Accessing ADT1 Piecewise ' ); + ad2 := ad ; + ad2.PieceWise(); + rtn_val := ad2.GetNumber(n1); + rtn_val := ad2.GetVarChar2(vc2); + rtn_val := ad2.GetChar(ch1); + rtn_val := ad2.GetNumber(fl1); + dbms_output.put_line('ADT1: ' || n1 || ' ' || vc2 || ' ' || + ch1 || ' ' || n1 ); + end ; + end if ; + end ; + end if ; +end ; +elsif (type_code = DBMS_TYPES.TYPECODE_NAMEDCOLLECTION) then +begin + type_name := ad.GetTypeName() ; + if(type_name like '%PHONE_LIST%') then + begin + dbms_output.put_line(' Accessing the whole VARRAY ' ); + rtn_val := ad.GetCollection(vry1); + for i in 1..vry1.count loop + dbms_output.put_line('phone_list(' || i || ') ' || vry1(i) ) ; + end loop ; + end ; + elsif (type_name like '%DATE_LIST%' ) then + begin + dbms_output.put_line(' Accessing the whole Nested Table ' ); + rtn_val := ad.GetCollection(nstd1) ; + for i in 1..nstd1.count loop + dbms_output.put_line(' NSTD1(' || i || ') ' || nstd1(i) ) ; + end loop ; + end ; + end if ; +end ; +end if ; +end ; +/ + +--*********************************************************** +-- Dsiplay AnyData stored in table +--*********************************************************** + +declare +ad Sys.AnyData ; +begin +for i in 1..12 loop + begin + select col2 into ad from anydata_tab where col1=i*10 ; + dbms_output.put_line('************************************') ; + dbms_output.put_line(' Display row ' || i*10 ) ; + dbms_output.put_line('************************************') ; + display_anydata_value(ad,0) ; + exception when others then + dbms_output.put_line(SQLERRM) ; + end ; +end loop ; +end ; +/ + +declare +ad Sys.AnyData ; +begin +select col2 into ad from anydata_tab where col1=100 ; +dbms_output.put_line('************************************') ; +dbms_output.put_line(' Display ADT piecewise ') ; +dbms_output.put_line('************************************') ; +display_anydata_value(ad,1) ; +end ; +/ +--*********************************************************** +-- Create AnyData of LOBs in PL/SQL blocks and display data +--*********************************************************** + +declare +ad sys.anydata ; +begin +ad := Sys.AnyData.ConvertBlob(to_blob('AABB98076')) ; +display_anydata_value(ad,0) ; +end ; +/ + +declare +ad sys.anydata ; +begin +ad := Sys.AnyData.ConvertClob('eighty') ; +display_anydata_value(ad,0) ; +end ; +/ + +--*********************************************************** +-- Create transient AnyData and display its value +--*********************************************************** + +declare +a1 SYS.AnyType; +a2 SYS.AnyType; +ad1 Sys.AnyData; +ad2 Sys.AnyData; +begin +a1 := SYS.AnyType.GetPersistent('ANYDATA_USER','PERSON_TYPE') ; +Sys.AnyData.BeginCreate(a1,ad1) ; +ad1.SetNumber(678905435,FALSE); +ad1.SetVarChar2('Emily',FALSE); +ad1.SetChar('DIRECTOR',FALSE) ; +ad1.SetNumber(1020.20,FALSE); +ad1.EndCreate(); +begin + --Inserting transient type into table not supported. + --This will raise an error . + insert into anydata_tab values (130,ad1) ; +exception when others then + dbms_output.put_line(SQLERRM); +end ; +display_anydata_value(ad1,1) ; +end ; +/ + +CONNECT system/manager; +DROP USER ANYDATA_USER CASCADE ; + +SET SERVEROUTPUT OFF +SET ECHO OFF + diff --git a/anydset.sql b/anydset.sql new file mode 100644 index 0000000..5d9b305 --- /dev/null +++ b/anydset.sql @@ -0,0 +1,246 @@ +Rem +Rem $Header: anydset.sql 31-oct-2006.13:41:39 ytsai Exp $ +Rem +Rem anydset.sql +Rem +Rem Copyright (c) 2006, Oracle. All rights reserved. +Rem +Rem NAME +Rem anydset.sql - Demonstrates Sys.AnyDataSet feature . +Rem +Rem DESCRIPTION +Rem Sys.AnyDataSet contains Type description as well as a +Rem set of values . This demo shows its usage. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ytsai 10/31/06 - fix connect +Rem sjanardh 05/02/01 - Merged sjanardh_trans_adddemo +Rem sjanardh 04/30/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +CONNECT system/manager; +DROP USER ANYDSET_USER CASCADE ; +GRANT CONNECT,RESOURCE,DBA TO ANYDSET_USER IDENTIFIED BY ANYDSET_USER ; +CONNECT ANYDSET_USER/ANYDSET_USER + +SET ECHO ON +SET SERVEROUTPUT ON SIZE 200000 + +--*********************************************************** +-- This demonstrates the usage of Sys.AnyDataSet +--*********************************************************** + +create type person_type as object ( +ssn number , +name varchar2(20), +job clob , +salary number(10,4) +); +/ +create type phone_list as varray(100) of number ; +/ +create type address_type as object ( +apt integer , +street char(30) , +state char(2) , +zip number(5) +); +/ +create type address_list as table of address_type ; +/ + +--*********************************************************** +-- Creates Procedure to display AnyDataSet value +--*********************************************************** + +create or replace procedure anydataset_display_value +(anyset in Sys.AnyDataSet ) as +as1 Sys.AnyDataSet ; +tn varchar2(30) ; +tp varchar2(30) ; +ct number ; +rtn_val pls_integer ; +rw1 raw(30); +cl1 clob ; +o1 person_type ; +o2 address_type ; +vr phone_list ; +nt address_list ; +begin + +as1 := anyset ; +tn := as1.GetTypeName() ; +ct := as1.GetCount() ; + +if (tn = 'SYS.RAW' ) then +begin + for i in 1..ct loop + rtn_val := as1.GetInstance(); + rtn_val := as1.GetRaw(rw1); + dbms_output.put_line(rw1); + end loop ; +end ; +elsif (tn = 'SYS.CLOB' ) then +begin + for i in 1..ct loop + rtn_val := as1.GetInstance(); + rtn_val := as1.GetClob(cl1); + if (cl1 is null) then + dbms_output.put_line(' CLOB is NULL ' ); + else + dbms_output.put_line(dbms_lob.substr(cl1)); + end if ; + end loop ; +end ; +elsif (tn like '%PERSON_TYPE%' ) then +begin + for i in 1..ct loop + rtn_val := as1.GetInstance(); + rtn_val := as1.GetObject(o1); + dbms_output.put_line ('PERSON_TYPE ' || o1.ssn || ' ' || o1.name + || ' ' || dbms_lob.substr(o1.job) || ' ' || o1.salary ) ; + end loop ; +end ; +elsif (tn like '%PHONE_LIST%' ) then +begin + for i in 1..ct loop + rtn_val := as1.GetInstance(); + rtn_val := as1.GetCollection(vr); + for j in 1..vr.count loop + dbms_output.put_line ('PHONE_LIST(' || j || ') ' || vr(j) ) ; + end loop ; + end loop ; +end ; +elsif (tn like '%ADDRESS_LIST%' ) then +begin + for i in 1..ct loop + rtn_val := as1.GetInstance(); + rtn_val := as1.GetCollection(nt); + for j in 1..nt.count loop + dbms_output.put_line ('ADDRESS_TYPE(' || j || ') ' || nt(j).apt || ' ' || + dbms_lob.substr(nt(j).street) || ' ' || nt(j).state || ' ' || nt(j).zip ) ; + end loop ; + end loop ; +end ; + +end if ; +end ; +/ +show errors + +--*********************************************************** +-- Creates AnyDataSet,sets value and displays the value +--*********************************************************** + +declare +as1 Sys.AnyDataSet; +at1 Sys.AnyType ; +rw1 raw(200) ; +begin +Sys.AnyDataSet.BeginCreate(DBMS_TYPES.TYPECODE_RAW,at1,as1); +for i in 1..30 loop + as1.AddInstance(); + rw1 := utl_raw.cast_to_raw(rpad('0123',i,'0123')) ; + as1.SetRaw(rw1); +end loop ; +as1.EndCreate(); +anydataset_display_value(as1); +end ; +/ + +declare +as1 Sys.AnyDataSet; +at1 Sys.AnyType ; +cl1 clob ; +begin +Sys.AnyDataSet.BeginCreate(DBMS_TYPES.TYPECODE_CLOB,at1,as1); +for i in 1..10 loop + as1.AddInstance(); + cl1 := to_clob(rpad('Clob',i*10,'Clob')) ; + as1.SetClob(cl1) ; +end loop ; +as1.EndCreate(); +anydataset_display_value(as1); +end ; +/ + +declare +as1 Sys.AnyDataSet; +at1 Sys.AnyType ; +begin +at1 := Sys.AnyType.GetPersistent('ANYDSET_USER','PERSON_TYPE') ; +Sys.AnyDataSet.BeginCreate(DBMS_TYPES.TYPECODE_OBJECT,at1,as1); +as1.AddInstance(); +as1.SetObject(Person_type(1237659012,'Betty','HR Manager',80999.00)); +as1.AddInstance(); +as1.SetObject(Person_type(8097659100,'Clark',null,null)); +as1.AddInstance(); +as1.PieceWise() ; +as1.SetNumber(1023040078); +as1.SetVarchar2('James'); +as1.SetClob('ADMINISTRAIVE ASSIST'); +as1.SetNumber(60000.00); +as1.EndCreate(); +anydataset_display_value(as1); +end ; +/ + +declare +as1 Sys.AnyDataSet; +at1 Sys.AnyType ; +begin +at1 := Sys.AnyType.GetPersistent('ANYDSET_USER','PHONE_LIST'); +Sys.AnyDataSet.BeginCreate(DBMS_TYPES.TYPECODE_NAMEDCOLLECTION,at1,as1); +as1.AddInstance(); +as1.SetCollection(PHONE_LIST(8095067000,0012034511,null)); +as1.AddInstance(); +as1.SetCollection(PHONE_LIST(3014556780,9012331099,1003073087,1105067890)); +as1.EndCreate(); +anydataset_display_value(as1); +end ; +/ + +declare +as1 Sys.AnyDataSet; +at1 Sys.AnyType ; +begin +at1 := Sys.AnyType.GetPersistent('ANYDSET_USER','ADDRESS_LIST'); +Sys.AnyDataSet.BeginCreate(DBMS_TYPES.TYPECODE_NAMEDCOLLECTION,at1,as1); +as1.AddInstance(); +as1.SetCollection(ADDRESS_LIST(ADDRESS_TYPE(113,'ABC','MA',90878),ADDRESS_TYPE(45,'DFG','MI',80912)) ); +as1.AddInstance(); +as1.PieceWise(); +as1.SetObject(ADDRESS_TYPE(12,'NBC','TX',10764)); +as1.SetObject(ADDRESS_TYPE(70,'MNS','CA',94067),TRUE) ; +as1.EndCreate(); +anydataset_display_value(as1); +end ; +/ + + +--*********************************************************** +-- Drop objects created , user etc. +--*********************************************************** + +drop type address_list ; +drop type phone_list ; +drop type address_type ; +drop type person_type ; + +CONNECT system/manager; +DROP USER ANYDSET_USER CASCADE ; + +SET SERVEROUTPUT OFF +SET ECHO OFF + diff --git a/anytype.sql b/anytype.sql new file mode 100644 index 0000000..ca34a50 --- /dev/null +++ b/anytype.sql @@ -0,0 +1,421 @@ +Rem +Rem $Header: anytype.sql 31-oct-2006.13:41:17 ytsai Exp $ +Rem +Rem anytype.sql +Rem +Rem Copyright (c) 2001, 2006, Oracle. All rights reserved. +Rem +Rem NAME +Rem anytype.sql - Demonstrates Sys.AnyType feature . +Rem +Rem DESCRIPTION +Rem Sys.AnyType stores Type descriptions and this demo +Rem shows its usage . +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ytsai 10/31/06 - fix connect +Rem sjanardh 08/03/01 - Fix CSID part. +Rem sjanardh 05/02/01 - Merged sjanardh_trans_adddemo +Rem sjanardh 05/02/01 - +Rem sjanardh 04/30/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +CONNECT system/manager; +DROP USER ANYTYPE_USER CASCADE ; + +GRANT CONNECT,RESOURCE,DBA TO ANYTYPE_USER IDENTIFIED BY ANYTYPE_USER ; +CONNECT ANYTYPE_USER/ANYTYPE_USER + +SET ECHO ON +SET SERVEROUTPUT ON SIZE 20000 + +--*********************************************************** +-- This demonstrates the usage of Sys.AnyType +--*********************************************************** + +--Creating types required for the demo. + +create type object_type1 as object ( +col1 number , +col2 varchar2(30) , +col3 clob , +col4 raw(10) +); +/ + +create type object_type2 as object ( +col1 number , +col2 blob +); +/ + +create type object_type3 as object ( +col1 char(20), +col2 date +); +/ + +create type object_type4 as object ( +number_col number , +object_col object_type1 +); +/ + +create type varray_type1 as varray(5) of date ; +/ +create type varray_type2 as varray(5) of object_type2 ; +/ + +create type nstd_type1 as table of number ; +/ +create type nstd_type2 as table of object_type4 ; +/ + +--*********************************************************** +--Procedures to display AnyType information. +--*********************************************************** + +create procedure display_anytype_info(an in sys.anytype) as +rtn number ; +pr pls_integer ; +sc pls_integer ; +ln pls_integer ; +cs pls_integer ; +cf pls_integer ; +sch varchar2(30) ; +tn varchar2(30) ; +vr varchar2(30) ; +cn pls_integer ; +csid pls_integer ; +begin + --Get the character set id of database character set . + select nls_charset_id(value) into csid from nls_database_parameters + where parameter='NLS_CHARACTERSET' ; + + rtn := an.GetInfo(pr,sc,ln,cs,cf,sch,tn,vr,cn) ; + + dbms_output.put_line('- Precision ' || pr ) ; + dbms_output.put_line('- Scale ' || sc ) ; + dbms_output.put_line('- Length ' || ln ) ; + if (cs is not null ) then + begin + if (cs = csid ) then + dbms_output.put_line('- CSID is same as db charset id' ) ; + else + dbms_output.put_line('- CSID is not same as db charset id') ; + end if ; + end ; + else + dbms_output.put_line('- CSID is null ' ) ; + end if ; + dbms_output.put_line('- CSFRM ' || cf ) ; + dbms_output.put_line('- Schema ' || sch) ; + dbms_output.put_line('- Type name ' || tn ) ; + dbms_output.put_line('- Version ' || vr ) ; + dbms_output.put_line('- Count ' || cn ) ; +end ; +/ + +create or replace procedure display_attribute_element_info(an1 in sys.anytype) as +an sys.anytype ; +rtn number ; +pos pls_integer ; +pr pls_integer ; +sc pls_integer ; +ln pls_integer ; +cs pls_integer ; +cf pls_integer ; +sch varchar2(20) ; +tn varchar2(20) ; +vr varchar2(30) ; +cn pls_integer ; +name varchar2(30) ; +j number ; +csid pls_integer ; +begin + --Get the character set id of database character set . + select nls_charset_id(value) into csid from nls_database_parameters + where parameter='NLS_CHARACTERSET' ; + + --Get the count , number of elements. + rtn := an1.GetInfo(pr,sc,ln,cs,cf,sch,tn,vr,cn) ; + + --For nested table type count is null. + if (cn is null ) then + cn := 1 ; + end if ; + + for j in 1..cn loop + begin + + --Get attribute element information. + rtn := an1.GetAttreleminfo(j,pr,sc,ln,cs,cf,an,name) ; + + dbms_output.put_line(' -------------------- '); + dbms_output.put_line(' COLUMN ' || name ); + + --Attribute is returned as an AnyType in variable an. + --If it is not null then we want to describe it . + if (an is not null) then + dbms_output.put_line(' - '); + dbms_output.put_line(' desc ' || name ); + --Display information of attribute + display_anytype_info(an) ; + dbms_output.put_line(' - '); + end if ; + + --Rest of the information . + dbms_output.put_line(' Precision ' || pr ) ; + dbms_output.put_line(' Scale ' || sc ) ; + dbms_output.put_line(' Length ' || ln ) ; + if (cs is not null ) then + begin + if (cs = csid ) then + dbms_output.put_line('- CSID is same as db charset id' ) ; + else + dbms_output.put_line('- CSID is not same as db charset id') ; + end if ; + end ; + else + dbms_output.put_line('- CSID is null ' ) ; + end if ; + dbms_output.put_line(' CSFRM ' || cf ) ; + dbms_output.put_line(' -------------------- '); + + exception + when others then + dbms_output.put_line(SQLERRM); + end ; + end loop ; +end ; +/ + + +--*********************************************************** +-- The following blocks show how to create AnyTypes from +-- from persistent database types . +--*********************************************************** + +--For object_type1 +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','OBJECT_TYPE1'); + display_anytype_info(any_type1); +end; +/ +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','OBJECT_TYPE1'); + display_attribute_element_info(any_type1); +end ; +/ + +--For object_type2 +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','OBJECT_TYPE2'); + display_anytype_info(any_type1); +end; +/ +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','OBJECT_TYPE2'); + display_attribute_element_info(any_type1); +end ; +/ + +--For object_type3 +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','OBJECT_TYPE3'); + display_anytype_info(any_type1); +end; +/ +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','OBJECT_TYPE3'); + display_attribute_element_info(any_type1); +end ; +/ + +--For object_type4 +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','OBJECT_TYPE4'); + display_anytype_info(any_type1); +end; +/ +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','OBJECT_TYPE4'); + display_attribute_element_info(any_type1); +end ; +/ + +--For varray_type1 +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','VARRAY_TYPE1'); + display_anytype_info(any_type1); +end; +/ +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','VARRAY_TYPE1'); + display_attribute_element_info(any_type1); +end ; +/ + +--For varray_type2 +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','VARRAY_TYPE2'); + display_anytype_info(any_type1); +end; +/ +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','VARRAY_TYPE2'); + display_attribute_element_info(any_type1); +end ; +/ + +--For nstd_type1 +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','NSTD_TYPE1'); + display_anytype_info(any_type1); +end; +/ +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','NSTD_TYPE1'); + display_attribute_element_info(any_type1); +end ; +/ + +--For nstd_type1 +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','NSTD_TYPE2'); + display_anytype_info(any_type1); +end; +/ +declare +any_type1 Sys.AnyType ; +begin + any_type1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','NSTD_TYPE2'); + display_attribute_element_info(any_type1); +end ; +/ + +--*********************************************************** +-- Create Transient AnyTypes in PL/SQL blocks . +--*********************************************************** + +--Transient AnytType of Date . +declare +an1 sys.anytype ; +begin + Sys.AnyType.BeginCreate(DBMS_TYPES.TYPECODE_DATE,an1) ; + an1.SetInfo(null,null,null,null,null,null,null); + an1.EndCreate() ; + display_anytype_info(an1); +end ; +/ + +--Transient AnytType of Varchar. +declare +an1 sys.anytype ; +begin + Sys.AnyType.BeginCreate(DBMS_TYPES.TYPECODE_VARCHAR,an1) ; + an1.SetInfo(null,null,20,null,null,null,null); + an1.EndCreate() ; + display_anytype_info(an1); +end ; +/ + +--Transient AnytType of Object type. +declare +an2 Sys.AnyType ; +begin + Sys.AnyType.BeginCreate(DBMS_TYPES.TYPECODE_OBJECT,an2) ; + an2.AddAttr('COL1',DBMS_TYPES.TYPECODE_NUMBER,null,null,null,null,null); + an2.AddAttr('COL2',DBMS_TYPES.TYPECODE_CLOB,null,null,null,null,null); + an2.AddAttr('COL3',DBMS_TYPES.TYPECODE_DATE,null,null,null,null,null); + an2.EndCreate() ; + display_anytype_info(an2); + display_attribute_element_info(an2); +end ; +/ + +--Transient AnytType of Collection type. +declare +an1 Sys.AnyType ; +begin + Sys.AnyType.BeginCreate(DBMS_TYPES.TYPECODE_NAMEDCOLLECTION,an1); + an1.SetInfo(null,null,null,null,null,null,DBMS_TYPES.TYPECODE_RAW,0) ; + an1.EndCreate() ; + display_anytype_info(an1); +end ; +/ + +--Transient AnytType of Persistent types. +declare +an1 Sys.AnyType ; +an2 Sys.AnyType ; +begin + an1 := Sys.AnyType.GetPersistent('ANYTYPE_USER','OBJECT_TYPE1'); + Sys.AnyType.BeginCreate(DBMS_TYPES.TYPECODE_NAMEDCOLLECTION,an2); + an2.SetInfo(null,null,null,null,null,an1,DBMS_TYPES.TYPECODE_OBJECT,0); + an2.EndCreate() ; + display_anytype_info(an2); +end ; +/ + +--*********************************************************** +-- Drop all objects created for the demo. +--*********************************************************** + +drop type varray_type1 ; +drop type varray_type2 ; +drop type nstd_type1 ; +drop type nstd_type2 ; +drop type object_type4 ; +drop type object_type3 ; +drop type object_type2 ; +drop type object_type1 ; + +CONNECT system/manager; +DROP USER ANYTYPE_USER CASCADE ; + +set serveroutput off +set echo off + + diff --git a/aqbzdemo.tar b/aqbzdemo.tar new file mode 100644 index 0000000..77bcf2f Binary files /dev/null and b/aqbzdemo.tar differ diff --git a/aqdemo00.sql b/aqdemo00.sql new file mode 100644 index 0000000..2be58ad --- /dev/null +++ b/aqdemo00.sql @@ -0,0 +1,216 @@ +Rem +Rem $Header: aqdemo00.sql 16-nov-2004.15:59:53 rbhyrava Exp $ +Rem +Rem aqdemo01.sql +Rem +Rem Copyright (c) 2000, 2004, Oracle. All rights reserved. +Rem +Rem NAME +Rem aqdemo01.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbhyrava 11/16/04 - create user +Rem lzhao 06/26/01 - set echo off for aqdemo01, aqdemo03 +Rem rbhyrava 04/29/01 - add comments for aqdemo08, aqdemo09 +Rem rbhyrava 01/26/01 - obselete job_queue_interval +Rem rbhyrava 07/10/00 - Bug - 1319922 +Rem rbhyrava 07/10/00 - Created +Rem +Rem +Rem aqdemo00.sql +Rem +Rem Copyright (c) 2000, 2004, Oracle. All rights reserved. +Rem +Rem NAME +Rem aqdemo00.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem +rem NAME +rem aqdemo00.sql +rem +rem DESCRIPTION +rem This set of scripts serve as an example for building an +rem application, using Oracle Advanced Queues, to perform +rem asynchronous database operations. +rem +rem The scripts do the following: +rem +rem aqdemo00 +rem 1) Create aquser as an user of AQ +rem 2) Create tables prog1_processed_data, prog2_processed_data and +rem prog3_processed_data +rem +rem aqdemo01 +rem 1) Create two queue tables - input_queue_table, prop_queue_table +rem 2) Create two queues - input_queue belonging to input_queue_table, +rem prop_queue belonging to prop_queue_table +rem 3) Create two subscribers to input_queue - prog1, prog2 +rem 4) Create one subscribers to input_queue - prog3 at prop_queue +rem 5) Schedule propagation between input_queue and other queues in +rem the database +rem +rem aqdemo02 +rem 1) Enqueue 100 messages into the input_queue +rem +rem aqdemo03 +rem 1) Installs the dequeue procedures +rem +rem aqdemo04 +rem 1) prog3 performs a blocking dequeue from prop_queue. Messages +rem in prop_table were propagated from input_queue. +rem +rem aqdemo05 +rem 1) A listener program listens on input_table and calls +rem prog1 or prog2 to dequeue from input_queue based on the +rem kind of message received. +rem +rem aqdemo06 +rem 1) This script cleans up all the tables, types, queues, +rem queue_tables, users etc. created by +rem aqdemo00 - aqdemo05 +rem +rem aqdemo07 +rem 1) This script demonstates using XMLType queues and +rem dequeue, subscribe using XPATH expressions on XMLType datatype +rem aqdemo07 +rem +rem aqdemo08 +rem 1) This script demonstrates using Server to Server , Email +rem notifications with default presentation of XML presentation +rem Modify email host and sender info before running the demo. +rem aqdemo08 +rem +rem NOTES +rem This file contains the sql script that drives the demo. +rem Before running the demo, add the following lines to +rem your init.ora file: +rem ## compatible can be 8.1.0 or higher +rem compatible = 8.1.0 +rem aq_tm_processes = 1 +rem job_queue_processes = 2 +rem shutdown and restart the database. +rem +rem Run this demo as SYS using SQLPLUS. Just login as SYS +rem in SQLPLUS and type '@aqdemo00'. +rem aqdemo00 calls aqdemo01 and aqdemo03. +rem +rem Log into another SQLPUS session and type '@aqdemo02'. +rem This enqueus 100 messages into input_queue +rem +rem Log into another SQLPLUS session and type '@aqdemo04'. +rem This program blocks on prop_queue for approxmately 2 minutes and +rem dequeues messages. +rem +rem Log into another SQLPLUS session and type '@aqdemo05'. +rem This program listens for approxmately 2 minutes on input_queue +rem and calls the dequeue for prog1 and prog2 appropriately. +rem +rem aqdemo02(enqueue), aqdemo04(blocking dequeue) and +rem aqdemo05(listen) can be run concurrently +rem +rem aqdemo06(cleanup script) has to be run by SYS. +rem Login as SYS in SQLPLUS and type '@aqdemo06'. +rem + +set serveroutput on +set echo on +spool aqdemo00.log +rem ==================================================================== +rem create a queue user +rem ==================================================================== + +drop user aquser cascade ; +create user aquser identified by aquser; +grant connect, resource, aq_administrator_role to aquser; + +grant execute on dbms_aq to aquser +/ +grant execute on dbms_aqadm to aquser +/ +grant execute on dbms_lock to aquser +/ + + +connect aquser/aquser +set serveroutput on +set echo on + +rem ==================================================================== +rem +rem Create a type +rem +rem ==================================================================== + +create type message as object ( + id NUMBER, + city VARCHAR2(30), + priority NUMBER) +/ + +rem ==================================================================== +rem +rem Create the table to store the dequeued data +rem +rem ==================================================================== +drop table prog1_processed_data +/ +drop table prog2_processed_data +/ +drop table prog3_processed_data +/ + +create table prog1_processed_data +( + id NUMBER, + city VARCHAR2(30), + priority NUMBER +) +/ + +create table prog2_processed_data +( + id NUMBER, + city VARCHAR2(30), + priority NUMBER +) +/ + +create table prog3_processed_data +( + id NUMBER, + city VARCHAR2(30), + priority NUMBER +) +/ + +rem ==================================================================== +rem Setup complete +rem ==================================================================== + + +rem Set up queue tables, queues, subscribers etc. +set echo off +@@aqdemo01.sql +rem Load dequeue procedures +set echo off +@@aqdemo03.sql + + + +rem ==================================================================== +rem Setup complete +rem ==================================================================== + +spool off diff --git a/aqdemo01.sql b/aqdemo01.sql new file mode 100644 index 0000000..6c5f5a2 --- /dev/null +++ b/aqdemo01.sql @@ -0,0 +1,374 @@ +Rem +Rem $Header: template.sql 06-feb-96.13:23:14 kosinski Exp $ +Rem +Rem aqdemo01.sql +Rem +Rem Copyright (c) Oracle Corporation 2000. All Rights Reserved. +Rem +Rem NAME +Rem aqdemo01.sql - +Rem +Rem DESCRIPTION +rem This file creates queue tables, queues, subscribers needed for +rem the demo. Propagation is scheduled between input_queue and other +rem queues in the same database +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbhyrava 07/10/00 - Created - bug :1319922 +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem kmeiyyap 09/15/98 - Created +Rem + +rem Create Queue table, Queues, Subscribers + +connect aquser/aquser +set serveroutput on +set echo on + +rem ============================== +rem Error Handling Routine +rem ============================== + +CREATE or REPLACE PROCEDURE catch_error ( error_code in number, + error_string in varchar2) +AS +BEGIN + dbms_output.put_line('Oracle Server Error = '|| to_char (error_code)); + dbms_output.put_line('Oracle Server Message = '|| error_string); +END; +/ + + + +rem ========================================== +rem Stop Queue input_queue +rem ========================================== + +DECLARE +BEGIN + dbms_output.put_line ('Stopping Queue input_queue...'); + dbms_aqadm.stop_queue + ( + queue_name => 'input_queue', + wait => TRUE + ); + + dbms_output.put_line ('Stopped Queue input_queue.'); + +exception + when others then + catch_error(SQLCODE, 'Stop Queue ' || substr(SQLERRM, 1, 256)); + +END; +/ + +rem ========================================== +rem Stop Queue prop_queue +rem ========================================== + +DECLARE +BEGIN + dbms_output.put_line ('Stopping Queue prop_queue...'); + dbms_aqadm.stop_queue + ( + queue_name => 'prop_queue', + wait => TRUE + ); + + dbms_output.put_line ('Stopped Queue prop_queue.'); + +exception + when others then + catch_error(SQLCODE, 'Stop Queue ' || substr(SQLERRM, 1, 256)); + +END; +/ + +rem ========================================== +rem Drop Queue input_queue +rem ========================================== + +DECLARE +BEGIN + dbms_output.put_line ('Dropping Queue input_queue...'); + dbms_aqadm.drop_queue + ( + queue_name => 'input_queue' + ); + + dbms_output.put_line ('Dropped Queue input_queue.'); + +exception + when others then + catch_error(SQLCODE, 'Drop Queue ' || substr(SQLERRM, 1, 256)); + +END; +/ + + +rem ========================================== +rem Drop Queue prop_queue +rem ========================================== + +DECLARE +BEGIN + dbms_output.put_line ('Dropping Queue prop_queue...'); + dbms_aqadm.drop_queue + ( + queue_name => 'prop_queue' + ); + + dbms_output.put_line ('Dropped Queue prop_queue.'); + +exception + when others then + catch_error(SQLCODE, 'Drop Queue ' || substr(SQLERRM, 1, 256)); + +END; +/ + +rem ========================================== +rem Drop Input Queue Table +rem ========================================== + +DECLARE +BEGIN + dbms_output.put_line ('Dropping Queue Table input_queue_table...'); + dbms_aqadm.drop_queue_table + ( + queue_table => 'input_queue_table', + force => TRUE + ); + + dbms_output.put_line ('Dropped Queue Table input_queue_table.'); + +exception + when others then + catch_error(SQLCODE, 'Drop Queue Table ' || substr(SQLERRM, 1, 256)); + +END; +/ + + +rem ========================================== +rem Drop Prop Queue Table +rem ========================================== + +DECLARE +BEGIN + dbms_output.put_line ('Dropping Queue Table prop_queue_table...'); + dbms_aqadm.drop_queue_table + ( + queue_table => 'prop_queue_table', + force => TRUE + ); + + dbms_output.put_line ('Dropped Queue Table prop_queue_table.'); + +exception + when others then + catch_error(SQLCODE, 'Drop Queue Table ' || substr(SQLERRM, 1, 256)); + +END; +/ +rem ========================================== +rem Create a queue table input_queue_table +rem ========================================== + +DECLARE +BEGIN + dbms_output.put_line ('Creating Queue Table input_queue_table...'); + + dbms_aqadm.CREATE_queue_table( + queue_table => 'input_queue_table', + multiple_consumers => TRUE, + queue_payload_type => 'message', + compatible => '8.1.3', + comment => 'Creating input queue table'); + + + dbms_output.put_line ('Created Queue Table input_queue_table.'); + +exception + when others then + catch_error(SQLCODE, 'Create Queue Table ' || substr(SQLERRM, 1, 256)); + +END; +/ + +rem ========================================== +rem Create a queue table prop_queue_table +rem ========================================== + +DECLARE +BEGIN + dbms_output.put_line ('Creating Queue Table prop_queue_table...'); + + dbms_aqadm.CREATE_queue_table( + queue_table => 'prop_queue_table', + multiple_consumers => TRUE, + queue_payload_type => 'message', + compatible => '8.1.3', + comment => 'Creating prop queue table'); + + dbms_output.put_line ('Created Queue Table prop_queue_table.'); + +exception + when others then + catch_error(SQLCODE, 'Create Queue Table ' || substr(SQLERRM, 1, 256)); + +END; +/ + + +rem ========================================== +rem Create a queue input_queue +rem ========================================== + +DECLARE +BEGIN + + dbms_output.put_line ('Creating Queue input_queue...'); + + dbms_aqadm.CREATE_queue( + queue_name => 'input_queue', + queue_table => 'input_queue_table', + comment => 'Demo Queue'); + + dbms_output.put_line ('Created Queue input_queue.'); + +exception + when others then + catch_error(SQLCODE, 'Create Queue ' || substr(SQLERRM, 1, 256)); + +END; +/ + + +rem ========================================== +rem Create a queue prop_queue +rem ========================================== + +DECLARE +BEGIN + + dbms_output.put_line ('Creating Queue prop_queue...'); + + dbms_aqadm.CREATE_queue( + queue_name => 'prop_queue', + queue_table => 'prop_queue_table', + comment => 'Propagation Queue'); + + dbms_output.put_line ('Created Queue prop_queue.'); + +exception + when others then + catch_error(SQLCODE, 'Create Queue ' || substr(SQLERRM, 1, 256)); + +END; +/ + +rem ==================================== +rem Start input queue input_queue +rem ==================================== + +DECLARE +BEGIN + + dbms_output.put_line('starting queue input_queue...'); + + dbms_aqadm.start_queue( + queue_name => 'input_queue'); + + dbms_output.put_line ('Started Queue input_queue.'); + +exception + when others then + catch_error(SQLCODE, 'Start Queue ' || substr(SQLERRM, 1, 256)); + +END; +/ + + +rem ==================================== +rem Start input queue prop_queue +rem ==================================== + +DECLARE +BEGIN + + dbms_output.put_line('starting Prop queue prop_queue...'); + + dbms_aqadm.start_queue( + queue_name => 'prop_queue'); + + dbms_output.put_line ('Started Queue prop_queue.'); + +exception + when others then + catch_error(SQLCODE, 'Start Queue ' || substr(SQLERRM, 1, 256)); + +END; +/ + + +rem ======================================== +rem Create queue subscribers +rem ======================================== + +DECLARE + subscriber sys.aq$_agent; +BEGIN + subscriber := sys.aq$_agent('prog1', NULL, NULL); + dbms_aqadm.add_subscriber( + queue_name => 'input_queue', + subscriber => subscriber); + dbms_output.put_line ('Added subscriber prog1 to input_queue.'); +END; +/ + +DECLARE + subscriber1 sys.aq$_agent; +BEGIN + subscriber1 := sys.aq$_agent('prog2', NULL, NULL); + dbms_aqadm.add_subscriber( + queue_name => 'input_queue', + subscriber => subscriber1, + rule => 'priority > 2'); + dbms_output.put_line ('Added subscriber prog2 to input_queue.'); +END; +/ + +DECLARE + subscriber sys.aq$_agent; +BEGIN + subscriber := sys.aq$_agent('prog3', 'prop_queue', NULL); + dbms_aqadm.add_subscriber( + queue_name => 'input_queue', + subscriber => subscriber, + rule => 'priority = 2'); + dbms_output.put_line ('Added subscriber prog3@prop_queue to input_queue.'); +END; +/ + +rem ======================================== +rem Schedule propagation +rem ======================================== + +DECLARE +BEGIN + + dbms_aqadm.schedule_propagation( + queue_name => 'input_queue', + latency => '10'); + dbms_output.put_line ( + 'Scheduled propagation from input_queue to other queues.'); +END; +/ + +rem ======================================== +rem Setup complete +rem ======================================== diff --git a/aqdemo02.sql b/aqdemo02.sql new file mode 100644 index 0000000..d91f4e0 --- /dev/null +++ b/aqdemo02.sql @@ -0,0 +1,84 @@ +Rem +Rem $Header: template.sql 06-feb-96.13:23:14 kosinski Exp $ +Rem +Rem aqdemo02.sql +Rem +Rem Copyright (c) Oracle Corporation 2000. All Rights Reserved. +Rem +Rem NAME +Rem aqdemo02.sql - +Rem +Rem DESCRIPTION +rem This file loads the enqueue package and enqueues 100 messages +rem (10 messages are enqueued every 3 seconds to a maximum of 100 +rem messages). +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbhyrava 07/10/00 - Created - bug: 1319922 +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem kmeiyyap 01/27/99 - spool to aqdemo02.log +rem kmeiyyap 09/15/98 - Created +rem +rem +rem + +connect aquser/aquser +set serveroutput on +set echo on +spool aqdemo02.log + +CREATE OR REPLACE PROCEDURE DEMO_ENQUEUE (userinfo message, + priority number) AS + + enq_msgid RAW(16); + eopt dbms_aq.enqueue_options_t; + mprop dbms_aq.message_properties_t; + +BEGIN + mprop.priority := priority; + dbms_aq.enqueue( + queue_name => 'input_queue', + enqueue_options => eopt, + message_properties => mprop, + payload => userinfo, + msgid => enq_msgid); + + commit; + +END demo_enqueue; +/ + +DECLARE + payload message; + city1 varchar2(30) := 'BELMONT'; + city2 varchar2(30) := 'REDWOOD SHORES'; + city3 varchar2(30) := 'SUNNYVALE'; + city4 varchar2(30) := 'BURLINGAME'; + +BEGIN + for i in 1..100 LOOP + IF mod (i, 3) = 0 THEN + payload := message(i, city1, mod(i, 3) + 1); + ELSIF mod(i, 4) = 0 THEN + payload := message(i, city2, mod(i, 3) + 1); + ELSIF mod(i, 2) = 0 THEN + payload := message(i, city3, mod(i, 3) + 1); + ELSE + payload := message(i, city4, mod(i, 3) + 1); + END IF; + + demo_enqueue(payload, (mod(i, 3) + 1)); + + IF mod (i, 10) = 0 THEN + dbms_lock.sleep(3); + END IF; + + END LOOP; +END; +/ + + +spool off diff --git a/aqdemo03.sql b/aqdemo03.sql new file mode 100644 index 0000000..5d76072 --- /dev/null +++ b/aqdemo03.sql @@ -0,0 +1,117 @@ +Rem +Rem $Header: template.sql 06-feb-96.13:23:14 kosinski Exp $ +Rem +Rem aqdemo03.sql +Rem +Rem Copyright (c) Oracle Corporation 2000. All Rights Reserved. +Rem +Rem NAME +Rem aqdemo03.sql - +Rem +Rem DESCRIPTION +rem This file loads the dequeue packages demo_dequeue and +rem demo_prop_dequeue +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbhyrava 07/10/00 - bug: 1319922 +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem kmeiyyap 10/07/98 - added wait time for dequeue +rem kmeiyyap 09/15/98 - Created +rem + +connect aquser/aquser +set echo on +set serveroutput on + + +CREATE OR REPLACE PROCEDURE DEMO_DEQUEUE(appname varchar2) AS + deq_msgid RAW(16); + dopt dbms_aq.dequeue_options_t; + mprop dbms_aq.message_properties_t; + payload message; + no_messages exception; + pragma exception_init(no_messages, -25228); + +BEGIN + + dopt.consumer_name := appname; + dopt.wait := 30; + dopt.navigation := DBMS_AQ.FIRST_MESSAGE; + + + dbms_aq.dequeue( + queue_name => 'input_queue', + dequeue_options => dopt, + message_properties => mprop, + payload => payload, + msgid => deq_msgid); + + IF appname = 'prog1' THEN + insert into prog1_processed_data + values (payload.id, payload.city, payload.priority); + ELSIF appname = 'prog2' THEN + insert into prog2_processed_data + values (payload.id, payload.city, payload.priority); + END IF; + + commit; + +EXCEPTION + WHEN no_messages THEN + dbms_output.put_line('No more messages in queue '); + commit; + +END demo_dequeue; +/ + +CREATE OR REPLACE PROCEDURE DEMO_PROP_DEQUEUE (appname varchar2) AS + deq_msgid RAW(16); + dopt dbms_aq.dequeue_options_t; + mprop dbms_aq.message_properties_t; + payload message; + no_messages exception; + pragma exception_init(no_messages, -25228); + start_tx NUMBER; + finish_tx NUMBER; + +BEGIN + + dopt.consumer_name := appname; + dopt.wait := DBMS_AQ.NO_WAIT; + dopt.navigation := DBMS_AQ.FIRST_MESSAGE; + + start_tx := dbms_utility.get_time; + LOOP + + BEGIN + finish_tx := dbms_utility.get_time; + IF finish_tx - start_tx > 12000 THEN + exit; + END IF; + + dbms_aq.dequeue( + queue_name => 'prop_queue', + dequeue_options => dopt, + message_properties => mprop, + payload => payload, + msgid => deq_msgid); + + IF appname = 'prog3' THEN + insert into prog3_processed_data + values (payload.id, payload.city, payload.priority); + END IF; + + commit; + + EXCEPTION + WHEN no_messages THEN + null; + END; + + END LOOP; +END demo_prop_dequeue; +/ + diff --git a/aqdemo04.sql b/aqdemo04.sql new file mode 100644 index 0000000..a721222 --- /dev/null +++ b/aqdemo04.sql @@ -0,0 +1,40 @@ +Rem +Rem $Header: aqdemo04.sql 25-sep-2001.11:19:27 lzhao Exp $ +Rem +Rem aqdemo04.sql +Rem +Rem Copyright (c) 2000, 2001, Oracle Corporation. All rights reserved. +Rem +Rem NAME +Rem aqdemo04.sql - +Rem +Rem DESCRIPTION +rem Dequeue messages by blocking on prop_queue for prog3 for +rem approximately 2 minutes +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem lzhao 09/25/01 - set feedback on +Rem rbhyrava 07/10/00 - bug 1319922 +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem kmeiyyap 01/27/99 - spool to aqdemo04.log +rem kmeiyyap 09/15/98 - Created +rem +set feedback on +connect aquser/aquser +set serveroutput on +set echo on +spool aqdemo04.log + +DECLARE +BEGIN + demo_prop_dequeue('prog3'); +END; +/ + +rem Show the number of messages in prog3_processed_data table +select count(*) from prog3_processed_data; + +spool off diff --git a/aqdemo05.sql b/aqdemo05.sql new file mode 100644 index 0000000..4cd629e --- /dev/null +++ b/aqdemo05.sql @@ -0,0 +1,89 @@ +Rem +Rem $Header: aqdemo05.sql 25-sep-2001.11:19:28 lzhao Exp $ +Rem +Rem aqdemo05.sql +Rem +Rem Copyright (c) 2000, 2001, Oracle Corporation. All rights reserved. +Rem +Rem NAME +Rem aqdemo05.sql - +Rem +Rem DESCRIPTION +rem Listening on input_queue for messages for +rem agents "prog1" and "prog2" for approximately 2 minutes; +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem lzhao 09/25/01 - set feedback on +Rem rbhyrava 07/10/00 - Bug 1319922 +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem kmeiyyap 01/27/99 - type agent_list_t changed to aq$_agent_list_t +rem kmeiyyap 10/07/98 - Added waiting time for listen +rem kmeiyyap 09/15/98 - Created +rem +set feedback on +connect aquser/aquser +set serveroutput on +set echo on +spool aqdemo05.log + +DECLARE + qlist dbms_aq.aq$_agent_list_t; + agent_w_msg sys.aq$_agent; + start_tx number; + finish_tx number; + listen_timeout exception; + pragma exception_init(listen_timeout, -25254); + +BEGIN + + qlist(0) := sys.aq$_agent('prog1', 'input_queue', NULL); + qlist(1) := sys.aq$_agent('prog2', 'input_queue', NULL); + + dbms_output.put_line ('Listening on input_queue.'); + + start_tx := dbms_utility.get_time; + LOOP + BEGIN + + finish_tx := dbms_utility.get_time; + IF finish_tx - start_tx > 12000 THEN + exit; + END IF; + + DBMS_AQ.LISTEN( + agent_list => qlist, + wait => 30, + agent => agent_w_msg); + + IF agent_w_msg.name = 'PROG1' THEN + demo_dequeue('prog1'); + ELSIF agent_w_msg.name = 'PROG2' THEN + demo_dequeue('prog2'); + END IF; + + EXCEPTION + when listen_timeout THEN + null; + END; + + END LOOP; +END; +/ + +rem show the number of messages in prog1_processed_data table +select count(*) from prog1_processed_data; + +rem show the number of messages in prog2_processed_data table +select count(*) from prog2_processed_data; + + +spool off + + + + + + diff --git a/aqdemo06.sql b/aqdemo06.sql new file mode 100644 index 0000000..c204e50 --- /dev/null +++ b/aqdemo06.sql @@ -0,0 +1,73 @@ +Rem +Rem $Header: template.sql 06-feb-96.13:23:14 kosinski Exp $ +Rem +Rem aqdemo06.sql +Rem +Rem Copyright (c) Oracle Corporation 2000. All Rights Reserved. +Rem +Rem NAME +rem aqdemo06.sql - This script cleans up all the tables, types +rem queues, queue_tables, users etc. created by +rem aqdemo00 - aqdemo05. +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +rem Run this script as SYS using SQLPLUS and type '@aqdemo06'. +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbhyrava 07/10/00 - Bug 1319922 +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem kmeiyyap 01/27/99 - clean up script for aqdemo +rem kmeiyyap 01/27/99 - Created +rem + +set serveroutput on +set echo on +spool aqdemo06.log + +rem ========================================== +rem Drop Input Queue Table +rem ========================================== + +DECLARE +BEGIN + dbms_output.put_line ('Dropping Queue Table input_queue_table...'); + dbms_aqadm.drop_queue_table + ( + queue_table => 'aquser.input_queue_table', + force => TRUE + ); + + dbms_output.put_line ('Dropped Queue Table input_queue_table.'); + +END; +/ + + +rem ========================================== +rem Drop Prop Queue Table +rem ========================================== + +DECLARE +BEGIN + dbms_output.put_line ('Dropping Queue Table prop_queue_table...'); + dbms_aqadm.drop_queue_table + ( + queue_table => 'aquser.prop_queue_table', + force => TRUE + ); + + dbms_output.put_line ('Dropped Queue Table prop_queue_table.'); + +END; +/ + +revoke execute on dbms_lock from aquser +/ + +drop user aquser cascade +/ + +spool off diff --git a/aqdemo07.sql b/aqdemo07.sql new file mode 100644 index 0000000..109e234 --- /dev/null +++ b/aqdemo07.sql @@ -0,0 +1,246 @@ +Rem +Rem $Header: aqdemo07.sql 16-nov-2004.16:33:26 rbhyrava Exp $ +Rem +Rem aqdemo07.sql +Rem +Rem Copyright (c) 2001, 2004, Oracle. All rights reserved. +Rem +Rem NAME +Rem aqdemo07.sql - +Rem +Rem DESCRIPTION +Rem Demonstrate Enqueue/Dequeue to queues using XMLType +Rem +Rem +Rem NOTES +Rem To create Queue table with ADT containing XmlType : +Rem the database compatility should be 9.0.0 or higher +Rem +Rem Restart the database after adding the following line to init.ora +Rem compatible=9.0.0 +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbhyrava 11/16/04 - user +Rem rbhyrava 10/15/03 - +Rem rbhyrava 10/15/03 - sys user +Rem rbhyrava 04/29/01 - Merged rbhyrava_aqxmltype_demos +Rem rbhyrava 04/26/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +set serveroutput on +spool aqdemo07.log + +rem ==================================================================== +rem create a queue user +rem ==================================================================== +CONNECT system/manager; + +CREATE USER aqadmn IDENTIFIED by aqadmn; +CREATE USER aquser IDENTIFIED by aquser; +GRANT CONNECT, RESOURCE, AQ_USER_ROLE TO aquser; +GRANT CONNECT, RESOURCE, AQ_ADMINISTRATOR_ROLE TO aqadmn; + +GRANT EXECUTE ON dbms_aq TO aquser; +GRANT EXECUTE ON dbms_aqadm TO aqadmn ; + +CONNECT aqadmn/aqadmn; +set serveroutput on; + +rem ==================================================================== +rem create a type +rem ==================================================================== + +/* create a message type */ +CREATE OR REPLACE TYPE message AS OBJECT ( + id NUMBER, + data VARCHAR2(30), + myxmldata sys.XMLType) ; +/ + +GRANT EXECUTE ON message TO aquser ; + +rem ==================================================================== +rem create queue table and queue +rem ==================================================================== + +/* create and start a multiple consumer queue */ +BEGIN + DBMS_AQADM.CREATE_QUEUE_TABLE ( + QUEUE_TABLE => 'xmltypemsgqtab', + MULTIPLE_CONSUMERS => TRUE, + QUEUE_PAYLOAD_TYPE => 'message') ; + + DBMS_AQADM.CREATE_QUEUE( + QUEUE_NAME=>'msg_queue', + QUEUE_TABLE =>'xmltypemsgqtab'); + + DBMS_AQADM.START_QUEUE ( QUEUE_NAME => 'msg_queue'); +END; +/ + + +rem ==================================================================== +REM Add rule based subscribers using message selectors +rem ==================================================================== + +BEGIN + -- subscriber - get first three Ranks from each class from the XML message + -- rule based subscription + DBMS_AQADM.ADD_SUBSCRIBER('msg_queue', + SYS.AQ$_AGENT('SUB1', null, null ), + 'XMLType.extract(tab.user_data.myxmldata, + ''/STUDENT/RANK/text()'').getNumberVal() between 1 and 3') ; + + -- another subscriber + DBMS_AQADM.ADD_SUBSCRIBER('msg_queue', + SYS.AQ$_AGENT('SUB2', null, null )) ; + +END; +/ + +REM GRANT ENQUEUE/DEQUEUE privileges to AQUSER on Queue +BEGIN + + dbms_aqadm.grant_queue_privilege('ENQUEUE','msg_queue', 'aquser',FALSE); + dbms_aqadm.grant_queue_privilege('DEQUEUE','msg_queue', 'aquser',FALSE); +END; +/ + +CONNECT aquser/aquser ; +set serveroutput on size 200000; + +REM Do enqueues using XMLType + +CREATE OR REPLACE PROCEDURE MSGENQ(qnm VARCHAR2, + txnno NUMBER, + nmesgs NUMBER) +AS +enq_msgid RAW(16); +eopt dbms_aq.enqueue_options_t; +mprop dbms_aq.message_properties_t; +enq_userdata aqadmn.message; +xd sys.XMLType ; +begin + +FOR i in 1..nmesgs LOOP + mprop.priority := 10*txnno + i; + xd := sys.XMLType.createXML('' || txnno || '' + || i || ''); + + enq_userdata := aqadmn.message( + txnno, 'Class: ' || txnno || ' Rank#: ' || i,xd ); + dbms_aq.enqueue( + queue_name => qnm, + enqueue_options => eopt, + message_properties => mprop, + payload => enq_userdata, + msgid => enq_msgid); +END LOOP; +commit; +END; +/ +SHOW ERRORS + +rem ==================================================================== +REM Enqueue messages +rem ==================================================================== +Rem Now Enqueue some messages +execute MSGENQ('AQADMN.msg_queue', 1, 5); +execute MSGENQ('AQADMN.msg_queue', 2, 6); +execute MSGENQ('AQADMN.msg_queue', 3, 7); +execute MSGENQ('AQADMN.msg_queue', 4, 8); +execute MSGENQ('AQADMN.msg_queue', 5, 9); + + +REM Now dequeue messages for the subscribers + +CREATE OR REPLACE PROCEDURE MSGDEQ(appname varchar2, + qname varchar2, + cond varchar2) AS +dequeue_options dbms_aq.dequeue_options_t; +message_properties dbms_aq.message_properties_t; +message_handle RAW(16); +payload aqadmn.message; + +no_messages exception; + +pragma exception_init (no_messages, -25228); + +BEGIN +dequeue_options.wait := 30; +dequeue_options.navigation := DBMS_AQ.FIRST_MESSAGE; +dequeue_options.consumer_name := appname; + +dbms_output.put_line('\nDequeue from : ' || qname || ' subscriber ' || appname); +if ( cond is not null) then + dbms_output.put_line (' ->Using Dequeue Condition: ' || cond) ; + dequeue_options.deq_condition := cond ; + +dbms_output.put_line('') ; +end if ; + +LOOP + BEGIN + dbms_aq.dequeue(queue_name => qname, + dequeue_options => dequeue_options, + message_properties => message_properties, + payload => payload, + msgid => message_handle); + + dbms_output.put('Id:' || payload.id || ' Data:' || payload.data || ' '); + dbms_output.put_line(' Myxmldata:' || payload.myxmldata.getStringVal()); + dequeue_options.navigation := DBMS_AQ.NEXT_MESSAGE; + END; +END LOOP; +EXCEPTION + WHEN no_messages THEN + dbms_output.put_line ('No more messages'); +END; +/ + +SHOW ERRORS + +rem ==================================================================== +REM Dequeue messages +rem ==================================================================== + +BEGIN + + MSGDEQ('SUB1', 'AQADMN.MSG_QUEUE' , null) ; + + -- Dequeue for messages which has XMLType data matching the condition + -- XML should contain CLASS tag AND CLASS should be in 4 or 5 + -- Specify rule during dequeue + + MSGDEQ('SUB2', 'AQADMN.MSG_QUEUE', + 'XMLType.existsNode(tab.user_data.myxmldata,''/STUDENT/CLASS'')=1 AND ' || + ' XMLType.extract(tab.user_data.myxmldata, ''/STUDENT/CLASS/text()'').getNumberVal() in ( 4, 5)') ; + +END; +/ + +REM =============================================================== +REM CLEANUP QUEUES/USERS +REM =============================================================== + +connect aqadmn/aqadmn +execute dbms_aqadm.stop_queue ('msg_queue') ; +execute dbms_aqadm.drop_queue ('msg_queue') ; +execute dbms_aqadm.drop_queue_table ('xmltypemsgqtab' , TRUE) ; + +DROP TYPE message ; + +CONNECT sys/change_on_install AS SYSDBA; + +drop user aquser cascade ; +drop user aqadmn cascade ; + +spool off diff --git a/aqdemo08.sql b/aqdemo08.sql new file mode 100644 index 0000000..08a5c24 --- /dev/null +++ b/aqdemo08.sql @@ -0,0 +1,575 @@ +Rem +Rem $Header: aqdemo08.sql 16-nov-2004.16:35:23 rbhyrava Exp $ +Rem +Rem aqdemo08.sql +Rem +Rem Copyright (c) 2001, 2004, Oracle. All rights reserved. +Rem +Rem NAME +Rem aqdemo08.sql - AQ Notifications Demo +Rem +Rem DESCRIPTION +Rem Make sure the database is started with following parameters +Rem aq_tm_processes =2 +Rem job_queue_processes=2 +Rem compatible=8.1.0 # or above +Rem Modify the email host , port and sendfrom . +Rem Modify the email you@company.com to valid email address +Rem NOTES +Rem This demo does the following +Rem - setup mail server - change mailhost and sender email address +Rem - setup users/queues/queue tables +Rem - Create callback functions used in registration +Rem - Register for event notification for the subscriber ADMIN +Rem - Registrations are added using default presentation +Rem and xml presentation +Rem - Do enqueues +Rem - Verify notifications +Rem - Cleanup +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbhyrava 11/16/04 - user +Rem ksurlake 06/10/04 - 3229354: Wait before unregistering +Rem rbhyrava 05/16/01 - fix typo / +Rem rbhyrava 04/29/01 - Merged rbhyrava_aqxmltype_demos +Rem rbhyrava 04/27/01 - Created +Rem + +spool aqdemo08.log +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +CONNECT sys/change_on_install as sysdba; +SET SERVEROUTPUT ON +SET ECHO ON + +Rem set the mailserver etc. +call dbms_aqelm.set_mailhost('youmailhost.company.com'); +call dbms_aqelm.set_mailport(25); +call dbms_aqelm.set_sendfrom('you@company.com'); + +Rem user pubsub1 is used for registering on a queue +DROP USER pubsub1 CASCADE; +CREATE USER pubsub1 IDENTIFIED BY pubsub1; + +Rem grant all the roles to pubsub1 +GRANT connect, resource, dba TO pubsub1; +GRANT aq_administrator_role, aq_user_role TO pubsub1; +GRANT EXECUTE ON dbms_aq TO pubsub1; +GRANT EXECUTE ON dbms_aqadm TO pubsub1; +EXECUTE dbms_aqadm.grant_type_access('pubsub1'); +EXECUTE dbms_aqadm.grant_system_privilege('ENQUEUE_ANY','pubsub1',FALSE); +EXECUTE dbms_aqadm.grant_system_privilege('DEQUEUE_ANY','pubsub1',FALSE); + +CONNECT pubsub1/pubsub1; + +rem stop the adt queue +BEGIN +DBMS_AQADM.STOP_QUEUE('pubsub1.adtevents'); +END; +/ + +rem drop the adt queue +BEGIN +DBMS_AQADM.DROP_QUEUE(QUEUE_NAME=>'pubsub1.adtevents'); +END; +/ + +rem drop the adt queue table +BEGIN +DBMS_AQADM.DROP_QUEUE_TABLE(QUEUE_TABLE => 'pubsub1.adt_msg_table', force => TRUE); +END; +/ + +rem create the adt +CREATE OR REPLACE TYPE adtmsg AS OBJECT (id NUMBER, data VARCHAR2(4000)) ; +/ + +rem create the raw queue table +BEGIN +DBMS_AQADM.CREATE_QUEUE_TABLE( + QUEUE_TABLE=>'pubsub1.raw_msg_table', + MULTIPLE_CONSUMERS => TRUE, + QUEUE_PAYLOAD_TYPE =>'RAW', + COMPATIBLE => '8.1.3'); +END; +/ + +rem creat the adt queue table +BEGIN +DBMS_AQADM.CREATE_QUEUE_TABLE( + QUEUE_TABLE=>'pubsub1.adt_msg_table', + MULTIPLE_CONSUMERS => TRUE, + QUEUE_PAYLOAD_TYPE =>'ADTMSG', + COMPATIBLE => '8.1.3'); +END; +/ +rem Create a queue for raw events +BEGIN +DBMS_AQADM.CREATE_QUEUE(QUEUE_NAME=>'pubsub1.events', + QUEUE_TABLE=>'pubsub1.raw_msg_table', + COMMENT=>'Q for events triggers'); +END; +/ + +rem Create a queue for adt events +BEGIN +DBMS_AQADM.CREATE_QUEUE(QUEUE_NAME=>'pubsub1.adtevents', + QUEUE_TABLE=>'pubsub1.adt_msg_table', + COMMENT=>'Q for adt events triggers'); +END; +/ + +rem start the queues +BEGIN +DBMS_AQADM.START_QUEUE('pubsub1.events'); +END; +/ + +BEGIN +DBMS_AQADM.START_QUEUE('pubsub1.adtevents'); +END; +/ +rem Create a non-persistent queue for events +BEGIN + DBMS_AQADM.CREATE_NP_QUEUE(QUEUE_NAME=>'pubsub1.nonperevents', + MULTIPLE_CONSUMERS => TRUE); +END; +/ + +rem start the np queue +BEGIN +DBMS_AQADM.START_QUEUE('pubsub1.nonperevents'); +END; +/ + +rem procedure to enqueue raw into persistent queue +CREATE OR REPLACE PROCEDURE new_rawenqueue(queue_name IN VARCHAR2, + correlation IN VARCHAR2 := NULL, + exception_queue IN VARCHAR2 := NULL) +AS + +enq_ct dbms_aq.enqueue_options_t; +msg_prop dbms_aq.message_properties_t; +enq_msgid RAW(16); +userdata RAW(1000); + +BEGIN + msg_prop.exception_queue := exception_queue; + msg_prop.correlation := correlation; + userdata := hextoraw('666'); + + DBMS_AQ.ENQUEUE(queue_name, enq_ct, msg_prop, userdata, enq_msgid); +END; +/ +GRANT EXECUTE ON new_rawenqueue TO PUBLIC; + +rem procedure to enqueue adt into persistent queue +CREATE OR REPLACE PROCEDURE new_adtenqueue(queue_name IN VARCHAR2, + correlation IN VARCHAR2 := NULL, + exception_queue IN VARCHAR2 := NULL) +AS + +enq_ct dbms_aq.enqueue_options_t; +msg_prop dbms_aq.message_properties_t; +enq_msgid raw(16); +payload adtmsg; + +BEGIN + msg_prop.exception_queue := exception_queue; + msg_prop.correlation := correlation; + payload := adtmsg(1, 'p queue Hello World!'); + + DBMS_AQ.ENQUEUE(queue_name, enq_ct, msg_prop, payload, enq_msgid); +END; +/ +GRANT EXECUTE ON new_adtenqueue TO PUBLIC; + +rem create procedure to enqueue raw into np queue +CREATE OR REPLACE PROCEDURE new_np_rawenqueue(queue VARCHAR2, + id INTEGER, + correlation VARCHAR2) +AS + +msgprop dbms_aq.message_properties_t; +enqopt dbms_aq.enqueue_options_t; +enq_msgid RAW(16); +payload RAW(10); + +BEGIN + payload := hextoraw('999'); + enqopt.visibility:=dbms_aq.IMMEDIATE; + msgprop.correlation:=correlation; + DBMS_AQ.ENQUEUE( queue, enqopt, msgprop, payload, enq_msgid); +END; +/ +GRANT EXECUTE ON new_np_rawenqueue TO PUBLIC; + +rem create procedure to enqueue adt into np queue +CREATE OR REPLACE PROCEDURE new_np_adtenqueue(queue VARCHAR2, + id INTEGER, + correlation VARCHAR2) +AS + +msgprop dbms_aq.message_properties_t; +enqopt dbms_aq.enqueue_options_t; +enq_msgid raw(16); +payload adtmsg; + +BEGIN + payload := adtmsg(1, 'np queue Hello World!'); + enqopt.visibility:=dbms_aq.IMMEDIATE; + msgprop.correlation:=correlation; + DBMS_AQ.ENQUEUE( queue, enqopt, msgprop, payload, enq_msgid); +END; +/ +GRANT EXECUTE ON new_np_adtenqueue TO PUBLIC; + +DECLARE + subscriber sys.aq$_agent; + +BEGIN + + subscriber := sys.aq$_agent('admin', null, null); + + dbms_aqadm.add_subscriber(queue_name => 'pubsub1.events', + subscriber => subscriber); + + dbms_aqadm.add_subscriber(queue_name => 'pubsub1.adtevents', + subscriber => subscriber); + + dbms_aqadm.add_subscriber(queue_name => 'pubsub1.nonperevents', + subscriber => subscriber); + +END; +/ + +SET ECHO ON; +CONNECT / as sysdba; +set serveroutput on; + +DROP TABLE plsqlregtr; +CREATE TABLE plsqlregtr +( + descr sys.aq$_descriptor, + reginfo sys.aq$_reg_info, + payload RAW(2000), + payloadl NUMBER +); + +GRANT ALL ON plsqlregtr TO PUBLIC; + +DROP TABLE plsqlregta; +CREATE TABLE plsqlregta +( + descr sys.aq$_descriptor, + reginfo sys.aq$_reg_info, + payload VARCHAR2(4000), + payloadl NUMBER +); + +GRANT ALL ON plsqlregta TO PUBLIC; + +CONNECT pubsub1/pubsub1 + +CREATE OR REPLACE PROCEDURE plsqlregproc1( + context RAW , reginfo sys.aq$_reg_info, descr sys.aq$_descriptor, + payload RAW, payloadl NUMBER) +AS +BEGIN + INSERT INTO sys.plsqlregtr (descr, reginfo, payload, payloadl) + VALUES (descr, reginfo, payload, payloadl); +END; +/ + +CREATE OR REPLACE PROCEDURE plsqlregproc2( + context RAW , reginfo sys.aq$_reg_info, descr sys.aq$_descriptor, + payload VARCHAR2, payloadl NUMBER) +AS +BEGIN + INSERT INTO sys.plsqlregta (descr, reginfo, payload, payloadl) + VALUES (descr, reginfo, payload, payloadl); +END; +/ +rem Do all the registerations +SET ECHO ON; +CONNECT pubsub1/pubsub1; +SET SERVEROUTPUT ON; + +DECLARE + + reginfo1 sys.aq$_reg_info; + reginfo2 sys.aq$_reg_info; + reginfo3 sys.aq$_reg_info; + reginfo4 sys.aq$_reg_info; + reginfo5 sys.aq$_reg_info; + reginfo6 sys.aq$_reg_info; + reginfolist sys.aq$_reg_info_list; + +BEGIN +-- register for p raw q default pres + reginfo1 := sys.aq$_reg_info('PUBSUB1.EVENTS:ADMIN',1,'plsql://plsqlregproc1',HEXTORAW('FF')); + +-- register for p raw q xml pres + reginfo2 := sys.aq$_reg_info('PUBSUB1.EVENTS:ADMIN',1,'plsql://plsqlregproc1?PR=1',HEXTORAW('FF')); + +-- register for p adt q default pres + reginfo3 := sys.aq$_reg_info('PUBSUB1.ADTEVENTS:ADMIN',1,'plsql://plsqlregproc2',HEXTORAW('FF')); + +-- register for p adt q xml pres + reginfo4 := sys.aq$_reg_info('PUBSUB1.ADTEVENTS:ADMIN',1,'plsql://plsqlregproc2?PR=1',HEXTORAW('FF')); + +-- for np q raw and adt can be enqueued into the same queue +-- register for np raw and adt q default pres + reginfo5 := sys.aq$_reg_info('PUBSUB1.NONPEREVENTS:ADMIN',1,'plsql://plsqlregproc1',HEXTORAW('FF')); + +-- register for np raw and adt q xml pres + reginfo6 := sys.aq$_reg_info('PUBSUB1.NONPEREVENTS:ADMIN',1,'plsql://plsqlregproc2?PR=1',HEXTORAW('FF')); + + reginfolist := sys.aq$_reg_info_list(reginfo1); + reginfolist.EXTEND; + reginfolist(2) := reginfo2; + reginfolist.EXTEND; + reginfolist(3) := reginfo3; + reginfolist.EXTEND; + reginfolist(4) := reginfo4; + reginfolist.EXTEND; + reginfolist(5) := reginfo5; + reginfolist.EXTEND; + reginfolist(6) := reginfo6; + + sys.dbms_aq.register(reginfolist, 6); + + commit; + +-- registerations are done + +END; +/ + +Rem Do all the registerations +CONNECT pubsub1/pubsub1; +SET ECHO ON; +SET SERVEROUTPUT ON; + +DECLARE + + reginfo1 sys.aq$_reg_info; + reginfo2 sys.aq$_reg_info; + reginfo3 sys.aq$_reg_info; + reginfo4 sys.aq$_reg_info; + reginfo5 sys.aq$_reg_info; + reginfo6 sys.aq$_reg_info; + reginfolist sys.aq$_reg_info_list; + +BEGIN +-- register for p raw q default pres + reginfo1 := sys.aq$_reg_info('PUBSUB1.EVENTS:ADMIN',1,'mailto://you@company.com',HEXTORAW('FF')); + +-- register for p raw q xml pres + reginfo2 := sys.aq$_reg_info('PUBSUB1.EVENTS:ADMIN',1,'mailto://you@company.com?PR=1',HEXTORAW('FF')); + +-- register for p adt q default pres + reginfo3 := sys.aq$_reg_info('PUBSUB1.ADTEVENTS:ADMIN',1,'mailto://you@company.com',HEXTORAW('FF')); + +-- register for p adt q xml pres + reginfo4 := sys.aq$_reg_info('PUBSUB1.ADTEVENTS:ADMIN',1,'mailto://you@company.com?PR=1',HEXTORAW('FF')); + +-- for np q raw and adt can be enqueued into the same queue +-- register for np raw and adt q default pres + reginfo5 := sys.aq$_reg_info('PUBSUB1.NONPEREVENTS:ADMIN',1,'mailto://you@company.com',HEXTORAW('FF')); + +-- register for np raw and adt q xml pres + reginfo6 := sys.aq$_reg_info('PUBSUB1.NONPEREVENTS:ADMIN',1,'mailto://you@company.com?PR=1',HEXTORAW('FF')); + + reginfolist := sys.aq$_reg_info_list(reginfo1); + reginfolist.EXTEND; + reginfolist(2) := reginfo2; + reginfolist.EXTEND; + reginfolist(3) := reginfo3; + reginfolist.EXTEND; + reginfolist(4) := reginfo4; + reginfolist.EXTEND; + reginfolist(5) := reginfo5; + reginfolist.EXTEND; + reginfolist(6) := reginfo6; + + sys.dbms_aq.register(reginfolist, 6); + + COMMIT; + +-- registrations are done + +END; +/ +CONNECT pubsub1/pubsub1; +SET ECHO ON; +SET SERVEROUTPUT ON; + +DECLARE +BEGIN +-- wait for registerations to happen +-- dbms_lock.sleep(90); + +-- now start enqueing + +-- raw into p queue + new_rawenqueue('PUBSUB1.EVENTS', 'PR CORRELATION STRING', 'PREQ'); + commit; + +-- adt into p queue + new_adtenqueue('PUBSUB1.ADTEVENTS', 'PA CORRELATION STRING', 'PAEQ'); + commit; + +-- raw into np queue + new_np_rawenqueue('PUBSUB1.NONPEREVENTS', 1, 'NPR CORRELATION STRING'); + commit; + +-- adt into np queue + new_np_adtenqueue('PUBSUB1.NONPEREVENTS', 1, 'NPA CORRELATION STRING'); + commit; + +END; +/ + +DECLARE +BEGIN +-- wait for PL/SQL callbacks to be invoked + dbms_lock.sleep(120); +END; +/ + +set echo on; +CONNECT pubsub1/pubsub1; +SET SERVEROUTPUT ON; + +SELECT count(*) FROM sys.plsqlregtr t; + +SELECT count(*) FROM sys.plsqlregta t; + +REM Do all the unregisterations +CONNECT pubsub1/pubsub1; +SET ECHO ON; +SET SERVEROUTPUT ON; + +DECLARE + + reginfo1 sys.aq$_reg_info; + reginfo2 sys.aq$_reg_info; + reginfo3 sys.aq$_reg_info; + reginfo4 sys.aq$_reg_info; + reginfo5 sys.aq$_reg_info; + reginfo6 sys.aq$_reg_info; + reginfolist sys.aq$_reg_info_list; + +BEGIN +-- register for p raw q default pres + reginfo1 := sys.aq$_reg_info('PUBSUB1.EVENTS:ADMIN',1,'plsql://plsqlregproc1',HEXTORAW('FF')); + +-- register for p raw q xml pres + reginfo2 := sys.aq$_reg_info('PUBSUB1.EVENTS:ADMIN',1,'plsql://plsqlregproc1?PR=1',HEXTORAW('FF')); + +-- register for p adt q default pres + reginfo3 := sys.aq$_reg_info('PUBSUB1.ADTEVENTS:ADMIN',1,'plsql://plsqlregproc2',HEXTORAW('FF')); + +-- register for p adt q xml pres + reginfo4 := sys.aq$_reg_info('PUBSUB1.ADTEVENTS:ADMIN',1,'plsql://plsqlregproc2?PR=1',HEXTORAW('FF')); + +-- for np q raw and adt can be enqueued into the same queue +-- register for np raw and adt q default pres + reginfo5 := sys.aq$_reg_info('PUBSUB1.NONPEREVENTS:ADMIN',1,'plsql://plsqlregproc1',HEXTORAW('FF')); + +-- register for np raw and adt q xml pres + reginfo6 := sys.aq$_reg_info('PUBSUB1.NONPEREVENTS:ADMIN',1,'plsql://plsqlregproc2?PR=1',HEXTORAW('FF')); + + reginfolist := sys.aq$_reg_info_list(reginfo1); + reginfolist.EXTEND; + reginfolist(2) := reginfo2; + reginfolist.EXTEND; + reginfolist(3) := reginfo3; + reginfolist.EXTEND; + reginfolist(4) := reginfo4; + reginfolist.EXTEND; + reginfolist(5) := reginfo5; + reginfolist.EXTEND; + reginfolist(6) := reginfo6; + + sys.dbms_aq.unregister(reginfolist, 6); + + COMMIT; + +-- unregisterations are done + +END; +/ +REM Do all the unregisterations +CONNECT pubsub1/pubsub1; +SET ECHO ON; +SET SERVEROUTPUT ON; + +DECLARE + + reginfo1 sys.aq$_reg_info; + reginfo2 sys.aq$_reg_info; + reginfo3 sys.aq$_reg_info; + reginfo4 sys.aq$_reg_info; + reginfo5 sys.aq$_reg_info; + reginfo6 sys.aq$_reg_info; + reginfolist sys.aq$_reg_info_list; + +BEGIN +-- register for p raw q default pres + reginfo1 := sys.aq$_reg_info('PUBSUB1.EVENTS:ADMIN',1,'mailto://you@company.com',HEXTORAW('FF')); + +-- register for p raw q xml pres + reginfo2 := sys.aq$_reg_info('PUBSUB1.EVENTS:ADMIN',1,'mailto://you@company.com?PR=1',HEXTORAW('FF')); + +-- register for p adt q default pres + reginfo3 := sys.aq$_reg_info('PUBSUB1.ADTEVENTS:ADMIN',1,'mailto://you@company.com',HEXTORAW('FF')); + +-- register for p adt q xml pres + reginfo4 := sys.aq$_reg_info('PUBSUB1.ADTEVENTS:ADMIN',1,'mailto://you@company.com?PR=1',HEXTORAW('FF')); + +-- for np q raw and adt can be enqueued into the same queue +-- register for np raw and adt q default pres + reginfo5 := sys.aq$_reg_info('PUBSUB1.NONPEREVENTS:ADMIN',1,'mailto://you@company.com',HEXTORAW('FF')); + +-- register for np raw and adt q xml pres + reginfo6 := sys.aq$_reg_info('PUBSUB1.NONPEREVENTS:ADMIN',1,'mailto://you@company.com?PR=1',HEXTORAW('FF')); + + reginfolist := sys.aq$_reg_info_list(reginfo1); + reginfolist.EXTEND; + reginfolist(2) := reginfo2; + reginfolist.EXTEND; + reginfolist(3) := reginfo3; + reginfolist.EXTEND; + reginfolist(4) := reginfo4; + reginfolist.EXTEND; + reginfolist(5) := reginfo5; + reginfolist.EXTEND; + reginfolist(6) := reginfo6; + + sys.dbms_aq.unregister(reginfolist, 6); + + COMMIT; + +-- unregisterations are done + +END; +/ + + +CONNECT sys/change_on_install as sysdba; + +drop user pubsub1 cascade ; +drop table plsqlregtr ; +drop table plsqlregta ; + +spool off +exit ; diff --git a/aqdemo09.sql b/aqdemo09.sql new file mode 100644 index 0000000..f965be7 --- /dev/null +++ b/aqdemo09.sql @@ -0,0 +1,147 @@ +Rem +Rem $Header: aqdemo09.sql 16-nov-2004.16:37:16 rbhyrava Exp $ +Rem +Rem aqdemo10.sql +Rem +Rem Copyright (c) 2003, 2004, Oracle. All rights reserved. +Rem +Rem NAME +Rem aqdemo09.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbhyrava 11/16/04 - user +Rem aahluwal 10/17/03 - aahluwal_create_arrenqdeq_demos +Rem aahluwal 10/07/03 - Created +Rem +rem NAME +rem aqdemo09.sql, aqdemo10.sql, aqdemo11.sql, aqdemo12.sql, +rem ociaqarrayenq.c, ociaqarraydeq.c +rem +rem DESCRIPTION +rem This set of scripts serve as an example for building an +rem application, using Oracle Advanced Queues, to perform +rem asynchronous database operations. These examples specifically +rem make use of the array enq/deq interfaces for applications +rem requiring high throughput. +rem +rem The scripts do the following: +rem +rem aqdemo09.sql (Login as SYS, and type '@aqdemo09') +rem 1) Create aquser as an user of AQ +rem 2) Create my_queue AQ queue within my_queue_tab AQ Queue Tab in +rem AQUSER's schema +rem 3) Add a subscriber to my_queue +rem +rem aqdemo10.sql +rem 1) Performs an array enq of a batch of messages into my_queue +rem +rem aqdemo11.sql +rem 1) Performs an array deq of a batch of messages from my_queue +rem +rem ociaqarrayenq.c, ociaqarraydeq.c +rem 1) Perform an array enq and array deq (respectively) on my_queue +rem from the OCI AQ array operations interfaces. +rem +rem aqdemo12.sql (Login as SYS, and type '@aqdemo09') +rem 1) Cleans up all objects +rem +rem + +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 + + +set serveroutput on +set echo on +spool aqdemo09.log + +rem ==================================================================== +rem create a queue user +rem ==================================================================== +create user aquser identified by aquser; +grant connect, resource , aq_administrator_role to aquser +/ +grant execute on dbms_aq to aquser +/ +grant execute on dbms_aqadm to aquser +/ + +connect aquser/aquser; + +rem ==================================================================== +rem +rem Create a type message for the payload of the queue. Also create types +rem message_tbl and message_arr which are used for subsequent array +rem operations. +rem +rem ==================================================================== +CREATE OR REPLACE TYPE message as OBJECT ( +data VARCHAR2(10)) ; +/ + +CREATE OR REPLACE TYPE message_tbl AS TABLE OF message; +/ + +CREATE OR REPLACE TYPE message_arr AS VARRAY(2000) OF message; +/ + +rem ========================================== +rem Create a queue table my_queue_tab +rem ========================================== +begin +dbms_aqadm.create_queue_table( + queue_table => 'my_queue_tab', + multiple_consumers => TRUE, + queue_payload_type => 'message', + compatible => '9.2.0.0.0'); +end; +/ + +rem ========================================== +rem Create a queue my_queue +rem ========================================== +begin +dbms_aqadm.create_queue( + queue_name => 'my_queue', + queue_table => 'my_queue_tab'); +end; +/ + +rem ==================================== +rem Start queue my_queue +rem ==================================== +begin +dbms_aqadm.start_queue( + queue_name => 'my_queue', + dequeue => TRUE, + enqueue => TRUE); +end; +/ + +rem ======================================== +rem Create queue subscriber +rem ======================================== +declare +app1 sys.aq$_agent; +begin +app1 := sys.aq$_agent('sub1', NULL, NULL); +dbms_aqadm.add_subscriber('my_queue',app1); +end; +/ + +rem ==================================================================== +rem Setup complete +rem ==================================================================== + +spool off diff --git a/aqdemo10.sql b/aqdemo10.sql new file mode 100644 index 0000000..ff6a115 --- /dev/null +++ b/aqdemo10.sql @@ -0,0 +1,83 @@ +Rem +Rem $Header: aqdemo10.sql 17-oct-2003.16:57:16 aahluwal Exp $ +Rem +Rem aqdemo10.sql +Rem +Rem Copyright (c) 2003, Oracle Corporation. All rights reserved. +Rem +Rem NAME +Rem aqdemo10.sql - +Rem +Rem DESCRIPTION +Rem Performs an array enq of a batch of messages into my_queue +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem aahluwal 10/17/03 - aahluwal_create_arrenqdeq_demos +Rem aahluwal 10/07/03 - Created +Rem + +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 + +Rem perform array enqueue into AQ queue my_queue + +connect aquser/aquser +set serveroutput on +set echo on + +DECLARE + enqopt dbms_aq.enqueue_options_t; + msgproparr dbms_aq.message_properties_array_t; + msgprop dbms_aq.message_properties_t; + payloadarr message_tbl; + msgidarr dbms_aq.msgid_array_t; + retval pls_integer; + +BEGIN + payloadarr := message_tbl(message('00000'), + message('11111'), + message('22222'), + message('33333'), + message('44444'), + message('55555'), + message('66666'), + message('77777'), + message('88888'), + message('99999')) ; + msgproparr := dbms_aq.message_properties_array_t(msgprop, + msgprop, + msgprop, + msgprop, + msgprop, + msgprop, + msgprop, + msgprop, + msgprop, + msgprop); + + retval := dbms_aq.enqueue_array( queue_name => 'AQUSER.MY_QUEUE', + enqueue_options => enqopt , + array_size => 10, + message_properties_array => msgproparr, + payload_array => payloadarr, + msgid_array => msgidarr ) ; + commit; + + dbms_output.put_line('Enqueued ' || retval || ' messages') ; + for i in 1..retval loop + dbms_output.put_line ('Message ' || i || ' payload: ' || payloadarr(i).data) ; + end loop ; + + +END; +/ + + diff --git a/aqdemo11.sql b/aqdemo11.sql new file mode 100644 index 0000000..d0821ec --- /dev/null +++ b/aqdemo11.sql @@ -0,0 +1,65 @@ +Rem +Rem $Header: aqdemo11.sql 17-oct-2003.16:57:17 aahluwal Exp $ +Rem +Rem aqdemo11.sql +Rem +Rem Copyright (c) 2003, Oracle Corporation. All rights reserved. +Rem +Rem NAME +Rem aqdemo11.sql - +Rem +Rem DESCRIPTION +Rem Performs an array deq of a batch of messages from my_queue +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem aahluwal 10/17/03 - aahluwal_create_arrenqdeq_demos +Rem aahluwal 10/07/03 - Created +Rem + +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 + +Rem perform array dequeue from AQ queue my_queue + +connect aquser/aquser +set serveroutput on +set echo on + +DECLARE + deqopt dbms_aq.dequeue_options_t ; + msgproparr dbms_aq.message_properties_array_t := + dbms_aq.message_properties_array_t(); + payloadarr message_arr := message_arr() ; + msgidarr dbms_aq.msgid_array_t ; + retval pls_integer ; +BEGIN + payloadarr.extend(10); + msgproparr.extend(10); + deqopt.consumer_name := 'SUB1'; + retval := dbms_aq.dequeue_array( queue_name => 'AQUSER.MY_QUEUE', + dequeue_options => deqopt , + array_size => payloadarr.count, + message_properties_array => msgproparr, + payload_array => payloadarr, + msgid_array => msgidarr ) ; + commit; + dbms_output.put_line('Dequeued ' || retval || ' messages') ; + for i in 1..retval loop + dbms_output.put_line ('Message ' || i || ' payload: ' || payloadarr(i).data) ; + end loop ; + +END; +/ + + + + + diff --git a/aqdemo12.sql b/aqdemo12.sql new file mode 100644 index 0000000..eb2dfc6 --- /dev/null +++ b/aqdemo12.sql @@ -0,0 +1,54 @@ +Rem +Rem $Header: aqdemo12.sql 17-oct-2003.16:57:18 aahluwal Exp $ +Rem +Rem aqdemo12.sql +Rem +Rem Copyright (c) 2003, Oracle Corporation. All rights reserved. +Rem +Rem NAME +Rem aqdemo12.sql - +Rem +Rem DESCRIPTION +Rem Removes objects and users created by aqdemo09.sql. +Rem +Rem NOTES +Rem Run this script as SYS using SQLPLUS and type '@aqdemo12'. +Rem +Rem MODIFIED (MM/DD/YY) +Rem aahluwal 10/17/03 - aahluwal_create_arrenqdeq_demos +Rem aahluwal 10/07/03 - Created +Rem + +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 + +set serveroutput on +set echo on +spool aqdemo12.log + +rem ========================================== +rem Drop My_Queue_Tab Queue Table +rem ========================================== +DECLARE +BEGIN + dbms_output.put_line ('Dropping Queue Table my_queue_tab...'); + dbms_aqadm.drop_queue_table + ( + queue_table => 'aquser.my_queue_tab', + force => TRUE + ); + + dbms_output.put_line ('Dropped Queue Table my_queue_tab.'); + +END; +/ + +drop user aquser cascade +/ + +spool off diff --git a/aqjmsREADME.txt b/aqjmsREADME.txt new file mode 100644 index 0000000..8014d62 --- /dev/null +++ b/aqjmsREADME.txt @@ -0,0 +1,205 @@ +/ $Header: aqjmsREADME.txt 05-jun-2007.15:02:54 aatam Exp $ +/ +/ aqjmsREADME.txt +/ +/ Copyright (c) Oracle Corporation 2000. All Rights Reserved. +/ +/ NAME +/ aqjmsREADME.txt - +/ +/ DESCRIPTION +/ +/ +/ NOTES +/ +/ +/ MODIFIED (MM/DD/YY) +/ aatam 06/05/07 - password need to be consistent +/ qialiu 02/02/07 - ojdbc5.jar +/ qialiu 04/07/06 - jta.jar is in /ade/qialiu_linux_db4/oracle/jlib +/ qialiu 03/09/06 - move jdk1.4 +/ rbhyrava 09/17/04 - orai18n +/ qialiu 07/14/04 - update jta.jar location +/ jleinawe 10/28/03 - update for 10g +/ jleinawe 05/09/03 - update compatibility +/ jleinawe 03/11/03 - add aqjmsdemo10 +/ jleinawe 12/20/02 - update classpath info +/ jleinawe 11/19/02 - add aqjmsdemo09 +/ vmaganty 10/04/02 - add JMS 1.1 domain unification demo info +/ jleinawe 09/10/02 - add aqjmsdemo07 and kprb +/ jleinawe 05/14/02 - udpate nls_charset.zip +/ rbhyrava 03/01/02 - ORAData +/ rbhyrava 07/16/01 - port specific +/ rbhyrava 06/19/01 - jndi location +/ rbhyrava 03/12/01 - jndi.jar +/ rbhyrava 03/06/01 - jndi +/ rbhyrava 01/26/01 - classes111 +/ rbhyrava 11/14/00 - jdbc path +/ rbhyrava 07/10/00 - fix bug 1319922 +/ rbhyrava 07/11/00 - aqjmsdemo.tar +/ rbhyrava 04/14/00 - demo drop +/ rbhyrava 03/20/00 - required init.ora setup +/ rbhyrava 03/15/00 - AQ JMS demo README +/ rbhyrava 03/15/00 - Creation +/ +The following files are required for running JMS samples + + aqjmsdmo.sql - Setup file for AQ JMS demos + aqjmsdemo01.java - Enqueue Text Message and Dequeue based on Message Properties + aqjmsdemo02.java - Message Listener demo- enqueue messages - run aqjmsdemo04 + aqjmsdemo03.java - depends on aqjmsdemo03 - setup Message Listener and dequeue + aqjmsdemo04.java - Oracle Type Payload - Dequeue on Payload content + aqjmsdemo05.java - Queue Browser Example + aqjmsdemo06.java - Schedule Propagation between queues in the database + aqjmsdemo07.java - Send and receive an ADT message containing XML data. + aqjmsdemo08.java - JMS 1.1 domain unification demo + aqjmsdemo09.java - JMS Bulk Array Enqueue/Dequeue + aqjmsdemo10.java - ANYDATA Messaging with JMS Message types and AdtMessage. + Cars.java - Jpublisher generated class ; used in aqjmsdemo04.java + Emp.java - Jpublisher generated class ; used in aqjmsdemo04.java + MesgListener.java - Message Listener - used in aqjmsdemo03.java + Message.java - Definition of Serializable Object - aqjmsdemo06.java + aqjmsdrp.sql - Cleanup for AQ JMS demos + +The following files are required for running AQ Java API samples + + aqoradmo.sql - Setup file for AQ java API demos + aqorademo01.java - Enqueue and Dequeue RAW messages + aqorademo02.java - Enqueue and Dequeue Object Type messages using + ORAData interface + Address.java - Jpublisher generated class ; used in aqorademo02.java + Person.java - Jpublisher generated class ; used in aqorademo02.java + aqoradrp.sql - Cleanup for AQ java API demos + +The following files are required for running the AQ Java KPRB driver samples + + aqjmskprb01.java - Enqueues and dequeues a message within the database. + aqjmskprb01a.sql - Setup file for kprb driver demo. + aqjmskprb01b.sql - Defines java program aqjmskprb01.java as a stored procedure. + aqjmskprb01c.sql - Executes aqjmskprb01.java as a stored procedure. + aqjmskprb01d.sql - Cleanup for AQ kprb driver demo. + + +Setup: +------ + +The CLASSPATH and PATH need to be set appropriately. The JDK need to be at +least JDK 1.5. + +the CLASSPATH need to have the following: + $ORACLE_HOME/rdbms/jlib/aqapi.jar + $ORACLE_HOME/rdbms/jlib/jmscommon.jar + $ORACLE_HOME/rdbms/jlib/xdb.jar + $ORACLE_HOME/lib/xmlparserv2.jar + $ORACLE_HOME/jdbc/lib/ojdbc5.jar + $ORACLE_HOME/jlib/orai18n.jar + $ORACLE_HOME/jlib/jndi.jar + $ORACLE_HOME/jlib/jta.jar + +Make sure LD_LIBRARY_PATH contain the directory of OCI JDBC driver shared + library objects (libocijdbc*.so). + +Eg: + for Solaris, add ORACLE_HOME/lib to LD_LIBRARY_PATH + In C-Shell + %setenv LD_LIBRARY_PATH ${ORACLE_HOME}/lib:${LD_LIBRARY_PATH} + + Refer to platform specific documentation for setting up the above. + +Database Setup: +-------------- + Before running the demo, add the following lines to your init.ora file: + compatible = 9.0.0.0.0 # or higher + aq_tm_processes = 1 + job_queue_processes = 2 + + shutdown and restart the database. + +Compilation: +------------ + + 2. The Jpublisher classes can be optionally generated using the following + syntax. + + jpub -user=aqjava/aqjava -sql=ADDRESS,PERSON -case=mixed -methods=false + jpub -user=jmsuser/JMSUSER -sql=Emp -case=mixed -methods=false + jpub -user=jmsuser/JMSUSER -sql=Cars -case=mixed -methods=false + + +How to Run the JMS API demos: +----------------------------- + +1. Verify the CLASSPATH and PATH setup based on platform and jdk version. + +2. Compile the demos + + %javac aqjmsdemo*.java aqorademo*.java + + Refer to the individual demos files for more information. + +3. Run the setup scripts + + % sqlplus system/manager @aqjmsdmo.sql + creates jmsuser user + + % sqlplus system/manager @aqoradmo.sql + creates aqjava user + +4. Run the demos + + %java aqjmsdemo01 [SID] [HOST] [PORT] [DRIVER] + %java aqjmsdemo02 [SID] [HOST] [PORT] [DRIVER] + %java aqjmsdemo03 [SID] [HOST] [PORT] [DRIVER] + %java aqjmsdemo04 [SID] [HOST] [PORT] [DRIVER] + %java aqjmsdemo05 [SID] [HOST] [PORT] [DRIVER] + %java aqjmsdemo06 [SID] [HOST] [PORT] [DRIVER] + %java aqjmsdemo07 [SID] [HOST] [PORT] [DRIVER] + %java aqjmsdemo08 [SID] [HOST] [PORT] [DRIVER] + %java aqjmsdemo09 [SID] [HOST] [PORT] [DRIVER] + %java aqjmsdemo10 [SID] [HOST] [PORT] + + %java aqorademo01 [SID] [HOST] [PORT] [DRIVER] + %java aqorademo02 [SID] [HOST] [PORT] [DRIVER] + + Example: + java aqjmsdemo01 orcl dlsun673 1521 thin + +5. Drop demo scripts + + % sqlplus system/manager @aqjmsdrp.sql + drops jmsuser user + + % sqlplus system/manager @aqoradrp.sql + drops aqjava user + + +How to Run the JMS KPRB Driver demos: +------------------------------------- + +1) Compile the demo + + % javac aqjmskprb01.java + +2) Create the test user and JMS Queue + (this creates jmsuser1 user and Queue jmsuser1.queue1) + + % sqlplus system/manager @aqjmskprb01a.sql + +3) Load the java demo class file into the database + + % loadjava -user jmsuser1/JMSUSER1 -v aqjmskprb01.class + +4) Define the java demo as a PL/SQL Java stored procedure + + % sqlplus jmsuser1/JMSUSER1 @aqjmskprb01b.sql + +5) Execute the demo program by calling it's PL/SQL procedure + + % sqlplus jmsuser1/JMSUSER1 @aqjmskprb01c.sql + +6) Drop demo scripts + (this drops user jmsuser1 and user's stored procedures) + + % sqlplus system/manager @aqjmskprb01d.sql + + diff --git a/aqjmsdemo01.java b/aqjmsdemo01.java new file mode 100644 index 0000000..3a9b469 --- /dev/null +++ b/aqjmsdemo01.java @@ -0,0 +1,222 @@ +/* $Header: aqjmsdemo01.java 05-jun-2007.15:10:19 aatam Exp $ */ + +/* Copyright (c) 2000, 2007, Oracle. All rights reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + aatam 06/05/07 - password need to be consistent + jleinawe 07/11/05 - jdk 1.5 + jleinawe 12/20/02 - update instructions + rbhyrava 01/09/01 - bug 1419924 + rbhyrava 11/14/00 - remove pwd at the end + rbhyrava 07/13/00 - fix compilation error + rbhyrava 03/16/00 - AQ jms demos + rbhyrava 03/15/00 - AQ JMS demo - Enqueue,Dequeue Text Message + rbhyrava 03/15/00 - Creation + */ + +/** + * @version $Header: aqjmsdemo01.java 05-jun-2007.15:10:19 aatam Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ +/*** + * This is a sample java file which uses Oracle JMS - Java Messaging Service + * API to Enqueue/Dequeue text Message. Rule-based subscription on message properties and/or the message content of a topic. + * + * This demo does the following: + * -- Setup a topic + * -- Create two Durable Subscribers.Specify a selector that represents + * a specification (selects) for the messages that the subscriber wishes + * to receive. + * -- Publish sereral Messages to the Topic + * -- Receive the Messages for each subscriber + * + * Instructions for setting up and running this demo are found in + * aqjmsREADME.txt. + * + ***/ +/* import useful packages */ +import oracle.AQ.*; +import oracle.jms.*; +import javax.jms.*; +import java.lang.*; + +public class aqjmsdemo01 +{ + public static void main (String args []) + throws java.sql.SQLException, ClassNotFoundException, JMSException + { + TopicSession tsess = null; + TopicConnectionFactory tcfact =null; + TopicConnection tconn =null; + try + { + if (args.length < 4 ) + System.out.println("Usage:java filename [SID] [HOST] [PORT] [DRIVER]"); + else { + tcfact = AQjmsFactory.getTopicConnectionFactory( + args[1], args[0], Integer.parseInt(args[2]), args[3]); + + tconn = tcfact.createTopicConnection( "jmsuser","JMSUSER"); + + /* Create a Topic Session */ + tsess = tconn.createTopicSession(true, Session.CLIENT_ACKNOWLEDGE); + + tconn.start() ; + setupTopic(tsess) ; + performJmsOperations(tsess); + tsess.close() ; + tconn.close() ; + System.out.println("End of Demo") ; + } + } + catch (Exception ex) + { + System.out.println("Exception-1: " + ex); + ex.printStackTrace(); + } + } + + public static void setupTopic(TopicSession tsess) throws Exception + { + AQQueueTableProperty qtprop ; + AQQueueTable qtable; + AQjmsDestinationProperty dprop; + Topic topic; + try { + /* Create Queue Tables */ + System.out.println("Creating Input Queue Table...") ; + + /* Drop the queue if already exists */ + try { + qtable=((AQjmsSession)tsess).getQueueTable("jmsuser", "jmsqtable" ); + qtable.drop(true); + } catch (Exception e) {} ; + + qtprop = new AQQueueTableProperty ("SYS.AQ$_JMS_TEXT_MESSAGE") ; + qtprop.setMultiConsumer(true) ; + qtprop.setCompatible("8.1") ; + qtprop.setPayloadType("SYS.AQ$_JMS_TEXT_MESSAGE") ; + qtable = ((AQjmsSession)tsess).createQueueTable("JMSUSER", + "jmsqtable", qtprop) ; + + System.out.println ("Creating Topic input_queue..."); + dprop = new AQjmsDestinationProperty() ; + topic=((AQjmsSession)tsess).createTopic( qtable,"jmstopic",dprop) ; + + /* Start the topic */ + ((AQjmsDestination)topic).start(tsess, true, true); + System.out.println("Successfully setup Topic"); + } catch (Exception ex) { + System.out.println("Error in setupTopic: " + ex); + throw ex; + } + } + + public static void performJmsOperations(TopicSession tsess) + { + Topic topic =null; + TopicSubscriber tsub1,tsub2; + TopicPublisher publisher; + TextMessage txtmsg, dtxtmsg; + + try + { + System.out.println ("Get the Topic..."); + topic = ((AQjmsSession)tsess).getTopic("JMSUSER","jmstopic") ; + + System.out.println("Creating Topic Subscribers...") ; + + tsub1 = tsess.createDurableSubscriber(topic, "dallas", + "(year = 1998 OR color NOT IN ('GREEN','RED','WHITE')) "+ + " AND make IN ('ACURA ', 'BMW', 'MERCEDES')", false); + + tsub2 = tsess.createDurableSubscriber(topic, "atlanta", + "price < 20000", false ); + + System.out.println("Publish messages...") ; + publisher = tsess.createPublisher(topic); + + + txtmsg = tsess.createTextMessage() ; + txtmsg.setText("Cars Distribution") ; + txtmsg.setObjectProperty("carno", new Integer(12345)) ; + txtmsg.setStringProperty("color", "BLUE") ; + txtmsg.setIntProperty("year", 1999) ; + txtmsg.setStringProperty("make", "BMW") ; + txtmsg.setDoubleProperty("price", 25995) ; + txtmsg.setJMSCorrelationID("dallas") ; + + publisher.publish(topic, txtmsg) ; + + txtmsg.clearProperties() ; + txtmsg.setObjectProperty("carno", new Integer(55)) ; + txtmsg.setStringProperty("color", "CYAN") ; + txtmsg.setIntProperty("year", 2000) ; + txtmsg.setStringProperty("make", "MERCEDES") ; + txtmsg.setDoubleProperty("price", 19000) ; + txtmsg.setJMSCorrelationID("atlanta") ; + publisher.publish(topic, txtmsg) ; + + txtmsg.clearProperties() ; + txtmsg.setObjectProperty("carno", new Integer(99099)) ; + txtmsg.setStringProperty("color", "RED") ; + txtmsg.setIntProperty("year", 1998) ; + txtmsg.setStringProperty("make", "ACURA") ; + txtmsg.setDoubleProperty("price", 19995) ; + txtmsg.setJMSCorrelationID("atlanta") ; + publisher.publish(topic, txtmsg) ; + + tsess.commit() ; + + /* Receive the text Message for two subscribers */ + boolean done=false ; + System.out.println ("Dequeue Message for Subscriber 1") ; + while (!done) { + dtxtmsg = (TextMessage) (tsub1.receiveNoWait() ) ; + + if (dtxtmsg == null) { + done=true; + } else + { + System.out.print(" Color: " + dtxtmsg.getStringProperty("color")); + System.out.print(" Make: " + dtxtmsg.getStringProperty("make")); + System.out.print(" Year: " + dtxtmsg.getStringProperty("year")); + System.out.print(" Price: " + dtxtmsg.getStringProperty("price")); + System.out.println(" Carno: " + dtxtmsg.getStringProperty("carno")); + } + } + + System.out.println ("Dequeue Message for Subscriber 2") ; + + done=false ; + while (!done) { + dtxtmsg = (TextMessage) (tsub2.receive(1) ) ; + if ( dtxtmsg == null ) { + done=true ; + } else { + System.out.print(" Color: " + dtxtmsg.getStringProperty("color")); + System.out.print(" Make: " + dtxtmsg.getStringProperty("make")); + System.out.print(" Year: " + dtxtmsg.getStringProperty("year")); + System.out.print(" Price: " + dtxtmsg.getStringProperty("price")); + System.out.println(" Carno: " + dtxtmsg.getStringProperty("carno")); + } + } + tsess.commit() ; + ((AQjmsDestination)topic).stop(tsess, true, true, false); + + } catch (Exception e) { + System.out.println("Error in performJmsOperations: " + e) ; + } + } +} diff --git a/aqjmsdemo02.java b/aqjmsdemo02.java new file mode 100644 index 0000000..8561194 --- /dev/null +++ b/aqjmsdemo02.java @@ -0,0 +1,214 @@ +/* $Header: aqjmsdemo02.java 05-jun-2007.15:10:20 aatam Exp $ */ + +/* Copyright (c) 2000, 2007, Oracle. All rights reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + aatam 06/05/07 - password need to be consistent + jleinawe 07/11/05 - jdk 1.5 + jleinawe 12/20/02 - update instructions + rbhyrava 01/09/01 - bug 1419924 + rbhyrava 03/16/00 - AQ jms demos + rbhyrava 03/15/00 - AQ JMS demo - Message Listener Demo - Enqueue Messag + rbhyrava 03/15/00 - Creation + */ + +/** + * @version $Header: aqjmsdemo02.java 05-jun-2007.15:10:20 aatam Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ + + + +/*** + * This is a sample java file which uses Oracle JMS - Java Messaging Service + * API to Publish messages into topic. aqjmsdemo04 will demonstrate the + * Subscribers receiving the messages asynchronously using Message Listener + * aqjmsdemo02 - enqueues the messages to the queue + * aqjmsdemo03 - setup Message Listener and dequeue the messages + + * This demo does the following: + * -- Create a Queue + * -- Send several MAP messages + * + * Instructions for setting up and running this demo are found in + * aqjmsREADME.txt. + ***/ + +/* import useful packages */ +import oracle.AQ.*; +import oracle.jms.*; +import javax.jms.*; +import java.lang.*; + +public class aqjmsdemo02 +{ + public static void main (String args []) + throws java.sql.SQLException, ClassNotFoundException, JMSException + { + QueueSession qsess = null; + QueueConnectionFactory qcfact; + QueueConnection qconn; + try + { + if (args.length < 4 ) + System.out.println("Usage:java filename [SID] [HOST] [PORT] [DRIVER]"); + else { + //args passed are sid,host,port,driver + qcfact = AQjmsFactory.getQueueConnectionFactory( + args[1], args[0], Integer.parseInt(args[2]), args[3]); + + /* Create Queue Connection */ + qconn = qcfact.createQueueConnection( "jmsuser","JMSUSER"); + + /* Create a Queue Session */ + qsess = qconn.createQueueSession(true, Session.CLIENT_ACKNOWLEDGE); + + qconn.start() ; + setupQueue(qsess) ; + enqueueMessages(qsess); + System.out.println("End of Demo") ; + qsess.close() ; + qconn.close() ; + } + } + catch (Exception ex) + { + System.out.println("Exception-1: " + ex); + ex.printStackTrace(); + } + } + + public static void setupQueue(QueueSession qsess) throws Exception + { + AQQueueTableProperty qtprop ; + AQQueueTable qtable; + AQjmsDestinationProperty dprop; + javax.jms.Queue q1; + try { + + /* Create Queue Tables */ + System.out.println("Creating Queue Table...") ; + + qtprop = new AQQueueTableProperty ("SYS.AQ$_JMS_MAP_MESSAGE") ; + qtprop.setCompatible("8.1") ; + qtprop.setPayloadType("SYS.AQ$_JMS_MAP_MESSAGE") ; + + /* Drop if the queue table already exists */ + try { + qtable=((AQjmsSession)qsess).getQueueTable("JMSUSER", "JMSQTABLE"); + qtable.drop(true); + } catch (Exception e) {} + + qtable = ((AQjmsSession)qsess).createQueueTable("JMSUSER", + "jmsqtable", qtprop) ; + + System.out.println ("Creating Queue..."); + dprop = new AQjmsDestinationProperty() ; + q1=((AQjmsSession)qsess).createQueue(qtable,"JMSMAPQ",dprop) ; + + /* Start the Queue */ + ((AQjmsDestination)q1).start(qsess, true, true); + + System.out.println("Successfully setup Queue"); + } catch (Exception ex) { + System.out.println("Error in setupTopic: " + ex); + throw ex; + } + } + + public static void enqueueMessages(QueueSession qsess) throws Exception + { + javax.jms.Queue q1 ; + MapMessage[] Messages; + byte[] barray ; + QueueSender qsender; + + TopicSubscriber tsub1,tsub2; + TopicPublisher publisher; + StringBuffer txtbuf ; + TextMessage txtmsg, dtxtmsg; + try + { + /* Get Queue */ + q1 = ((AQjmsSession)qsess).getQueue("JMSUSER", "JMSMAPQ") ; + + System.out.println("Send messages...") ; + + barray = new byte[25] ; + for ( int i=0 ; i< 25 ; i++) barray[i] = 67 ; + + Messages = new MapMessage[5] ; + + Messages[0] = qsess.createMapMessage() ; + Messages[0].setIntProperty ("carno", 3355) ; + Messages[0].setStringProperty ("color", "BLUE") ; + Messages[0].setStringProperty ("make", "BMW") ; + Messages[0].setDoubleProperty ("price", 20000) ; + Messages[0].setIntProperty ("year", 1999) ; + + Messages[1] = qsess.createMapMessage() ; + Messages[1].setIntProperty ("carno", 4444) ; + Messages[1].setStringProperty ("color", "BLACK") ; + Messages[1].setStringProperty ("make", "ACURA") ; + Messages[1].setDoubleProperty ("price", 22995) ; + Messages[1].setIntProperty ("year", 1998) ; + + Messages[2] = qsess.createMapMessage() ; + Messages[2].setIntProperty ("carno", 1212) ; + Messages[2].setStringProperty ("color", "BLUE") ; + Messages[2].setStringProperty ("make", "MERCEDES") ; + Messages[2].setDoubleProperty ("price", 30995) ; + Messages[2].setIntProperty ("year", 2001) ; + + Messages[3] = qsess.createMapMessage() ; + Messages[3].setIntProperty ("carno", 5345) ; + Messages[3].setStringProperty ("color", "GREEN") ; + Messages[3].setStringProperty ("make", "LEXUS") ; + Messages[3].setDoubleProperty ("price", 21895) ; + Messages[3].setIntProperty ("year", 1995) ; + + Messages[4] = qsess.createMapMessage() ; + Messages[4].setIntProperty ("carno", 8909) ; + Messages[4].setStringProperty ("color", "BLUE") ; + Messages[4].setStringProperty ("make", "BMW") ; + Messages[4].setDoubleProperty ("price", 40995) ; + Messages[4].setIntProperty ("year", 2002) ; + + /* Create Queue Sender */ + qsender = qsess.createSender(q1) ; + + for ( int i = 0 ; i < 5 ; i++ ) + { + Messages[i].setBytes("Picture" , barray) ; + Messages[i].setJMSCorrelationID(Messages[i].getStringProperty("color")); + System.out.println("Sending "+Messages[i].getStringProperty ("color") + + " " + Messages[i].getStringProperty("make") + + " " + Messages[i].getIntProperty("year") + + " " + Messages[i].getDoubleProperty("price")) ; + + qsender.send(q1, Messages[i], DeliveryMode.PERSISTENT, + 1+ (i%10) , AQjmsConstants.EXPIRATION_NEVER ) ; + try { + Thread.sleep(5000) ; + } catch (InterruptedException e) {} ; + qsess.commit() ; + } + System.out.println("Successfully Sent Messages."); + + } catch (JMSException e) { + System.out.println("Error in Sending Messages : " + e) ; + throw e; + } + } +} diff --git a/aqjmsdemo03.java b/aqjmsdemo03.java new file mode 100644 index 0000000..8fe7960 --- /dev/null +++ b/aqjmsdemo03.java @@ -0,0 +1,130 @@ +/* $Header: aqjmsdemo03.java 05-jun-2007.15:10:22 aatam Exp $ */ + +/* Copyright (c) 2000, 2007, Oracle. All rights reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + aatam 06/05/07 - password need to be consistent + jleinawe 07/11/05 - + jleinawe 12/20/02 - update instructions + rbhyrava 03/01/02 - increase sleep + rbhyrava 01/25/02 - increase sleep time + lzhao 06/26/01 - comment + rbhyrava 01/09/01 - bug 1419924 + rbhyrava 03/15/00 - AQ JMS demo - Message Listener Demo + rbhyrava 03/15/00 - Creation + */ + +/** + * @version $Header: aqjmsdemo03.java 05-jun-2007.15:10:22 aatam Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ + +/* Message Listener */ +/*** + * This is a sample java file which uses Oracle JMS - Java Messaging Service + * API where Subscribers can Recieve messages asynchronously using + * MessageListener + * Subscribers receiveing the messages asynchronously using Message Listener + * aqjmsdemo02 - enqueues the messages to the queue + * aqjmsdemo03 - setup Message Listener and dequeue the messages + * This demo does the following: + * -- Get the Queue already created in aqjmsdemo03.java + * -- Create Receiver for the Queue + * -- Setup the message listener for Queue Receiver + * -- Start the connection + * -- Recieve the messages + * -- Stop the connection + * + * Instructions for setting up and running this demo are found in + * aqjmsREADME.txt. + ***/ + +/* import useful packages */ + +/* import useful packages */ +import oracle.AQ.*; +import oracle.jms.*; +import javax.jms.*; +import java.lang.*; + +public class aqjmsdemo03 +{ + + public static void main (String args []) + throws java.sql.SQLException, ClassNotFoundException, JMSException + { + QueueSession qsess = null; + QueueConnectionFactory qcfact; + QueueConnection qconn; + try + { + if (args.length < 4 ) + System.out.println("Usage:java filename [SID] [HOST] [PORT] [DRIVER]"); + else { + qcfact = AQjmsFactory.getQueueConnectionFactory( + args[1], args[0], Integer.parseInt(args[2]), args[3]); + qconn = qcfact.createQueueConnection( "jmsuser","JMSUSER"); + /* Create a Queue Session */ + qsess = qconn.createQueueSession(true, Session.CLIENT_ACKNOWLEDGE); + System.out.println("Successfully created QueueSession"); + + qconn.start() ; + demoMessageListener(qsess); + qsess.close() ; + qconn.close() ; + System.out.println("End of Demo") ; + } + } + catch (Exception ex) + { + System.out.println("Exception-1: " + ex); + ex.printStackTrace(); + } + } + + public static void demoMessageListener(QueueSession qsess) throws Exception + { + javax.jms.Queue queue; + QueueReceiver qrecv ; + MessageListener mLis ; + + try + { + System.out.println("Get the Queue") ; + /* Get the Queue */ + /* Queue JMSMAPQ is created in aqjmsdemo02 */ + queue = ((AQjmsSession)qsess).getQueue("JMSUSER", "JMSMAPQ") ; + + System.out.println("Create Receiver...") ; + + /* Create a queue receiever */ + qrecv = qsess.createReceiver(queue, "JMSCorrelationID='BLUE'") ; + + /* Setup the message listener */ + System.out.println("Set Message Listener... and Sleep...") ; + mLis = new MesgListener(qsess); + qrecv.setMessageListener (mLis) ; + + try { + Thread.sleep(250000) ; + } catch (InterruptedException e) {} ; + + System.out.println("Successfully dequeued with MessageListener") ; + + } catch (JMSException e) { + System.out.println("Error in demoMessageListener: " +e ) ; + throw e; + } + } +} diff --git a/aqjmsdemo04.java b/aqjmsdemo04.java new file mode 100644 index 0000000..ec0cfb9 --- /dev/null +++ b/aqjmsdemo04.java @@ -0,0 +1,238 @@ +/* $Header: aqjmsdemo04.java 05-jun-2007.15:10:23 aatam Exp $ */ + +/* Copyright (c) 2000, 2007, Oracle. All rights reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + aatam 06/05/07 - password need to be consistent + jleinawe 07/11/05 - + jleinawe 12/20/02 - update instructions + rbhyrava 03/01/02 - use ORAData + rbhyrava 01/09/01 - bug 1419924 + rbhyrava 03/16/00 - AQ jms demos + rbhyrava 03/15/00 - AQ JMS demo - Object Type Payload + rbhyrava 03/15/00 - Creation + */ + +/** + * @version $Header: aqjmsdemo04.java 05-jun-2007.15:10:23 aatam Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ +/*** + * This is a sample java file which uses Oracle JMS - Java Messaging Service + * API to Publish/Receive messages to/from topic. The Oracle Type Payload is + * used. Dequeue is based on the Payload content + * This is an Oracle Extention to JMS. + * This demo does the following: + * -- Create a multi-consumer topic with Payload type as EMP + * Refer to aqjmsdemo.sql for definition of EMP and CARS Object Type + definitions + * -- Create a Topic Publisher + * -- Create two durable subscribers based on the Payload content + * -- Publish messages + * -- Receive the messages for both the subscribers + * + * Instructions for setting up and running this demo are found in + * aqjmsREADME.txt. + ***/ + +/* import useful packages */ +import oracle.AQ.*; +import oracle.jms.*; +import javax.jms.*; +import java.lang.*; + +public class aqjmsdemo04 +{ + public static void main (String args []) + throws java.sql.SQLException, ClassNotFoundException, JMSException + { + TopicSession tsess = null; + TopicConnectionFactory tcfact=null; + TopicConnection tconn=null; + try + { + if (args.length < 4 ) + System.out.println("Usage:java filename [SID] [HOST] [PORT] [DRIVER]"); + else { + tcfact = AQjmsFactory.getTopicConnectionFactory( + args[1], args[0], Integer.parseInt(args[2]), args[3]); + + tconn = tcfact.createTopicConnection( "jmsuser","JMSUSER"); + + /* Create a Topic Session */ + tsess = tconn.createTopicSession(true, Session.CLIENT_ACKNOWLEDGE); + tconn.start() ; + setupTopic(tsess) ; + publishReceiveMessages(tsess); + tsess.close() ; + tconn.close() ; + System.out.println("End of Demo") ; + } + } + catch (Exception ex) + { + System.out.println("Exception-1: " + ex); + ex.printStackTrace(); + } + } + + public static void setupTopic(TopicSession tsess) throws Exception + { + AQQueueTableProperty qtprop ; + AQQueueTable qtable; + AQjmsDestinationProperty dprop; + Topic topic; + try { + /* Create Queue Tables */ + System.out.println("Creating Queue Table...") ; + /* Drop the queue if already exists */ + try { + qtable=((AQjmsSession)tsess).getQueueTable("jmsuser", "jmsadtqueue"); + qtable.drop(true); + } catch (Exception e) {} ; + + qtprop = new AQQueueTableProperty ("EMP") ; + qtprop.setComment("EMP queue") ; + qtprop.setMultiConsumer(true) ; + qtprop.setCompatible("8.1") ; + qtprop.setPayloadType("JMSUSER.EMP") ; + + qtable = ((AQjmsSession)tsess).createQueueTable("JMSUSER", + "JMSADTQUEUE", qtprop) ; + + System.out.println ("Creating Topic EMPCARS..."); + dprop = new AQjmsDestinationProperty() ; + dprop.setComment("create topic") ; + topic= ((AQjmsSession)tsess).createTopic( qtable,"EMPCARS",dprop); + + /* Start the topic */ + ((AQjmsDestination)topic).start(tsess, true, true); + System.out.println("Successfully setup Topic"); + } catch (Exception ex) { + System.out.println("Error in setupTopic: " + ex); + throw ex; + } + } + + public static void publishReceiveMessages(TopicSession tsess) + throws Exception + { + Topic topic =null; + TopicSubscriber[] subs; + TopicPublisher publisher; + StringBuffer txtbuf ; + AdtMessage adt_msg; + Emp empmsg, rmsg; + Cars c; + try + { + + /* Get the topic */ + System.out.println("Getting the Topic...") ; + topic = ((AQjmsSession)tsess).getTopic("JMSUSER", "EMPCARS"); + + System.out.println("Creating Topic Subscribers...") ; + subs = new TopicSubscriber[2] ; + + subs[0] = ((AQjmsSession)tsess).createDurableSubscriber(topic, + "PROG1", "TAB.USER_DATA.CAROWN.COLOR = 'RED'", + false, Emp.getORADataFactory()) ; + subs[1] = ((AQjmsSession)tsess).createDurableSubscriber(topic, + "PROG2", "TAB.USER_DATA.RANK > 2", + false, Emp.getORADataFactory()) ; + + System.out.println("Create a Publisher...") ; + publisher = tsess.createPublisher(topic); + + adt_msg = ((AQjmsSession)tsess).createAdtMessage() ; + + String[] names={"KING JOE","SCOTT RAY","ADITYA NELLORE","LORI MAXWELL" }; + int[] rank={1,2,3,4} ; + String color[] = {"YELLOW", "RED", "BLUE","RED" } ; + String make[] = {"BMW", "ACURA", "MERCEDES","LEXUS" } ; + empmsg = new Emp() ; + c = new Cars() ; + + System.out.println("Publish messages...") ; + + for ( int i = 1 ; i < 4 ; i++) + { + java.math.BigDecimal id = new java.math.BigDecimal(i) ; + empmsg.setId(id) ; + empmsg.setName(names[i]) ; + empmsg.setRank(new java.math.BigDecimal(rank[i])) ; + c.setCarno(new java.math.BigDecimal(1000 + i)) ; + c.setMake(make[i] ); + c.setColor(color[i] ); + c.setPrice(new java.math.BigDecimal(10000 * i) ); + empmsg.setCarown(c) ; + + adt_msg.clearProperties() ; + //adt_msg.setJMSCorrelationID(new Integer(100+i) ) ; + adt_msg.setAdtPayload(empmsg) ; + adt_msg.setJMSPriority(1+(i%3)) ; + publisher.publish(topic,adt_msg, DeliveryMode.PERSISTENT, + 1+(i%3),AQjmsConstants.EXPIRATION_NEVER); + + System.out.print("Sent Message Pri: " +adt_msg.getJMSPriority()) ; + System.out.print(" Id: " +empmsg.getId()) ; + System.out.print(" Name: " +empmsg.getName()) ; + System.out.print(" Rank: " +empmsg.getRank()) ; + System.out.print(" Car: " +empmsg.getCarown().getColor()) ; + System.out.println(" " +empmsg.getCarown().getMake()) ; + } + + System.out.println("Commit") ; + tsess.commit() ; + + Thread.sleep(500); + + System.out.println("Receive Messages...") ; + + /* Receive messages for each subscriber */ + + for (int i=0; i< subs.length ; i++) + { + System.out.println ("Messages for subscriber : " +i) ; + boolean more = true; + while(more) { + try { + adt_msg = (AdtMessage)( subs[i].receiveNoWait() ); + if (adt_msg != null) + { + rmsg = (Emp) (adt_msg.getAdtPayload()); + System.out.print("Priority : " +adt_msg.getJMSPriority()) ; + System.out.print(" Id: " +rmsg.getId()) ; + System.out.print(" Name: " +rmsg.getName()) ; + System.out.print(" Rank: " +rmsg.getRank()) ; + System.out.print(" Car: " +rmsg.getCarown().getColor()) ; + System.out.println(" " +rmsg.getCarown().getMake()) ; + } + else { + System.out.println ("No more messages.") ; + more=false; + } + tsess.commit(); + } catch (Exception e) { + System.out.println ("Error in Receive: " + e) ; + more=false; + } + } /* while loop*/ + } + } catch (Exception e) { + System.out.println("Error in publish receive Messages: " + e) ; + throw e; + } + } +} diff --git a/aqjmsdemo05.java b/aqjmsdemo05.java new file mode 100644 index 0000000..a2f8d33 --- /dev/null +++ b/aqjmsdemo05.java @@ -0,0 +1,234 @@ +/* $Header: aqjmsdemo05.java 05-jun-2007.15:10:24 aatam Exp $ */ + +/* Copyright (c) 2000, 2007, Oracle. All rights reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + aatam 06/05/07 - password need to be consistent + aatam 06/27/06 - fix Queue is ambiguous error + jleinawe 07/11/05 - + jleinawe 12/20/02 - update instructions + rbhyrava 01/09/01 - bug 1419924 + rbhyrava 03/15/00 - AQ JMS demo - Queue Browser + rbhyrava 03/15/00 - Creation + */ + +/** + * @version $Header: aqjmsdemo05.java 05-jun-2007.15:10:24 aatam Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ + +/*** + * This is a sample java file which uses Oracle JMS - Java Messaging Service + * API to demonstrate QueueBrowser. + * Client uses a QueueBrowser to view messages on a queue without removing them. + * + * This demo does the following: + * -- Create a single consumer queue of Payload type as CARS + * Refer to aqjmsdemo.sql for definition of CARS Object Type + * -- Create a Queue Sender + * -- Create a Queue Browser with Message Selector ; + messages delivered to the browser to those that match the selector. + * -- Save the message Ids + * -- Dequeue the messages based on the Message ids + * + * Instructions for setting up and running this demo are found in + * aqjmsREADME.txt. + * + ***/ + +/* import useful packages */ +import oracle.AQ.*; +import oracle.jms.*; +import javax.jms.*; +import java.lang.*; +import java.util.* ; +public class aqjmsdemo05 +{ + public static void main (String args []) + throws java.sql.SQLException, ClassNotFoundException, JMSException + { + QueueSession qsess = null; + QueueConnectionFactory qcfact=null; + QueueConnection qconn=null; + try + { + if (args.length < 4 ) + System.out.println("Usage:java filename [SID] [HOST] [PORT] [DRIVER]"); + else { + qcfact = AQjmsFactory.getQueueConnectionFactory( + args[1], args[0], Integer.parseInt(args[2]), args[3]); + + qconn = qcfact.createQueueConnection( "jmsuser","JMSUSER"); + + /* Create a Queue Session */ + qsess = qconn.createQueueSession(true, Session.CLIENT_ACKNOWLEDGE); + + qconn.start() ; + setupQueue(qsess) ; + sendMessages(qsess) ; + queueBrowserDemo(qsess); + qsess.close() ; + qconn.close() ; + System.out.println("End of Demo") ; + } + } + catch (Exception ex) + { + System.out.println("Exception-1: " + ex); + ex.printStackTrace(); + } + } + + public static void setupQueue(QueueSession qsess) throws Exception + { + AQQueueTable qtable=null; + AQQueueTableProperty qtprop; + AQjmsDestinationProperty dprop; + javax.jms.Queue queue; + try { + /* Create Queue Tables */ + System.out.println("Creating Queue Table...") ; + + /* Drop the queue if already exists */ + try { + qtable=((AQjmsSession)qsess).getQueueTable("jmsuser", "jmsqbtable" ); + qtable.drop(true); + } catch (Exception e) {} ; + + qtprop = new AQQueueTableProperty ("SYS.AQ$_JMS_TEXT_MESSAGE") ; + qtprop.setPayloadType("SYS.AQ$_JMS_TEXT_MESSAGE") ; + + qtable = ((AQjmsSession)qsess).createQueueTable("JMSUSER", + "jmsqbtable", qtprop) ; + + System.out.println ("Creating Queue jmsqb..."); + dprop = new AQjmsDestinationProperty() ; + queue=((AQjmsSession)qsess).createQueue( qtable,"jmsqb",dprop) ; + + /* Start the Queue */ + ((AQjmsDestination)queue).start(qsess, true, true); + System.out.println("Successfully setup Queue"); + } catch (Exception ex) { + System.out.println("Error in setupQueue: " + ex); + throw ex; + } + } + + public static void sendMessages(QueueSession qsess) throws Exception + { + javax.jms.Queue q1; + QueueSender qsender ; + TextMessage txtmsg; + StringBuffer txtbuf; + String color[] = {"YELLOW", "RED", "BLUE","RED" } ; + String make[] = {"BMW", "ACURA", "MERCEDES","LEXUS" } ; + try + { + System.out.println ("get Queue JMSQB"); + q1=((AQjmsSession)qsess).getQueue("JMSUSER","JMSQB") ; + + System.out.println("Send messages...") ; + /* Create Queue Sender */ + qsender = qsess.createSender(q1) ; + + txtbuf = new StringBuffer() ; + txtbuf.append ("Favorite Cars") ; + txtmsg = ((AQjmsSession)qsess).createTextMessage(txtbuf) ; + + for (int i =0; i < 4 ; i++) { + txtmsg.setIntProperty("carno",1000 + i) ; + txtmsg.setStringProperty("make", make[i]) ; + txtmsg.setIntProperty ("year",1999 + i) ; + txtmsg.setDoubleProperty("price",10000*(i+1)); + txtmsg.setStringProperty("color",color[i]) ; + txtmsg.setJMSCorrelationID(color[i]+"-"+make[i]) ; + + qsender.send(q1, txtmsg, DeliveryMode.PERSISTENT, 1+ (i%10), + AQjmsConstants.EXPIRATION_NEVER) ; + + byte[] msgid =((AQjmsMessage)txtmsg).getJMSMessageIDAsBytes() ; + System.out.println("Sent "+ txtmsg.getStringProperty("color") + + " " + txtmsg.getStringProperty("make") + + " " + txtmsg.getIntProperty("year") ) ; + } + qsess.commit(); + + }catch (Exception e) { + System.out.println("Error in SendMessages : " + e) ; + throw e; + } + } + + public static void queueBrowserDemo(QueueSession qsess) throws JMSException + { + javax.jms.Queue q1; + QueueBrowser qb; + Enumeration q1_enum ; + String[] msgids ; + int cnt=0; + TextMessage tmsg; + QueueReceiver qr ; + try + { + /* Get the queue */ + System.out.println("Get the Queue..") ; + q1= ((AQjmsSession)qsess).getQueue("JMSUSER", "JMSQB") ; + /* Create Queue Browser */ + System.out.println("Create Queue Browser..") ; + qb = ((AQjmsSession)qsess).createBrowser(q1, + "JMSCorrelationID LIKE 'RED%'", null, true); + + q1_enum = qb.getEnumeration() ; + + /* Browse the messages now */ + msgids = new String[10]; + while(q1_enum.hasMoreElements() == true ) + { + try { + tmsg = (TextMessage) (q1_enum.nextElement()) ; + msgids[cnt] = tmsg.getJMSMessageID() ; + System.out.println("MessageID is "+ msgids[cnt]) ; + cnt++ ; + System.out.println("Browser "+ tmsg.getStringProperty("color") + + " " + tmsg.getStringProperty("make") + + " " + tmsg.getIntProperty("year")) ; + + System.out.print(" Correlation id "+ tmsg.getJMSCorrelationID()); + System.out.println(" Priority "+ tmsg.getJMSPriority()); + + } catch (Exception e) { + System.out.println("Browser raised exception " + e) ; + } + } + + System.out.println("Now Dequeue Messages using message Ids") ; + for (int i =0; i< cnt; i++) { + + qr = ((AQjmsSession)qsess).createReceiver(q1, + "JMSMessageID = '"+msgids[i]+"'",null ) ; + + tmsg= (TextMessage)qr.receiveNoWait() ; + + System.out.println("Dequeued "+ tmsg.getStringProperty("color") + + " " + tmsg.getStringProperty("make") + + " " + tmsg.getIntProperty("year")) ; + qr.close() ; + } + qsess.commit(); + } catch (JMSException e) { + System.out.println("Error in QueueBrowserDemo : "+ e) ; + throw e ; + } + } /* end of demo06 */ +} diff --git a/aqjmsdemo06.java b/aqjmsdemo06.java new file mode 100644 index 0000000..acaa31a --- /dev/null +++ b/aqjmsdemo06.java @@ -0,0 +1,274 @@ +/* $Header: aqjmsdemo06.java 05-jun-2007.15:10:24 aatam Exp $ */ + +/* Copyright (c) 2000, 2007, Oracle. All rights reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + aatam 06/05/07 - password need to be consistent + jleinawe 07/11/05 - + jleinawe 03/12/03 - add unschedulePropagation call + jleinawe 12/20/02 - update instructions + rbhyrava 01/09/01 - bug 1419924 + rbhyrava 07/13/00 - fix typo + rbhyrava 03/16/00 - AQ jms demos + rbhyrava 03/15/00 - AQ JMS demo - Propagation + rbhyrava 03/15/00 - Creation + */ + +/** + * @version $Header: aqjmsdemo06.java 05-jun-2007.15:10:24 aatam Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ + +/*** + * This is a sample java file which uses Oracle JMS - Java Messaging Service + * API to schedule Propagation between Queues in Oracle database + * + * This demo is functionally same a newaqdemo01.sql and does the following: + * -- Create two queue tables - input_queue_table, prop_queue_table + * -- Create two queues - input_queue belonging to input_queue_table, + * prop_queue belonging to prop_queue_table + * -- Create two subscribers to input_queue - prog1, prog2 + * -- Create one subscribers to input_queue - prog3 at prop_queue + * -- Schedule propagation between input_queue and other queues in + * the database + * + * Instructions for setting up and running this demo are found in + * aqjmsREADME.txt. + * + ***/ + +/* Object Message */ + +/* import useful packages */ +import oracle.AQ.*; +import oracle.jms.*; +import javax.jms.*; +import java.lang.*; + +public class aqjmsdemo06 +{ + public static void main (String args []) + throws java.sql.SQLException, ClassNotFoundException, JMSException + { + TopicSession tsess = null; + TopicConnectionFactory tcfact=null; + TopicConnection tconn=null; + try + { + if (args.length < 4 ) + System.out.println("Usage:java filename [SID] [HOST] [PORT] [DRIVER]"); + else { + tcfact = AQjmsFactory.getTopicConnectionFactory( + args[1], args[0], Integer.parseInt(args[2]), args[3]); + + tconn = tcfact.createTopicConnection( "jmsuser","JMSUSER"); + + /* Create a Topic Session */ + tsess = tconn.createTopicSession(true, Session.CLIENT_ACKNOWLEDGE); + + tconn.start() ; + setupTopic(tsess) ; + performJmsOperations(tsess); + tsess.close(); + tconn.close(); + System.out.println("End of Demo") ; + } + } + catch (Exception ex) + { + System.out.println("Exception-1: " + ex); + ex.printStackTrace(); + } + } + + public static void setupTopic(TopicSession tsess) throws Exception + { + AQQueueTableProperty qtprop1,qtprop2 ; + AQQueueTable qtable,table1, table2; + AQjmsDestinationProperty dprop; + Topic topic1, topic2; + try { + /* Create Queue Tables */ + System.out.println("Creating Input Queue Table...") ; + + /* Drop the queue if already exists */ + try { + qtable=((AQjmsSession)tsess).getQueueTable("jmsuser", + "INPUT_QUEUE_TABLE" ); + qtable.drop(true); + } catch (Exception e) {} ; + try { + qtable=((AQjmsSession)tsess).getQueueTable("jmsuser", + "PROP_QUEUE_TABLE" ); + qtable.drop(true); + } catch (Exception e) {} ; + + qtprop1 = new AQQueueTableProperty ("SYS.AQ$_JMS_OBJECT_MESSAGE") ; + qtprop1.setComment("input queue") ; + qtprop1.setMultiConsumer(true) ; + qtprop1.setCompatible("8.1") ; + qtprop1.setPayloadType("SYS.AQ$_JMS_OBJECT_MESSAGE") ; + table1 = ((AQjmsSession)tsess).createQueueTable("JMSUSER", + "INPUT_QUEUE_TABLE", qtprop1) ; + + System.out.println("Creating Propagation Queue Table...") ; + qtprop2 = new AQQueueTableProperty ("SYS.AQ$_JMS_OBJECT_MESSAGE") ; + qtprop2.setComment("Popagation queue") ; + qtprop2.setPayloadType("SYS.AQ$_JMS_OBJECT_MESSAGE") ; + qtprop2.setMultiConsumer(true) ; + qtprop2.setCompatible("8.1") ; + table2 = ((AQjmsSession)tsess).createQueueTable("JMSUSER", + "PROP_QUEUE_TABLE", qtprop2) ; + + System.out.println ("Creating Topic input_queue..."); + dprop = new AQjmsDestinationProperty() ; + dprop.setComment("create topic 1") ; + topic1=((AQjmsSession)tsess).createTopic(table1,"INPUT_QUEUE",dprop) ; + + dprop.setComment("create topic 2") ; + topic2=((AQjmsSession)tsess).createTopic( table2,"PROP_QUEUE",dprop) ; + + /* Start the topic */ + ((AQjmsDestination)topic1).start(tsess, true, true); + ((AQjmsDestination)topic2).start(tsess, true, true); + System.out.println("Successfully setup Topics"); + + } catch (Exception ex) { + System.out.println("Error in setupTopic: " + ex); + throw ex; + } + + } + + + public static void performJmsOperations(TopicSession tsess) + throws Exception + { + Topic topic1,topic2; + TopicSubscriber[] subs; + AQjmsAgent agt; + ObjectMessage objmsg = null, robjmsg=null; + TopicPublisher publisher ; + Message sobj , rmsg; + String[] cities={"BELMONT","REDWOOD SHORES", "SUNNYVALE", "BURLINGAME" }; + try + { + + System.out.println("Get Topics...") ; + topic1 = ((AQjmsSession)tsess).getTopic("JMSUSER", "INPUT_QUEUE") ; + topic2 = ((AQjmsSession)tsess).getTopic("JMSUSER", "PROP_QUEUE") ; + + System.out.println("Creating Topic Subscribers...") ; + + subs = new TopicSubscriber[3] ; + subs[0] = ((AQjmsSession)tsess).createDurableSubscriber( + topic1, "PROG1", null, false); + subs[1] = ((AQjmsSession)tsess).createDurableSubscriber( + topic1, "PROG2", "JMSPriority > 2", false); + subs[2] = tsess.createDurableSubscriber( + topic2, "PROG3", null , false) ; + + agt = new AQjmsAgent("PROG3", "PROP_QUEUE" ) ; + + System.out.println("Creating Remote Subscriber...") ; + ((AQjmsSession)tsess).createRemoteSubscriber( + topic1, agt,"JMSPriority = 2"); + + /* Schedule Propagation with latency 0 */ + System.out.println("Schedule Propagation...") ; + ((AQjmsDestination)topic1).schedulePropagation( + tsess, null, null, null, null, new Double(0)) ; + + System.out.println("Publish messages...") ; + objmsg = ((AQjmsSession)tsess).createObjectMessage() ; + + publisher = tsess.createPublisher(topic1); + + /*publish 100 messages*/ + + for ( int i = 1 ; i <= 100 ; i++) + { + objmsg.setIntProperty("Id",i) ; + if ( ( i % 3 ) == 0 ) { + objmsg.setStringProperty("City",cities[0]) ; + } + else if ((i % 4 ) == 0) { + objmsg.setStringProperty("City",cities[1]) ; + } + else if (( i % 2) == 0) { + objmsg.setStringProperty("City",cities[2]) ; + } + else { + objmsg.setStringProperty("City",cities[3]) ; + } + + objmsg.setIntProperty("Priority",(1+ (i%3))) ; + + sobj = new Message() ; + sobj.setId(i) ; + sobj.setName("message# "+i) ; + sobj.setData(500); + objmsg.setObject(sobj) ; + objmsg.setJMSCorrelationID(""+i) ; + objmsg.setJMSPriority(1+(i%3)) ; + publisher.publish(topic1,objmsg, DeliveryMode.PERSISTENT, + 1 +(i%3), AQjmsConstants.EXPIRATION_NEVER); + } + System.out.println("Commit now...") ; + tsess.commit() ; + + Thread.sleep(50000); + + /* Receive messages for each subscriber */ + System.out.println("Receive Messages...") ; + for (int i=0; i< subs.length ; i++) + { + System.out.println ("Messages for subscriber : " +i) ; + if (subs[i].getMessageSelector() != null) + { + System.out.println(" with selector: " + + subs[i].getMessageSelector()); + } + + boolean done = false; + while(!done) { + try { + robjmsg = (ObjectMessage)( subs[i].receiveNoWait() ); + if (robjmsg != null) + { + rmsg = (Message)robjmsg.getObject(); + System.out.print("Name : " +rmsg.getName()) ; + System.out.print(" Pri: " +robjmsg.getJMSPriority()) ; + System.out.print(" Message: " +robjmsg.getIntProperty("Id")) ; + System.out.print(" " +robjmsg.getStringProperty("City")) ; + System.out.println(" " +robjmsg.getIntProperty("Priority")) ; + } + else { + System.out.println ("No more messages.") ; + done=true; + } + tsess.commit(); + } catch (Exception e) { + System.out.println("Error in performJmsOperations: " + e) ; + done=true; + } + } /* while loop*/ + } + ((AQjmsDestination)topic1).unschedulePropagation(tsess,null); + } catch (Exception e) { + System.out.println("Error in performJmsOperations: " + e) ; + throw e; + } + } /* end of demo06 */ +} diff --git a/aqjmsdemo07.java b/aqjmsdemo07.java new file mode 100644 index 0000000..72d0edf --- /dev/null +++ b/aqjmsdemo07.java @@ -0,0 +1,418 @@ +/* $Header: aqjmsdemo07.java 05-jun-2007.15:10:25 aatam Exp $ */ + +/* Copyright (c) 2002, 2007, Oracle. All rights reserved. */ + +/* + DESCRIPTION + AQ/OJMS XML payload demo + + PRIVATE CLASSES + + + NOTES + see below + + MODIFIED (MM/DD/YY) + aatam 06/05/07 - password need to be consistent + jleinawe 07/11/05 - + jleinawe 04/18/05 - update lcr format + jleinawe 12/20/02 - update instructions + rbhyrava 10/07/02 - import oracle.jdbc.* + jleinawe 09/04/02 - jleinawe_new_aq_demos + jleinawe 08/30/02 - Creation + */ + +/** + * @version $Header: aqjmsdemo07.java 05-jun-2007.15:10:25 aatam Exp $ + * @author jleinawe + * @since release specific (what release of product did this appear in) + */ + +/**** + * This is a sample java file which uses Oracle JMS - Java Message Service + * API to Enqueue/Dequeue an XML message using a sys.Anydata queue. + * + * This demo does the following: + * - creates an Anydata Queue + * - creates a QueueSender + * - sends a message containing an XML message body + * - create a QueueReceiver + * - receives and prints the XML message + * - drops the Anydata Queue + * + * Instructions for setting up and running this demo are found in + * aqjmsREADME.txt. + * + ***/ + +import javax.jms.*; +import java.sql.*; +import oracle.AQ.*; +import oracle.jms.*; +import oracle.xdb.*; + +public class aqjmsdemo07 +{ + + public static void main (String args []) + throws java.sql.SQLException, ClassNotFoundException, JMSException + { + try + { + String ora_sid; + String host; + int port; + try + { + ora_sid = args[0]; + host = args[1]; + port = Integer.parseInt(args[2]); + + System.out.println ("ora_sid: " + ora_sid); + System.out.println ("host: " + host); + System.out.println ("port: " + port); + + init(ora_sid, host, port); + EnqueueAnydata(ora_sid, host, port); + DequeueAnydata(ora_sid, host, port); + tearDown(ora_sid, host, port); + System.out.println("End of Demo"); + } + catch (ArrayIndexOutOfBoundsException ex) + { + System.out.println ("Not enough parameters. " + + "Usage: java filename [SID] [HOST] [PORT]\n" + + "\tExample: java aqjmsdemo07 orcl myserver 1521"); + return; + } + } + catch (Exception ex) + { + System.out.println("Exception: " + ex); + ex.printStackTrace(); + } + } + + + public static void EnqueueAnydata(String ora_sid, String host, int port) + { + QueueConnectionFactory qc_fact = null; + QueueConnection q_conn = null; + QueueSession q_sess = null; + java.sql.Connection db_conn = null; + AQQueueTableProperty qt_prop = null; + AQQueueTable q_table = null; + AQjmsDestinationProperty dest_prop = null; + javax.jms.Queue queue = null; + AdtMessage adt_msg = null; + QueueSender q_sender = null; + Message jms_msg = null; + oracle.xdb.XMLType xtype = null; + String data = null; + + + try + { + qc_fact = AQjmsFactory.getQueueConnectionFactory(host, + ora_sid, port, "oci8"); + + q_conn = qc_fact.createQueueConnection("jmsuser", "JMSUSER"); + q_sess = q_conn.createQueueSession(true, Session.CLIENT_ACKNOWLEDGE); + + q_conn.start(); + db_conn = ((AQjmsSession)q_sess).getDBConnection(); + + queue = ((AQjmsSession)q_sess).getQueue("jmsuser", "xmlq"); + + // + // create sender + // + q_sender = q_sess.createSender(queue); + + // + // create ade message + // + adt_msg = ((AQjmsSession)q_sess).createAdtMessage(); + + System.out.println("start xml convert"); + + data = " \n" + + "source_dbname \n" + + "INSERT \n" + + "RAM \n" + + "EMP \n" + + "0ABC \n" + + "0.0.0 \n" + + "0 \n" + + " \n" + + " \n" + + "C01 \n" + + "Clob old \n" + + " \n" + + " \n" + + "C02 \n" + + "A123FF \n" + + " \n" + + " \n" + + "C03 \n" + + " \n" + + "1997/11/24 00:00:00SYYYY/MM/DD HH24:MI:SS \n" + + " \n" + + " \n" + + " \n" + + "C04 \n" + + " \n" + + "1999/05/31 13:20:00.000000000SYYYY/MM/DD HH24:MI:SSXFF9 \n" + + " \n" + + " \n" + + " \n" + + "C05 \n" + + "0ABCDE \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "C01 \n" + + "A123FF \n" + + " \n" + + " \n" + + "C02 \n" + + "35.23 \n" + + " \n" + + " \n" + + "C03 \n" + + "-100000 \n" + + " \n" + + " \n" + + "C04 \n" + + "Hel lo \n" + + " \n" + + " \n" + + "C05 \n" + + "wor ld \n" + + " \n" + + " \n" + + ""; + + + xtype = oracle.xdb.XMLType.createXML(db_conn, data); + + adt_msg.setAdtPayload(xtype); + + System.out.println("Enqueue anydata(xmltype) message"); + + // + // send the message + // + ((AQjmsQueueSender)q_sender).send(queue, adt_msg, + DeliveryMode.PERSISTENT, 1, + AQjmsConstants.EXPIRATION_NEVER); + + q_sess.commit(); + q_sess.close(); + q_conn.close(); + + } + catch (java.sql.SQLException sql_ex) + { + System.out.println("Exception: " + sql_ex); + sql_ex.printStackTrace(); + } + catch (JMSException aq_ex) + { + System.out.println("Exception: " + aq_ex); + aq_ex.printStackTrace(); + + if(aq_ex.getLinkedException() != null) + { + aq_ex.getLinkedException().printStackTrace(); + } + } + + } + + + public static void DequeueAnydata(String ora_sid, String host, int port) + { + QueueConnectionFactory qc_fact = null; + QueueConnection q_conn = null; + QueueSession q_sess = null; + java.sql.Connection db_conn = null; + AQQueueTableProperty qt_prop = null; + AQQueueTable q_table = null; + AQjmsDestinationProperty dest_prop = null; + javax.jms.Queue queue = null; + AdtMessage adt_msg = null; + AdtMessage adt_msg2 = null; + QueueReceiver q_receiver= null; + TextMessage t_msg = null; + javax.jms.Message jms_msg = null; + oracle.xdb.XMLType xtype2 = null; + + try + { + qc_fact = AQjmsFactory.getQueueConnectionFactory(host, + ora_sid, port, "oci8"); + + q_conn = qc_fact.createQueueConnection("jmsuser", "JMSUSER"); + q_sess = q_conn.createQueueSession(true, Session.CLIENT_ACKNOWLEDGE); + + q_conn.start(); + db_conn = ((AQjmsSession)q_sess).getDBConnection(); + + // + // get queue xmlq + // + queue = ((AQjmsSession)q_sess).getQueue("jmsuser", "xmlq"); + + // + // Create receiver + // + q_receiver = ((AQjmsSession)q_sess).createReceiver(queue); + + // + // Receive message + // + jms_msg = (javax.jms.Message) q_receiver.receive(); + + // + // output message contents + // + if(jms_msg == null) + System.out.println("Null message received"); + else + { + if(jms_msg instanceof AdtMessage) + { + adt_msg2 = (AdtMessage)jms_msg; + System.out.println("Retrieved message: " + adt_msg2.getAdtPayload()); + + if(adt_msg2.getAdtPayload() instanceof oracle.xdb.XMLType) + { + xtype2 = (XMLType)adt_msg2.getAdtPayload(); + System.out.println("Data: \n" + xtype2.getStringVal()); + } + + System.out.println("Msg id: " + adt_msg2.getJMSMessageID()); + q_sess.commit(); + } + else + System.out.println("Invalid message type"); + } + q_conn.close(); + } + catch (java.sql.SQLException sql_ex) + { + System.out.println("Exception: " + sql_ex); + sql_ex.printStackTrace(); + } + catch (JMSException aq_ex) + { + System.out.println("Exception: " + aq_ex); + aq_ex.printStackTrace(); + + if(aq_ex.getLinkedException() != null) + { + aq_ex.getLinkedException().printStackTrace(); + } + } + catch (Exception ex) + { + System.out.println("Exception: " + ex); + ex.printStackTrace(); + } + } + + + public static void init(String ora_sid, String host, int port) + { + java.sql.Connection conn = null; + String url = null; + String jmsCall = null; + CallableStatement stmt = null; + try + { + // + // setup connection (either thin or oci8) + // + url = new String ("jdbc:oracle:oci8:"); + url = url.concat("@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(PORT=" +port); + url = url.concat(")(HOST=" +host+ "))(CONNECT_DATA=(SID=" + + ora_sid+ ")))"); + DriverManager.registerDriver(new oracle.jdbc.OracleDriver()); + conn = DriverManager.getConnection(url, "jmsuser", "JMSUSER"); + + // + // create queue table xmlq_t and enable it for jms types + // + jmsCall ="{call dbms_aqadm.create_queue_table( queue_table => 'xmlq_t',"+ + " multiple_consumers => false, "+ + "queue_payload_type => 'sys.ANYDATA',compatible => '8.1.3')}"; + stmt = conn.prepareCall(jmsCall); + stmt.execute(); + + // enable jms types + jmsCall = "{call dbms_aqadm.enable_jms_types('xmlq_t')}"; + stmt = conn.prepareCall(jmsCall); + stmt.execute(); + + // + // create queue xmlq + // + jmsCall = "{call dbms_aqadm.create_queue(queue_name => 'xmlq',"+ + " queue_table => 'xmlq_t')}"; + stmt = conn.prepareCall(jmsCall); + stmt.execute(); + + // + // start queue xmlq + // + jmsCall = "{call dbms_aqadm.start_queue(queue_name => 'xmlq')}"; + stmt = conn.prepareCall(jmsCall); + stmt.execute(); + + conn.close(); + } + catch (SQLException s) + { + System.out.println("Exception: "+s); + s.printStackTrace(); + } + } + + + public static void tearDown(String ora_sid, String host, int port) + { + java.sql.Connection conn = null; + String url = null; + String jmsCall = null; + CallableStatement stmt = null; + try + { + // + // Drop queue table 'xmlq_t' + // + url = new String ("jdbc:oracle:oci8:"); + url = url.concat("@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(PORT=" +port); + url = url.concat(")(HOST=" +host+ "))(CONNECT_DATA=(SID=" + + ora_sid+ ")))"); + DriverManager.registerDriver(new oracle.jdbc.OracleDriver()); + conn = DriverManager.getConnection(url, "jmsuser", "JMSUSER"); + + jmsCall = "{call dbms_aqadm.drop_queue_table( queue_table => 'xmlq_t',"+ + " force => TRUE)}"; + stmt = conn.prepareCall(jmsCall); + stmt.execute(); + + conn.close(); + } + catch (SQLException s) + { + s.printStackTrace(); + } + } +} diff --git a/aqjmsdemo08.java b/aqjmsdemo08.java new file mode 100644 index 0000000..4b7506d --- /dev/null +++ b/aqjmsdemo08.java @@ -0,0 +1,410 @@ +/* $Header: aqjmsdemo08.java 05-jun-2007.15:10:25 aatam Exp $ */ + +/* Copyright (c) 2002, 2007, Oracle. All rights reserved. */ + +/* + DESCRIPTION + OJMS JMS 1.1 domain unification demo + + PRIVATE CLASSES + None + + NOTES + This sample performs JMS topic and queue operations using the same JMS + connection and session and in the context of the same transaction using + JMS 1.1 domain unified apis. + + MODIFIED (MM/DD/YY) + aatam 06/05/07 - password need to be consistent + jleinawe 07/11/05 - + jleinawe 09/19/03 - no destination for Producer.send(...) + jleinawe 12/20/02 - update instructions + jleinawe 11/01/02 - + vmaganty 10/04/02 - checkin OJMS JMS 1.1 compliance changes + vmaganty 09/20/02 - Creation + */ + +/** + * @version $Header: aqjmsdemo08.java 05-jun-2007.15:10:25 aatam Exp $ + * @author vmaganty + * @since release specific (what release of product did this appear in) + */ + + +/*** This is a sample java file which uses Oracle JMS - Java Messaging + * Service API to Enqueue/Dequeue JMS Messages from both queues and + * topics in the same transaction using the same session and + * connection using the JMS 1.1 domain unfied APIs. + * + * Instructions for setting up and running this demo are found in + * aqjmsREADME.txt. + * + ***/ +/* import useful packages */ +import oracle.AQ.*; +import oracle.jms.*; +import javax.jms.*; +import java.lang.*; + +public class aqjmsdemo08 +{ + public static void main (String args []) + throws java.sql.SQLException, ClassNotFoundException, JMSException + { + Session sess = null; + ConnectionFactory cfact = null; + Connection conn = null; + try { + if (args.length < 4 ) + System.out.println("Usage:java filename [SID] [HOST] [PORT] [DRIVER]"); + else { + System.out.println("Create connection factory, connection and session"); + cfact = + AQjmsFactory.getConnectionFactory(args[1], args[0], + Integer.parseInt(args[2]), + args[3]); + + conn = cfact.createConnection( "jmsuser","JMSUSER"); + + /* Create a Topic Session */ + sess = conn.createSession(true, Session.CLIENT_ACKNOWLEDGE); + + System.out.println("Start the connection"); + conn.start() ; + + System.out.println("Setup a queue and a topic"); + setupQueue(sess) ; + setupTopic(sess) ; + + System.out.println("Perform queue and topic operations on the same connection and session in the same transaction"); + System.out.println("Begin transaction"); + enqueueMessages(sess); + dequeueMessages(sess); + performTopicOperations(sess); + System.out.println("Committing transaction"); + sess.commit(); + System.out.println("Cleaning up"); + sess.unsubscribe("atlanta"); + sess.close() ; + conn.close() ; + System.out.println("End of Demo") ; + } + } + catch (Exception ex) { + System.out.println("Exception-1: " + ex); + ex.printStackTrace(); + } + } + + public static void setupTopic(Session sess) throws Exception + { + AQQueueTableProperty qtprop ; + AQQueueTable qtable; + AQjmsDestinationProperty dprop; + Topic topic; + + try { + /* Create Queue Tables */ + System.out.println("Creating Queue Table...") ; + + /* Drop the queue if already exists */ + try { + qtable=((AQjmsSession)sess).getQueueTable("jmsuser", "jmstxtqtable" ); + qtable.drop(true); + } catch (Exception e) {} ; + + qtprop = new AQQueueTableProperty ("SYS.AQ$_JMS_TEXT_MESSAGE") ; + qtprop.setMultiConsumer(true) ; + qtprop.setCompatible("8.1") ; + qtprop.setPayloadType("SYS.AQ$_JMS_TEXT_MESSAGE") ; + qtable = ((AQjmsSession)sess).createQueueTable("JMSUSER", + "jmstxtqtable", qtprop) ; + + System.out.println ("Creating Topic ..."); + dprop = new AQjmsDestinationProperty() ; + topic=((AQjmsSession)sess).createTopic( qtable,"jmstopic",dprop) ; + + /* Start the topic */ + ((AQjmsDestination)topic).start(sess, true, true); + System.out.println("Successfully setup Topic"); + } catch (Exception ex) { + System.out.println("Error in setupTopic: " + ex); + throw ex; + } + } + + public static void performTopicOperations(Session sess) + { + Topic topic = null; + MessageConsumer mcon; + TopicSubscriber tsub; + MessageProducer mprod; + TextMessage txtmsg, dtxtmsg; + + try { + System.out.println ("Get the Topic..."); + topic = ((AQjmsSession)sess).getTopic("JMSUSER","jmstopic") ; + + System.out.println("Creating a nondurable MessageConsumer with selector...") ; + + mcon = + sess.createConsumer(topic, + "(year = 1998 OR color NOT IN ('GREEN','RED','WHITE')) " + + " AND make IN ('ACURA ', 'BMW', 'MERCEDES')", false); + + System.out.println("Creating a durable TopicSubscriber with selector...") ; + + tsub = sess.createDurableSubscriber(topic, "atlanta", + "price < 20000", false ); + + + System.out.println("Produce and send text messages to topic...") ; + + mprod = sess.createProducer(topic); + + txtmsg = sess.createTextMessage() ; + txtmsg.setText("Cars Distribution") ; + txtmsg.setObjectProperty("carno", new Integer(12345)) ; + txtmsg.setStringProperty("color", "BLUE") ; + txtmsg.setIntProperty("year", 1999) ; + txtmsg.setStringProperty("make", "BMW") ; + txtmsg.setDoubleProperty("price", 25995) ; + txtmsg.setJMSCorrelationID("dallas") ; + + mprod.send(txtmsg) ; + + txtmsg.clearProperties() ; + txtmsg.setObjectProperty("carno", new Integer(55)) ; + txtmsg.setStringProperty("color", "CYAN") ; + txtmsg.setIntProperty("year", 2000) ; + txtmsg.setStringProperty("make", "MERCEDES") ; + txtmsg.setDoubleProperty("price", 19000) ; + txtmsg.setJMSCorrelationID("atlanta") ; + + mprod.send(txtmsg) ; + + txtmsg.clearProperties() ; + txtmsg.setObjectProperty("carno", new Integer(99099)) ; + txtmsg.setStringProperty("color", "RED") ; + txtmsg.setIntProperty("year", 1998) ; + txtmsg.setStringProperty("make", "ACURA") ; + txtmsg.setDoubleProperty("price", 19995) ; + txtmsg.setJMSCorrelationID("atlanta") ; + + mprod.send(txtmsg) ; + + // sess.commit() ; + + System.out.println ("Consume messages from topic using non durable consumer") ; + boolean done = false ; + while (!done) { + dtxtmsg = (TextMessage) (mcon.receiveNoWait() ) ; + + if (dtxtmsg == null) { + done=true; + } else + { + System.out.print(" Color: " + dtxtmsg.getStringProperty("color")); + System.out.print(" Make: " + dtxtmsg.getStringProperty("make")); + System.out.print(" Year: " + dtxtmsg.getStringProperty("year")); + System.out.print(" Price: " + dtxtmsg.getStringProperty("price")); + System.out.println(" Carno: " + dtxtmsg.getStringProperty("carno")); + } + } + + System.out.println ("Consume messages from topic using durable subscriber") ; + done=false ; + while (!done) { + dtxtmsg = (TextMessage) (tsub.receiveNoWait() ) ; + + if (dtxtmsg == null) { + done=true; + } else + { + System.out.print(" Color: " + dtxtmsg.getStringProperty("color")); + System.out.print(" Make: " + dtxtmsg.getStringProperty("make")); + System.out.print(" Year: " + dtxtmsg.getStringProperty("year")); + System.out.print(" Price: " + dtxtmsg.getStringProperty("price")); + System.out.println(" Carno: " + dtxtmsg.getStringProperty("carno")); + } + } + + + // sess.commit() ; + + ((AQjmsDestination)topic).stop(sess, true, true, false); + + } catch (Exception e) { + System.out.println("Error in performJmsOperations: " + e) ; + } + } + + + public static void setupQueue(Session sess) throws Exception + { + AQQueueTableProperty qtprop ; + AQQueueTable qtable; + AQjmsDestinationProperty dprop; + javax.jms.Queue q1; + + try { + + /* Create Queue Tables */ + System.out.println("Creating Queue Table...") ; + + qtprop = new AQQueueTableProperty ("SYS.AQ$_JMS_MAP_MESSAGE") ; + qtprop.setCompatible("8.1") ; + qtprop.setPayloadType("SYS.AQ$_JMS_MAP_MESSAGE") ; + + /* Drop if the queue table already exists */ + try { + qtable=((AQjmsSession)sess).getQueueTable("JMSUSER", "JMSMAPQTABLE"); + qtable.drop(true); + } catch (Exception e) {} + + qtable = ((AQjmsSession)sess).createQueueTable("JMSUSER", + "jmsmapqtable", qtprop) ; + + System.out.println ("Creating Queue..."); + dprop = new AQjmsDestinationProperty() ; + q1=((AQjmsSession)sess).createQueue(qtable,"JMS_MAPQ",dprop) ; + + /* Start the Queue */ + ((AQjmsDestination)q1).start(sess, true, true); + + System.out.println("Successfully setup Queue"); + } catch (Exception ex) { + System.out.println("Error in setupQueue: " + ex); + throw ex; + } + } + + public static void enqueueMessages(Session sess) throws Exception + { + javax.jms.Queue q1 ; + MapMessage[] Messages; + byte[] barray ; + MessageProducer mprod; + + StringBuffer txtbuf ; + TextMessage txtmsg, dtxtmsg; + try + { + /* Get Queue */ + q1 = ((AQjmsSession)sess).getQueue("JMSUSER", "JMS_MAPQ") ; + + System.out.println("Produce and send text messages to queue...") ; + + barray = new byte[25] ; + for ( int i=0 ; i< 25 ; i++) barray[i] = 67 ; + + Messages = new MapMessage[5] ; + + Messages[0] = sess.createMapMessage() ; + Messages[0].setIntProperty ("carno", 3355) ; + Messages[0].setStringProperty ("color", "BLUE") ; + Messages[0].setStringProperty ("make", "BMW") ; + Messages[0].setDoubleProperty ("price", 20000) ; + Messages[0].setIntProperty ("year", 1999) ; + + Messages[1] = sess.createMapMessage() ; + Messages[1].setIntProperty ("carno", 4444) ; + Messages[1].setStringProperty ("color", "BLACK") ; + Messages[1].setStringProperty ("make", "ACURA") ; + Messages[1].setDoubleProperty ("price", 22995) ; + Messages[1].setIntProperty ("year", 1998) ; + + Messages[2] = sess.createMapMessage() ; + Messages[2].setIntProperty ("carno", 1212) ; + Messages[2].setStringProperty ("color", "BLUE") ; + Messages[2].setStringProperty ("make", "MERCEDES") ; + Messages[2].setDoubleProperty ("price", 30995) ; + Messages[2].setIntProperty ("year", 2001) ; + + Messages[3] = sess.createMapMessage() ; + Messages[3].setIntProperty ("carno", 5345) ; + Messages[3].setStringProperty ("color", "GREEN") ; + Messages[3].setStringProperty ("make", "LEXUS") ; + Messages[3].setDoubleProperty ("price", 21895) ; + Messages[3].setIntProperty ("year", 1995) ; + + Messages[4] = sess.createMapMessage() ; + Messages[4].setIntProperty ("carno", 8909) ; + Messages[4].setStringProperty ("color", "BLUE") ; + Messages[4].setStringProperty ("make", "BMW") ; + Messages[4].setDoubleProperty ("price", 40995) ; + Messages[4].setIntProperty ("year", 2002) ; + + /* Create Queue Sender */ + mprod = sess.createProducer(q1) ; + + for ( int i = 0 ; i < 5 ; i++ ) + { + Messages[i].setBytes("Picture" , barray) ; + Messages[i].setJMSCorrelationID(Messages[i].getStringProperty("color")); + System.out.println("Sending "+Messages[i].getStringProperty ("color") + + " " + Messages[i].getStringProperty("make") + + " " + Messages[i].getIntProperty("year") + + " " + Messages[i].getDoubleProperty("price")) ; + + mprod.send(Messages[i], DeliveryMode.PERSISTENT, + 1+ (i%10) , AQjmsConstants.EXPIRATION_NEVER ) ; + try { + Thread.sleep(5000) ; + } catch (InterruptedException e) {} ; + // sess.commit() ; + } + System.out.println("Successfully Sent Messages."); + + } catch (JMSException e) { + System.out.println("Error in Sending Messages : " + e) ; + throw e; + } + } + + public static void dequeueMessages(Session sess) throws Exception + { + MapMessage mm; + int mesgno = 0; + javax.jms.Queue queue; + MessageConsumer mcon; + + try + { + System.out.println("Get the Destination") ; + queue = ((AQjmsSession)sess).getQueue("JMSUSER", "JMS_MAPQ") ; + + System.out.println("Create message consumer with selector...") ; + mcon = sess.createConsumer((Destination) queue, "JMSCorrelationID='BLUE'") ; + + System.out.println("Receive messages using the message consumer...") ; + boolean done = false ; + while (!done) { + mm = (MapMessage) (mcon.receiveNoWait() ) ; + + if (mm == null) { + done=true; + } else { + mesgno++; + System.out.println("Retrieved message " + + mesgno + " with correlation: " + mm.getJMSCorrelationID()); + System.out.println (" "+ mm.getStringProperty ("color") + + " " + mm.getStringProperty("make") + + " " + mm.getIntProperty("year") + + " " + mm.getDoubleProperty("price")) ; + } + } + + /* + try { + sess.commit() ; + } catch (Exception e) { + System.out.println("Exception on Session Commit " + e) ; + } + */ + } catch (JMSException e) { + System.out.println("Exception onMessage:" + e) ; + } + } +} + diff --git a/aqjmsdemo09.java b/aqjmsdemo09.java new file mode 100644 index 0000000..8111644 --- /dev/null +++ b/aqjmsdemo09.java @@ -0,0 +1,429 @@ +/* $Header: aqjmsdemo09.java 05-jun-2007.15:10:27 aatam Exp $ */ + +/* Copyright (c) 2002, 2007, Oracle. All rights reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + aatam 06/05/07 - password need to be consistent + jleinawe 07/11/05 - + jleinawe 12/20/02 - update instructions + jleinawe 11/19/02 - queue name conflict + vmaganty 11/05/02 - OJMS bulk enqueue/dequeue changes + vmaganty 10/30/02 - Creation + */ + +/** + * @version $Header: aqjmsdemo09.java 05-jun-2007.15:10:27 aatam Exp $ + * @author vmaganty + * @since release specific (what release of product did this appear in) + */ + + +/*** This is a sample java file which uses Oracle JMS - Oracle + * specific bulk array enqueue dequeue messaging APIs to + * Enqueue/Dequeue JMS Messages from both queues and topics in the + * same transaction using the same session and connection using JMS + * 1.1 domain unfied APIs. + * + * Instructions for setting up and running this demo are found in + * aqjmsREADME.txt. + * + ***/ + +/* import useful packages */ +import oracle.AQ.*; +import javax.jms.*; +import oracle.jms.*; +import java.lang.*; + +public class aqjmsdemo09 +{ + public static void main (String args []) + throws java.sql.SQLException, ClassNotFoundException, JMSException + { + Session sess = null; + ConnectionFactory cfact = null; + Connection conn = null; + try { + if (args.length < 4 ) + System.out.println("Usage:java filename [SID] [HOST] [PORT] [DRIVER]"); + else { + System.out.println("Create connection factory, connection and session"); + cfact = + AQjmsFactory.getConnectionFactory(args[1], args[0], + Integer.parseInt(args[2]), + args[3]); + + conn = cfact.createConnection( "jmsuser","JMSUSER"); + + /* Create a Topic Session */ + sess = conn.createSession(true, Session.CLIENT_ACKNOWLEDGE); + + System.out.println("Start the connection"); + conn.start() ; + + System.out.println("Setup a queue and a topic"); + setupQueue(sess) ; + setupTopic(sess) ; + System.out.println("Perform bulk queue and topic operations on the"); + System.out.println("same connection and session in the same transaction"); + System.out.println("Begin transaction"); + enqueueMessages(sess); + dequeueMessages(sess); + + performTopicOperations(sess); + System.out.println("Committing transaction"); + sess.commit(); + System.out.println("Cleaning up"); + sess.unsubscribe("atlanta"); + sess.close() ; + conn.close() ; + System.out.println("End of Demo") ; + } + } + catch (Exception ex) { + System.out.println("Exception-1: " + ex); + ex.printStackTrace(); + } + } + + public static void setupTopic(Session sess) throws Exception + { + AQQueueTableProperty qtprop ; + AQQueueTable qtable; + AQjmsDestinationProperty dprop; + Topic topic; + + try { + /* Create Queue Tables */ + System.out.println("Creating Queue Table...") ; + + /* Drop the queue if already exists */ + try { + qtable=((AQjmsSession)sess).getQueueTable("jmsuser", "jmst9table" ); + qtable.drop(true); + } catch (Exception e) {} ; + + qtprop = new AQQueueTableProperty ("SYS.AQ$_JMS_MESSAGE") ; + qtprop.setMultiConsumer(true) ; + qtprop.setCompatible("8.1") ; + qtprop.setPayloadType("SYS.AQ$_JMS_MESSAGE") ; + qtable = ((AQjmsSession)sess).createQueueTable("JMSUSER", + "jmst9table", qtprop) ; + + System.out.println ("Creating Topic ..."); + dprop = new AQjmsDestinationProperty() ; + topic=((AQjmsSession)sess).createTopic( qtable,"JMSDemoTopic9",dprop) ; + + /* Start the topic */ + ((AQjmsDestination)topic).start(sess, true, true); + System.out.println("Successfully setup Topic"); + } catch (Exception ex) { + System.out.println("Error in setupTopic: " + ex); + throw ex; + } + } + + public static void performTopicOperations(Session sess) + { + Topic topic = null; + MessageConsumer mcon; + TopicSubscriber tsub; + MessageProducer mprod; + javax.jms.Message[] send_messages = null; + javax.jms.Message[] receive_messages = null; + + try { + System.out.println ("Get the Topic..."); + topic = ((AQjmsSession)sess).getTopic("JMSUSER","JMSDemoTopic9") ; + + System.out.println("Creating a nondurable MessageConsumer with selector...") ; + + mcon = + sess.createConsumer(topic, + "(year = 1998 OR color NOT IN ('GREEN','RED','WHITE')) " + + " AND make IN ('ACURA ', 'BMW', 'MERCEDES')", false); + + System.out.println("Creating a durable TopicSubscriber with selector...") ; + + tsub = sess.createDurableSubscriber(topic, "atlanta", + "price < 20000", false ); + + + System.out.println("Produce and send assorted messages to topic...") ; + + send_messages = new javax.jms.Message[4]; + + mprod = sess.createProducer(topic); + + + send_messages[0] = (javax.jms.Message) (sess.createMapMessage()); + send_messages[0].setObjectProperty("carno", new Integer(55)) ; + send_messages[0].setStringProperty("color", "CYAN") ; + send_messages[0].setIntProperty("year", 2000) ; + send_messages[0].setStringProperty("make", "MERCEDES") ; + send_messages[0].setDoubleProperty("price", 19000) ; + send_messages[0].setJMSCorrelationID("atlanta") ; + + send_messages[1] = (javax.jms.Message) (sess.createBytesMessage()) ; + ((BytesMessage) send_messages[1]).writeBytes("Cars Distribution".getBytes()) ; + send_messages[1].setObjectProperty("carno", new Integer(12345)) ; + send_messages[1].setStringProperty("color", "BLUE") ; + send_messages[1].setIntProperty("year", 1999) ; + send_messages[1].setStringProperty("make", "BMW") ; + send_messages[1].setDoubleProperty("price", 15995) ; + send_messages[1].setJMSCorrelationID("dallas") ; + + + send_messages[2] = (javax.jms.Message) (sess.createStreamMessage()); + send_messages[2].setObjectProperty("carno", new Integer(99099)) ; + send_messages[2].setStringProperty("color", "RED") ; + send_messages[2].setIntProperty("year", 1998) ; + send_messages[2].setStringProperty("make", "ACURA") ; + send_messages[2].setDoubleProperty("price", 19995) ; + send_messages[2].setJMSCorrelationID("seattle") ; + + send_messages[3] = (javax.jms.Message) (sess.createTextMessage()) ; + ((TextMessage) send_messages[3]).setText("Cars WholeSale") ; + send_messages[3].setObjectProperty("carno", new Integer(5678)) ; + send_messages[3].setStringProperty("color", "RED") ; + send_messages[3].setIntProperty("year", 2003) ; + send_messages[3].setStringProperty("make", "Subaru") ; + send_messages[3].setDoubleProperty("price", 18488) ; + send_messages[3].setJMSCorrelationID("portland") ; + + + ((AQjmsProducer) mprod).bulkSend((Destination) topic, send_messages) ; + + // sess.commit() ; + + System.out.println ("Consume messages in bulk from topic using non durable consumer") ; + boolean done = false ; + while (!done) { + receive_messages = ((AQjmsConsumer) mcon).bulkReceiveNoWait(2); + + if (receive_messages == null) { + done=true; + } else { + for ( int i=0; i + + NOTES + + + MODIFIED (MM/DD/YY) + aatam 06/05/07 - password need to be consistent + jleinawe 07/11/05 - + jleinawe 03/13/03 - jleinawe_newaqdemos + jleinawe 03/11/03 - Creation + */ + +/** + * @version $Header: aqjmsdemo10.java 07-jun-2007.14:35:37 aatam Exp $ + * @author jleinawe + * @since release specific (what release of product did this appear in) + */ + +/*** This is a sample java file which shows messaging with SYS.ANYDATA queues + * It will demonstrate a send/receive using each of the five JMS Message + * Types (Text, Map, Object, Bytes, Stream) and with an AdtMessage. + * + * Instructions for setting up and running this demo are found in + * aqjmsREADME.txt + * + * Note: SYS.ANYDATA Queue Types are not supported for thin jdbc driver + ***/ + +import oracle.AQ.*; +import oracle.jms.*; +import javax.jms.*; + +public class aqjmsdemo10 +{ + public static void main (String args[]) + throws Exception + { + javax.jms.QueueConnectionFactory qcf = null; + javax.jms.QueueConnection qconn = null; + javax.jms.QueueSession qsession = null; + javax.jms.Queue queue = null; + + if (args.length < 3) + System.out.println("Usage: java filename [SID] [HOST] [PORT]"); + else + { + // + // setup + // + qcf = AQjmsFactory.getQueueConnectionFactory( + args[1], args[0], Integer.parseInt(args[2]), "oci8"); + qconn = qcf.createQueueConnection( "jmsuser","JMSUSER"); + qsession = qconn.createQueueSession(true, Session.CLIENT_ACKNOWLEDGE); + qconn.start() ; + queue = setup(qsession); + + // + // run the demo + // + enqueueMessages(qsession, queue); + dequeueMessages(qsession, queue); + + // + // cleanup and exit + // + cleanup(qsession); + qsession.close(); + qconn.close(); + } + System.out.println("End of Demo"); + } + + +/** + * Enqueue each type of JMS Message on the ANYDATA queue + */ + public static void enqueueMessages(QueueSession session, javax.jms.Queue queue) + throws javax.jms.JMSException, java.sql.SQLException + { + StringBuffer msgBody = null;; + javax.jms.QueueSender sender = null; + javax.jms.Message message = null; + oracle.jms.AdtMessage adt_message = null; + Cars car = null; + int counter = 0; + + // + // create the QueueSender + // + sender= session.createSender(queue); + + // + // send a message for each message type + // + + // TextMessage + msgBody = new StringBuffer("This is a Text Message"); + message = session.createTextMessage(); + ((TextMessage)message).setText(msgBody.toString()); + sender.send(message); + System.out.println("Sent TextMessage"); + counter++; + + // MapMessage + msgBody = new StringBuffer("This is a Map Message"); + message = session.createMapMessage(); + ((MapMessage)message).setString("stringbuf", msgBody.toString()); + sender.send(message); + System.out.println("Sent MapMessage"); + counter++; + + // ObjectMessage + msgBody = new StringBuffer("This is a Object Message"); + message = session.createObjectMessage(); + ((ObjectMessage)message).setObject(msgBody); + sender.send(message); + System.out.println("Sent ObjectMessage"); + counter++; + + // BytesMessage + msgBody = new StringBuffer("This is a Bytes Message"); + message = session.createBytesMessage(); + ((BytesMessage)message).writeBytes(msgBody.toString().getBytes()); + sender.send(message); + System.out.println("Sent BytesMessage"); + counter++; + + // StreamMessage + msgBody = new StringBuffer("This is a Stream Message"); + message = session.createStreamMessage(); + ((StreamMessage)message).writeBytes(msgBody.toString().getBytes()); + sender.send(message); + System.out.println("Sent StreamMessage"); + counter++; + + // ADT Message + car = new Cars(); + car.setCarno(new java.math.BigDecimal(11051963)); + car.setMake("CHEVROLET"); + car.setColor("BLUE"); + car.setPrice(new java.math.BigDecimal(21099)); + adt_message = ((AQjmsSession)session).createAdtMessage(); + adt_message.setAdtPayload(car); + sender.send(adt_message); + System.out.println("Sent AdtMessage"); + counter++; + + // + // commit the sends + // + session.commit(); + System.out.println("Sent a total of "+counter+" messages"); + + sender.close(); + } + + +/** + * Dequeue each message enqueued on the ANYDATA Queue + */ + public static void dequeueMessages(QueueSession session, javax.jms.Queue queue) + throws javax.jms.JMSException, java.lang.ClassNotFoundException, + java.sql.SQLException + { + javax.jms.QueueReceiver receiver = null; + javax.jms.Message message = null; + int counter = 0; + java.util.Dictionary map = null; + + // + // setup mapping (needed because we have an AdtMessage) + // + map = (java.util.Dictionary)((AQjmsSession)session).getTypeMap(); + map.put("JMSUSER.CARS", Class.forName("Cars")); + + // + // create receiver + // + receiver = session.createReceiver(queue); + + // + // receive all messages on the queue + // + boolean nullMsgReceive = false; + while (!nullMsgReceive) + { + message = (javax.jms.Message) receiver.receive(20000); + + if (message == null) + { + System.out.println("Received a total of "+counter+" messages"); + nullMsgReceive = true; + } + else + { + counter++; + if (message instanceof TextMessage) + { + String body = ((TextMessage)message).getText(); + System.out.println("Received TextMessage: "+body); + } + else if (message instanceof MapMessage) + { + String body = ((MapMessage)message).getString("stringbuf"); + System.out.println("Received MapMessage: "+body); + } + else if (message instanceof ObjectMessage) + { + StringBuffer strbuf + = (StringBuffer)((ObjectMessage)message).getObject(); + System.out.println("Received ObjectMessage: "+strbuf.toString()); + } + else if (message instanceof StreamMessage) + { + byte[] bdata = new byte[128]; + ((StreamMessage) message).readBytes(bdata); + String body = new String(bdata); + System.out.println("Received StreamMessage: "+body); + } + else if (message instanceof BytesMessage) + { + byte[] bdata = new byte[128]; + ((BytesMessage) message).readBytes(bdata); + String body = new String(bdata); + System.out.println("Received BytesMessage: "+body); + } + else if (message instanceof AdtMessage) + { + Cars car = (Cars) ((AdtMessage) message).getAdtPayload(); + System.out.print("Received AdtMessage for Cars: "); + System.out.print(car.getCarno()+", "); + System.out.print(car.getMake()+", "); + System.out.print(car.getColor()+", "); + System.out.println(car.getPrice()); + } + else + { + System.out.println("Unknown Message Type Received!"); + } + } + session.commit(); + } + receiver.close(); + } + +/** + * Creates and returns ANYDATA queue called jmsuser.jmsanydata10 + */ + public static javax.jms.Queue setup(QueueSession session) + throws javax.jms.JMSException, oracle.AQ.AQException + { + oracle.AQ.AQQueueTableProperty qtprop = null; + oracle.AQ.AQQueueTable qtable = null; + oracle.jms.AQjmsDestinationProperty dprop = null; + javax.jms.Queue queue = null; + + // + // drop queue table if it already exists + // + try + { + qtable = + ((AQjmsSession)session).getQueueTable("jmsuser", "jmsqtable_any"); + if (qtable != null) + qtable.drop(true); + } + catch (Exception e){} + + // + // create ANYDATA queue table + // + qtprop = new AQQueueTableProperty ("SYS.ANYDATA"); + qtprop.setMultiConsumer(false); + qtprop.setCompatible("9.2.0.0.0"); + qtable = ((AQjmsSession)session).createQueueTable("jmsuser", + "jmsqtable_any", qtprop); + + // + // create JMS Queue for ANYDATA queue table + // + dprop = new AQjmsDestinationProperty(); + queue = ((AQjmsSession)session).createQueue (qtable, "jmsanydata10", dprop); + System.out.println("Created queue jmsanydata10"); + + // + // enable the ANYDATA JMS Queue for JMS Messaging + // + try + { + java.sql.CallableStatement stmt; + java.sql.Connection conn = ((AQjmsSession)session).getDBConnection(); + String sqlCall = + "{call dbms_aqadm.enable_jms_types('jmsuser.jmsqtable_any')}"; + stmt = conn.prepareCall(sqlCall); + stmt.execute(); + System.out.println("Queue is JMS enabled"); + } + catch (java.sql.SQLException s) + { + s.printStackTrace(); + } + + // + // Start the queue + // + ((AQjmsDestination)queue).start(session, true, true); + + return queue; + } + +/** + * drops queue table "jmsuser.jmsqtable_any" + */ + private static void cleanup(QueueSession session) + { + // + // drop queue table used for test + // + try + { + oracle.AQ.AQQueueTable qtable = + ((AQjmsSession)session).getQueueTable("jmsuser", "jmsqtable_any"); + if (qtable != null) + qtable.drop(true); + } + catch (Exception e) + { + System.out.println("Error dropping jmsanydata10"); + e.printStackTrace(); + } + System.out.println("Queue jmsanydata10 dropped successfully"); + } +} + diff --git a/aqjmsdmo.sql b/aqjmsdmo.sql new file mode 100644 index 0000000..bbd892c --- /dev/null +++ b/aqjmsdmo.sql @@ -0,0 +1,61 @@ +Rem +Rem $Header: aqjmsdmo.sql 05-jun-2007.15:02:55 aatam Exp $ +Rem +Rem aqjmsdmo.sql +Rem +Rem Copyright (c) 2000, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem aqjmsdmo.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem aatam 06/05/07 - password need to be consistent +Rem rbhyrava 11/16/04 - user creation +Rem rbhyrava 07/10/00 - AQ JMS demo -setup +Rem rbhyrava 07/10/00 - Created +Rem +REM ===================================================== +REM SETUP for AQ JMS Demos:create user and payload types +REM ===================================================== +SET echo on; +CONNECT system/manager; +DROP USER jmsuser CASCADE ; +CREATE USER jmsuser IDENTIFIED BY JMSUSER; +GRANT CONNECT, RESOURCE, AQ_ADMINISTRATOR_ROLE TO jmsuser; + +CONNECT jmsuser/JMSUSER; + +CREATE TYPE message AS OBJECT ( + id NUMBER, + city VARCHAR2(30), + priority NUMBER +); +/ + +CREATE OR REPLACE TYPE cars AS OBJECT ( + carno NUMBER, + make VARCHAR2(20) , + year NUMBER, + price NUMBER(10,2) , + color VARCHAR2(10) +); +/ +CREATE OR REPLACE TYPE emp AS OBJECT ( + id NUMBER , + name VARCHAR2(20), + carown cars, + rank NUMBER, + zip VARCHAR2(5) +); +/ +EXIT; + +REM ============================================== +REM SETUP complete +REM ============================================== diff --git a/aqjmsdrp.sql b/aqjmsdrp.sql new file mode 100644 index 0000000..e373e2c --- /dev/null +++ b/aqjmsdrp.sql @@ -0,0 +1,22 @@ +Rem +Rem $Header: template.sql 06-feb-96.13:23:14 kosinski Exp $ +Rem +Rem aqjmsdrp.sql +Rem +Rem Copyright (c) Oracle Corporation 2000. All Rights Reserved. +Rem +Rem NAME +Rem aqjmsdrp.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbhyrava 07/10/00 - Created +Rem +CONNECT system/manager; +DROP USER jmsuser cascade ; +EXIT; diff --git a/aqjmskprb01.java b/aqjmskprb01.java new file mode 100644 index 0000000..205a3c0 --- /dev/null +++ b/aqjmskprb01.java @@ -0,0 +1,173 @@ +/* $Header: aqjmskprb01.java 11-jul-2005.13:27:45 jleinawe Exp $ */ + +/* Copyright (c) 2002, 2005, Oracle. All rights reserved. */ + +/* + DESCRIPTION + AQ/OJMS KPRB driver demo + + PRIVATE CLASSES + + + NOTES + see below + + MODIFIED (MM/DD/YY) + jleinawe 07/11/05 - + rbhyrava 10/07/02 - import oracle.jdbc.* + jleinawe 09/04/02 - jleinawe_new_aq_demos + jleinawe 08/30/02 - Creation + */ + +/** + * @version $Header: aqjmskprb01.java 11-jul-2005.13:27:45 jleinawe Exp $ + * @author jleinawe + * @since release specific (what release of product did this appear in) + */ + +/**** + * This is a sample java file which uses Oracle JMS - Java Message service + * API. This file helps demonstrate how to send and receive a message + * from within an Oracle Database. + * + * This demo runs within the database and does the following + * - gets the database connection + * - creates a QueueReceiver + * - creates a QueueSender + * - sends and receives a text message + * + * Compilation + * =========== + * 1) The client machine should have JDK 1.1.x or JDK 1.2 or higher installed. + * 2) The following jar/zip files should be in the CLASSPATH + * For JDK1.2 or higher + * classes12.zip + * aqapi.jar + * jmscommon.jar + * nls_charset12.zip + * + * For JDK1.1.x + * classes111.zip + * aqapi11.jar + * jmscommon.jar + * nls_charset11.zip + * + * 3) Compile by executing "javac aqjmskprb01.java" + * + * This demo cannot be executed standalone. For execution, see the + * instructions for the kprb driver demo in the aqjmsREADME.txt file. + * + */ + +import oracle.jms.*; +import oracle.jdbc.*; +import javax.jms.*; +import java.sql.*; + +public class aqjmskprb01 +{ + + public static void main(String[] args) + throws Exception + { + runTest(args[0]); + } + + // send and receive one message + public static void runTest(String msgBody) + { + OracleDriver ora_drv = null; + java.sql.Connection db_conn = null; + + + QueueConnection s_conn = null; + QueueSession s_session = null; + QueueSender sender = null; + javax.jms.Queue s_queue = null; + TextMessage s_msg = null; + + QueueConnection r_conn = null; + QueueSession r_session = null; + QueueReceiver receiver = null; + javax.jms.Queue r_queue = null; + TextMessage r_msg = null; + + try + { + // + // get database connection + // + ora_drv = new OracleDriver(); + db_conn = ora_drv.defaultConnection(); + + // + // setup receiver + // + r_conn = AQjmsQueueConnectionFactory.createQueueConnection(db_conn); + r_conn.start(); + r_session = r_conn.createQueueSession(true, Session.CLIENT_ACKNOWLEDGE); + r_queue = ((AQjmsSession) r_session).getQueue("jmsuser1", "queue1"); + receiver = r_session.createReceiver(r_queue); + System.out.println("receiver created"); + + // + // setup sender + // + s_conn = AQjmsQueueConnectionFactory.createQueueConnection(db_conn); + s_conn.start(); + s_session = s_conn.createQueueSession(true, Session.CLIENT_ACKNOWLEDGE); + s_queue = ((AQjmsSession) s_session).getQueue("jmsuser1", "queue1"); + sender = r_session.createSender(s_queue); + System.out.println("sender created"); + + // + // create message + // + s_msg = s_session.createTextMessage(msgBody); + System.out.println("message created"); + + // + // send message + // + sender.send(s_msg); + s_session.commit(); + System.out.println("message sent"); + + // + // receive message + // + r_msg = (TextMessage) receiver.receive(); + r_session.commit(); + System.out.println("message received"); + + // + // output message text + // + String body = r_msg.getText(); + System.out.println("message was '"+body+"'"); + + // + // cleanup + // + s_session.close(); + s_conn.close(); + r_session.close(); + r_conn.close(); + } + catch (java.sql.SQLException sql_ex) + { + System.out.println("Exception-2: " + sql_ex); + sql_ex.printStackTrace(); + } + catch (JMSException aq_ex) + { + System.out.println("Exception-2: " + aq_ex); + aq_ex.printStackTrace(); + + if(aq_ex.getLinkedException() != null) + { + aq_ex.getLinkedException().printStackTrace(); + } + } + } +} diff --git a/aqjmskprb01a.sql b/aqjmskprb01a.sql new file mode 100644 index 0000000..f41cf43 --- /dev/null +++ b/aqjmskprb01a.sql @@ -0,0 +1,53 @@ +Rem +Rem $Header: aqjmskprb01a.sql 05-jun-2007.15:02:52 aatam Exp $ +Rem +Rem aqjmskprb01a.sql +Rem +Rem Copyright (c) 2002, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem aqjmskprb01a.sql +Rem +Rem DESCRIPTION +Rem creates user and queue for AQ/OJMS kprb driver demo +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem aatam 06/05/07 - password need to be consistent +Rem jleinawe 09/04/02 - jleinawe_new_aq_demos +Rem jleinawe 08/30/02 - Created +Rem + +SET ECHO ON +CONNECT system/manager +SET SERVEROUTPUT on + +-- +-- create the user "jmsuser1" +-- +CREATE USER jmsuser1 IDENTIFIED BY JMSUSER1; + +GRANT CONNECT, RESOURCE, AQ_ADMINISTRATOR_ROLE, AQ_USER_ROLE TO jmsuser1; +GRANT EXECUTE ON DBMS_AQADM TO jmsuser1; +GRANT EXECUTE ON DBMS_AQ TO jmsuser1; + +execute dbms_java.grant_permission('JMSUSER1', 'java.net.SocketPermission', 'localhost:1024-', 'accept, listen, resolve'); + +execute dbms_java.grant_permission( 'JMSUSER1', 'SYS:java.lang.RuntimePermission', ' getClassLoader', '' ) + +execute dbms_java.grant_permission( 'JMSUSER1', 'SYS:java.lang.RuntimePermission' , 'setContextClassLoader', '' ) + +CONNECT jmsuser1/JMSUSER1; + +-- +-- create and start the JMS Queue "queue1" +-- +execute dbms_aqadm.create_queue_table(queue_table => 'queue1', queue_payload_type => 'SYS.AQ$_JMS_TEXT_MESSAGE', comment => 'a test queue', multiple_consumers => false, compatible => '8.1.0'); + +execute dbms_aqadm.create_queue( queue_name => 'queue1', queue_table => 'queue1' ); + +execute dbms_aqadm.start_queue(queue_name => 'queue1'); + +quit; diff --git a/aqjmskprb01b.sql b/aqjmskprb01b.sql new file mode 100644 index 0000000..2332d2f --- /dev/null +++ b/aqjmskprb01b.sql @@ -0,0 +1,43 @@ +Rem +Rem $Header: aqjmskprb01b.sql 05-jun-2007.15:02:53 aatam Exp $ +Rem +Rem aqjmskprb01b.sql +Rem +Rem Copyright (c) 2002, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem aqjmskprb01b.sql - +Rem +Rem DESCRIPTION +Rem defines java stored procedure for AQ/OJMS kprb driver demo +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem aatam 06/05/07 - password need to be consistent +Rem jleinawe 09/04/02 - jleinawe_new_aq_demos +Rem jleinawe 08/30/02 - Created +Rem + +set echo on +set serveroutput on +connect jmsuser1/JMSUSER1 + +-- +-- define the kprb driver demos in the database +-- + +create or replace package jmsdemo authid current_user as + procedure start_me(t1 VARCHAR2); +end jmsdemo; +/ +create or replace package body jmsdemo as + procedure start_me(t1 VARCHAR2) is language java + name 'aqjmskprb01.main (java.lang.String[])'; +end jmsdemo; +/ +show errors + + +quit; diff --git a/aqjmskprb01c.sql b/aqjmskprb01c.sql new file mode 100644 index 0000000..2c4be87 --- /dev/null +++ b/aqjmskprb01c.sql @@ -0,0 +1,37 @@ +Rem +Rem $Header: aqjmskprb01c.sql 05-jun-2007.15:02:53 aatam Exp $ +Rem +Rem aqjmskprb01c.sql +Rem +Rem Copyright (c) 2002, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem aqjmskprb01c.sql - +Rem +Rem DESCRIPTION +Rem Calls java stored procedure for AQ/OJMS kprb driver demo +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem aatam 06/05/07 - password need to be consistent +Rem jleinawe 09/04/02 - jleinawe_new_aq_demos +Rem jleinawe 08/30/02 - Created +Rem + +set echo on +connect jmsuser1/JMSUSER1 + +-- +-- run the kprb driver demo +-- +set serveroutput on + +call dbms_java.set_output(30000); + +call jmsdemo.start_me('hello'); +call jmsdemo.start_me('hello again'); + +quit; + diff --git a/aqjmskprb01d.sql b/aqjmskprb01d.sql new file mode 100644 index 0000000..cecd1f8 --- /dev/null +++ b/aqjmskprb01d.sql @@ -0,0 +1,34 @@ +Rem +Rem $Header: aqjmskprb01d.sql 05-jun-2007.15:02:54 aatam Exp $ +Rem +Rem aqjmskprb01d.sql +Rem +Rem Copyright (c) 2002, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem aqjmskprb01d.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem aatam 06/05/07 - password need to be consistent +Rem jleinawe 09/04/02 - jleinawe_new_aq_demos +Rem jleinawe 08/30/02 - Created +Rem + + +connect jmsuser1/JMSUSER1; + +execute dbms_aqadm.drop_Queue_table(queue_table => 'queue1', force => true); + +drop package jmsdemo; + +connect system/manager; +drop user jmsuser1 cascade; + +quit; + diff --git a/aqorademo01.java b/aqorademo01.java new file mode 100644 index 0000000..83a9b1d --- /dev/null +++ b/aqorademo01.java @@ -0,0 +1,306 @@ +/* $Header: aqorademo01.java 12-aug-2003.12:51:11 rbhyrava Exp $ */ + +/* Copyright (c) 2000, 2003, Oracle Corporation. All rights reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + rbhyrava 08/12/03 - stop/drop queue/queuetables + rbhyrava 10/07/02 - import oracle.jdbc.* + rbhyrava 03/20/00 - use driver arg + rbhyrava 03/16/00 - AQ API demos + rbhyrava 03/15/00 - AQ API demo - Enqueue,Dequeue RAW Message + rbhyrava 03/15/00 - Creation + */ + +/** + * @version $Header: aqorademo01.java 12-aug-2003.12:51:11 rbhyrava Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ +/*** + * This is a sample java file which uses Oracle AQ API to enqueue and + * dequeue RAW messages + + * -- Create a Queue + * -- Enqueue RAW Message + * Dequeue RAW message + * + * The following instructions describe how to compile and execute + * this sample on the client machine. + * + * System requirements: + * ==================== + * 1) Oracle 8.1.6 database or higher + * 2) The client machine should have JDK 1.1.x or JDK1.2 or higher installed + * 3) The following jar/zip files should be in the CLASSPATH on the client + * machine. + * For JDK1.2.x + * classes12.zip + * aqapi.jar + * For JDK1.1.x + * classes111.zip + * aqapi11.jar + * Set up CLASSPATH, PATH, LD_LIBRARY_PATH based on JDK version and platform. + * Compilation and Running: + * ======================== + * 4) If you already have the jars in step 3) in classpath + * javac aqorademo01.java + * + * 5) java aqorademo01 + * Example usage: + * java aqorademo01 orcl82 dlsun666 1521 thin + * + * Thin driver is used in the demo. Modify the connect string to use oci8 + * jdbc driver + ***/ + +/* Set up main class from which we will call subsequent examples and handle + exceptions: */ +import java.sql.*; +import oracle.AQ.*; + +public class aqorademo01 +{ + public static void main(String args[]) + { + AQSession aq_sess = null; + try + { + if (args.length < 4 ) + System.out.println("Usage:java filename [SID] [HOST] [PORT] [DRIVER]"); + else { + aq_sess = createSession(args); + /* now Enqueue and Dequeue Messages */ + createQTable(aq_sess) ; + enqRawMsg(aq_sess); + deqRawMsg(aq_sess); + dropQTable(aq_sess); + System.out.println("End of Demo") ; + } + } + catch (Exception ex) + { + System.out.println("Exception-1: " + ex); + ex.printStackTrace(); + } + } + +/* Create an Java AQ Session for the 'aqjava' user as shown in the + AQDriverManager section above: */ + + public static AQSession createSession(String args[]) throws Exception + { + Connection db_conn; + AQSession aq_sess = null; + + try + { + Class.forName("oracle.jdbc.OracleDriver"); + + String drv,url; + drv=args[3]; + + if ( drv.toLowerCase().compareTo("thin") == 0) + url="jdbc:oracle:"+args[3]+":@"+args[1]+":"+args[2]+":"+args[0]; + else { + url= new String ("jdbc:oracle:oci8:"); + url= url.concat("@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)" + + "(PORT=" + args[2] + + ")(HOST=" + args[1] + "))(CONNECT_DATA=(SID=" + + args[0] + ")))"); + + } + //"jdbc:oracle:thin:@host:port:sid" + System.out.println("Connect String is :"+url) ; + + db_conn = DriverManager.getConnection(url, "aqjava", "aqjava"); + + System.out.println("JDBC Connection opened "); + db_conn.setAutoCommit(false); + + /* Load the Oracle8i AQ driver: */ + Class.forName("oracle.AQ.AQOracleDriver"); + + /* Create an AQ Session: */ + aq_sess = AQDriverManager.createAQSession(db_conn); + System.out.println("Successfully created AQSession "); + } + catch (Exception ex) + { + System.out.println("Exception: " + ex); + throw ex; + } + return aq_sess; + } + + + public static void createQTable(AQSession aq_sess) throws Exception + { + AQQueueTableProperty qtable_prop; + AQQueueProperty queue_prop; + AQQueueTable q_table; + AQQueue queue; + + try { + /* Create a AQQueueTableProperty object (payload type - RAW): */ + qtable_prop = new AQQueueTableProperty("RAW"); + + /* Drop the queue if already exists */ + try { + q_table = aq_sess.getQueueTable ("aqjava", "aq_table4" ); + q_table.drop(true); + } catch (Exception e) {} ; + + /* Create a queue table called aq_table4 in aqjava schema: */ + q_table=aq_sess.createQueueTable ("aqjava", "aq_table4", qtable_prop); + System.out.println("Successfully created aq_table4 in aqjava schema"); + + /* Create a new AQQueueProperty object */ + queue_prop = new AQQueueProperty(); + + /* Create a queue called aq_queue4 in aq_table4: */ + queue = aq_sess.createQueue (q_table, "aq_queue4", queue_prop); + System.out.println("Successfully created aq_queue4 in aq_table4"); + + /* Enable enqueue/dequeue on this queue: */ + queue.start(); + System.out.println("Successful start queue"); + } catch (Exception e) { + System.out.println("Error in createQTable:"+ e); + throw e; + } + } + + + + public static void enqRawMsg(AQSession aq_sess) throws Exception + { + AQQueueTable q_table; + AQQueue queue; + AQMessage message; + AQRawPayload raw_payload; + AQEnqueueOption enq_option; + String test_data = "new message"; + byte[] b_array; + Connection db_conn; + + try { + db_conn = ((AQOracleSession)aq_sess).getDBConnection(); + + /* Get a handle to queue table - aq_table4 in aqjava schema: */ + q_table = aq_sess.getQueueTable ("aqjava", "aq_table4"); + System.out.println("Successful getQueueTable"); + + /* Get a handle to a queue - aq_queue4 in aquser schema: */ + queue = aq_sess.getQueue ("aqjava", "aq_queue4"); + System.out.println("Successful getQueue"); + + /* Create a message to contain raw payload: */ + message = queue.createMessage(); + + /* Get handle to the AQRawPayload object and populate it with raw data: */ + b_array = test_data.getBytes(); + + raw_payload = message.getRawPayload(); + + raw_payload.setStream(b_array, b_array.length); + + /* Create a AQEnqueueOption object with default options: */ + enq_option = new AQEnqueueOption(); + /* Enqueue the message: */ + queue.enqueue(enq_option, message); + + db_conn.commit(); + } catch (Exception e) { + System.out.println("Exception during Enqueue: " + e) ; + throw e; + } + } + + + + public static void deqRawMsg(AQSession aq_sess) throws Exception + { + AQQueueTable q_table; + AQQueue queue; + AQMessage message; + AQRawPayload raw_payload; + AQEnqueueOption enq_option; + String test_data = "new message"; + AQDequeueOption deq_option; + byte[] b_array; + Connection db_conn; + try { + db_conn = ((AQOracleSession)aq_sess).getDBConnection(); + + /* Get a handle to queue table - aq_table4 in aqjava schema: */ + q_table = aq_sess.getQueueTable ("aqjava", "aq_table4"); + System.out.println("Successful getQueueTable"); + + /* Get a handle to a queue - aq_queue4 in aquser schema: */ + queue = aq_sess.getQueue ("aqjava", "aq_queue4"); + System.out.println("Successful getQueue"); + + /* Create a message to contain raw payload: */ + message = queue.createMessage(); + + /* Get handle to the AQRawPayload object and populate it with raw data: */ + b_array = test_data.getBytes(); + + raw_payload = message.getRawPayload(); + + raw_payload.setStream(b_array, b_array.length); + + /* Create a AQEnqueueOption object with default options: */ + enq_option = new AQEnqueueOption(); + + /* Enqueue the message: */ + queue.enqueue(enq_option, message); + System.out.println("Successful enqueue"); + + db_conn.commit(); + + /* Create a AQDequeueOption object with default options: */ + deq_option = new AQDequeueOption(); + + /* Dequeue a message: */ + message = queue.dequeue(deq_option); + System.out.println("Successful dequeue"); + + /* Retrieve raw data from the message: */ + raw_payload = message.getRawPayload(); + + b_array = raw_payload.getBytes(); + + db_conn.commit(); + } catch (Exception e) { + System.out.println("Exception during Dequeue: " + e) ; + throw e; + } + } + public static void dropQTable(AQSession aq_sess) throws Exception + { + AQQueueTable q_table; + AQQueue queue ; + try { + q_table = aq_sess.getQueueTable ("aqjava", "aq_table4" ); + queue = aq_sess.getQueue("aqjava", "aq_queue4"); + queue.stop(true, true, true) ; + q_table.dropQueue("aq_queue4"); + q_table.drop(true); + } catch (Exception e) { + System.out.println("Error in dropQTable:"+ e); + } ; + + System.out.println("Successfully dropped aq_table4 in aqjava schema"); + } +} diff --git a/aqorademo02.java b/aqorademo02.java new file mode 100644 index 0000000..b5a0380 --- /dev/null +++ b/aqorademo02.java @@ -0,0 +1,260 @@ +/* $Header: aqorademo02.java 12-aug-2003.12:51:12 rbhyrava Exp $ */ + +/* Copyright (c) 2000, 2003, Oracle Corporation. All rights reserved. */ + +/* + DESCRIPTION + + + PRIVATE CLASSES + + + NOTES + + + MODIFIED (MM/DD/YY) + rbhyrava 08/12/03 - stop/drop queue/queuetables + rbhyrava 10/07/02 - import oracle.jdbc.* + rbhyrava 03/01/02 - use ORAData + rbhyrava 03/20/00 - oci driver + rbhyrava 03/16/00 - AQ API demos + rbhyrava 03/15/00 - AQ API demo - Object Type, Dequeue on Payload conten + rbhyrava 03/15/00 - Creation + */ + +/** + * @version $Header: aqorademo02.java 12-aug-2003.12:51:12 rbhyrava Exp $ + * @author rbhyrava + * @since release specific (what release of product did this appear in) + */ + +/*** + * This is a sample java file which uses Oracle AQ API to enqueue and + * dequeue Object Type Payload messages + + * -- Create a Queue + * -- Enqueue Object Payload message + * Dequeue Object Payload Message + * + * ORAData interface is used for Object types. Jpub generated classes + * are used and provided for reference. + * + * The following instructions describe how to compile and execute + * this sample on the client machine. + * + * System requirements: + * ==================== + * 1) Oracle 8.1.6 database or higher + * 2) The client machine should have JDK 1.1.x or JDK1.2 or higher installed + * 3) The following jar/zip files should be in the CLASSPATH on the client + * machine. + * For JDK1.2.x + * classes12.zip + * aqapi.jar + * For JDK1.1.x + * classes111.zip + * aqapi11.jar + * Set up CLASSPATH, PATH, LD_LIBRARY_PATH based on JDK version and platform. + * Compilation and Running: + * ======================== + * 4) If you already have the jars in step 3) in classpath + * javac aqorademo02.java ADDRESS.java PERSON.java + * + * 5) java aqorademo02 + * Example usage: + * java aqorademo02 orcl82 dlsun666 1521 thin + * + * Thin driver is used in the demo. Modify the connect string to use oci8 + * jdbc driver + * + ***/ + +/* Set up main class from which we will call subsequent examples and handle + exceptions: */ +import java.sql.*; +import oracle.AQ.*; + +public class aqorademo02 +{ + public static void main(String args[]) + { + AQSession aq_sess = null; + try + { + if (args.length < 4 ) + System.out.println("Usage:java filename [SID] [HOST] [PORT] [DRIVER]"); + else { + aq_sess = createSession(args); + /* now Enqueue and Dequeue Messages */ + createQTable(aq_sess) ; + AQObjectPayloadTest(aq_sess) ; + dropQTable(aq_sess) ; + System.out.println("End of Demo") ; + } + } + catch (Exception ex) + { + System.out.println("Exception-1: " + ex); + ex.printStackTrace(); + } + } + +/* Create an Java AQ Session for the 'aqjava' user as shown in the + AQDriverManager section above: */ + + public static AQSession createSession(String args[]) throws Exception + { + Connection db_conn; + AQSession aq_sess = null; + + try + { + Class.forName("oracle.jdbc.OracleDriver"); + String url, drv; + + drv=args[3]; + + if ( drv.toLowerCase().compareTo("thin") == 0) + url="jdbc:oracle:"+args[3]+":@"+args[1]+":"+args[2]+":"+args[0]; + else { + url= new String ("jdbc:oracle:oci8:"); + url= url.concat("@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)" + + "(PORT=" + args[2] + + ")(HOST=" + args[1] + "))(CONNECT_DATA=(SID=" + + args[0] + ")))"); + + } + //"jdbc:oracle:thin:@host:port:sid" + System.out.println("Connect String is :"+url) ; + + db_conn = DriverManager.getConnection(url, "aqjava", "aqjava"); + + System.out.println("JDBC Connection opened "); + db_conn.setAutoCommit(false); + + /* Load the Oracle8i AQ driver: */ + Class.forName("oracle.AQ.AQOracleDriver"); + + /* Create an AQ Session: */ + aq_sess = AQDriverManager.createAQSession(db_conn); + System.out.println("Successfully created AQSession "); + } + catch (Exception ex) + { + System.out.println("Exception: " + ex); + throw ex; + } + return aq_sess; + } + + + public static void createQTable(AQSession aq_sess) throws Exception + { + AQQueueTableProperty qtable_prop; + AQQueueProperty queue_prop; + AQQueueTable q_table; + AQQueue queue; + + try { + /* Create a AQQueueTableProperty object (payload type ): */ + qtable_prop = new AQQueueTableProperty("PERSON"); + + /* Drop the queue if already exists */ + try { + q_table = aq_sess.getQueueTable ("aqjava", "aq_table2" ); + q_table.drop(true); + } catch (Exception e) {} ; + + /* Create a queue table called aq_table2 in aqjava schema: */ + q_table = aq_sess.createQueueTable ("aqjava","aq_table2", qtable_prop); + System.out.println("Successfully created aq_table2 in aqjava schema"); + + /* Create a new AQQueueProperty object */ + queue_prop = new AQQueueProperty(); + + /* Create a queue called test_queue2 */ + queue = aq_sess.createQueue (q_table, "test_queue2", queue_prop); + System.out.println("Successfully created test_queue2 in aq_table2"); + + /* Enable enqueue/dequeue on this queue: */ + queue.start(); + System.out.println("Successful start queue"); + } catch (Exception e) { + System.out.println("Error in createQTable:"+ e); + throw e; + } + } + + public static void AQObjectPayloadTest(AQSession aq_sess) + throws AQException, SQLException, ClassNotFoundException + { + Connection db_conn = null; + AQQueue queue = null; + AQMessage message = null; + AQObjectPayload payload = null; + AQEnqueueOption eq_option = null; + AQDequeueOption dq_option = null; + PERSON pers = null; + PERSON pers2= null; + ADDRESS addr = null; + + db_conn = ((AQOracleSession)aq_sess).getDBConnection(); + + queue = aq_sess.getQueue("aqjava", "test_queue2"); + + /* Enqueue a message in test_queue2 */ + message = queue.createMessage(); + + pers = new PERSON(); + pers.setName("John"); + addr = new ADDRESS(); + addr.setStreet("500 Easy Street"); + addr.setCity("San Francisco"); + pers.setHome(addr); + + payload = message.getObjectPayload(); + payload.setPayloadData(pers); + eq_option = new AQEnqueueOption(); + + /* Enqueue a message into test_queue2 */ + queue.enqueue(eq_option, message); + + db_conn.commit(); + + /* Dequeue a message from test_queue2 */ + dq_option = new AQDequeueOption(); + message = ((AQOracleQueue)queue).dequeue(dq_option, PERSON.getORADataFactory()); + + payload = message.getObjectPayload(); + pers2 = (PERSON) payload.getPayloadData(); + + System.out.println("Object data retrieved: [PERSON]"); + System.out.println("Name: " + pers2.getName()); + System.out.println("Address "); + System.out.println("Street: " + pers2.getHome().getStreet()); + System.out.println("City: " + pers2.getHome().getCity()); + + db_conn.commit(); + } + + public static void dropQTable(AQSession aq_sess) throws Exception + { + AQQueueTable q_table; + AQQueue queue; + + try { + q_table = aq_sess.getQueueTable ("aqjava", "aq_table2" ); + queue = aq_sess.getQueue("aqjava", "test_queue2"); + queue.stop(true, true, true) ; + q_table.dropQueue("test_queue2"); + q_table.drop(true); + } catch (Exception e) { + System.out.println("Error in dropQTable:"+ e); + } ; + + System.out.println("Successfully dropped aq_table2 in aqjava schema"); + } + +} + + diff --git a/aqoradmo.sql b/aqoradmo.sql new file mode 100644 index 0000000..e4049e5 --- /dev/null +++ b/aqoradmo.sql @@ -0,0 +1,48 @@ +Rem +Rem $Header: aqoradmo.sql 16-nov-2004.15:56:51 rbhyrava Exp $ +Rem +Rem aqoradmo.sql +Rem +Rem Copyright (c) 2000, 2004, Oracle. All rights reserved. +Rem +Rem NAME +Rem aqoradmo.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbhyrava 11/16/04 - user creation +Rem rbhyrava 07/10/00 - AQ API demo - setup +Rem rbhyrava 07/10/00 - Created +Rem + +REM =========================================================== +REM SETUP for AQ Java API demos:create user and payload types +REM =========================================================== +SET echo on; +CONNECT system/manager; +DROP USER aqjava CASCADE; +CREATE USER aqjava IDENTIFIED BY aqjava; +GRANT CONNECT, RESOURCE, AQ_ADMINISTRATOR_ROLE TO aqjava; +GRANT EXECUTE ON DBMS_AQADM TO aqjava; +GRANT EXECUTE ON DBMS_AQ TO aqjava; +CONNECT aqjava/aqjava; + +CREATE TYPE address AS OBJECT ( + street VARCHAR (30), + city VARCHAR(30) +); +/ +CREATE TYPE person AS OBJECT ( + name VARCHAR (30), + home ADDRESS +); +/ +EXIT; +REM ============================================== +REM SETUP complete +REM ============================================== diff --git a/aqoradrp.sql b/aqoradrp.sql new file mode 100644 index 0000000..267f6ba --- /dev/null +++ b/aqoradrp.sql @@ -0,0 +1,28 @@ +Rem +Rem $Header: aqoradrp.sql 15-nov-2000.10:01:53 ociqa Exp $ +Rem +Rem aqoradrp.sql +Rem +Rem Copyright (c) Oracle Corporation 2000. All Rights Reserved. +Rem +Rem NAME +Rem aqoradrp.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ociqa 11/15/00 - +Rem rbhyrava 07/10/00 - demodrop script +Rem rbhyrava 07/10/00 - Created +Rem +REM -------------------- +REM Drop the user +REM -------------------- + +CONNECT system/manager ; +DROP USER aqjava CASCADE ; +EXIT; diff --git a/aqxml01.xml b/aqxml01.xml new file mode 100644 index 0000000..b6e24b1 --- /dev/null +++ b/aqxml01.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + aqxmladmn.book_q1 + + + + 3 + + + 1 + + + PROGRAMMING + 0 + + AGENT01 + 0 + + + + + + XML Unleashed + Mike Johnson + ISBN0101 + 25 + + + + + + 2 + + + CLASSICS + 0 + + AGENT02 + 0 + + + + + + GREAT ADVENTURES + Charles Dikens + ISBN0202 + 8 + + + + + 3 + + + CHILDREN + 0 + + AGENT01 + 0 + + + + + + MARY HAD A LITTLE LAMB + Tommy Close + ISBN0303 + 5 + + + + + + + + + diff --git a/aqxml02.xml b/aqxml02.xml new file mode 100644 index 0000000..b7c71e9 --- /dev/null +++ b/aqxml02.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + aqxmladmn.BOOK_Q1 + 0 + 10 + + + + + + diff --git a/aqxml03.xml b/aqxml03.xml new file mode 100644 index 0000000..7da5a1a --- /dev/null +++ b/aqxml03.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + aqxmladmn.cars_q1 + + + + 2 + + + 1 + + + CARS + 0 + + AGENT01 + 0 + + + + + + 4MEG123 + 2001 + BMW + RED + Red on Sale -20 + 35000 + + + + + + 2 + + + CARS + 0 + + AGENT02 + 0 + + + + + + 4PCE123 + 2000 + LEXUS + BLUE + In Stock -50 + 55000 + + + + + + + diff --git a/aqxml04.xml b/aqxml04.xml new file mode 100644 index 0000000..2d8e81c --- /dev/null +++ b/aqxml04.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + aqxmladmn.cars_q1 + DEALS_CARS_Q1 + 8 + + + + diff --git a/aqxml05.xml b/aqxml05.xml new file mode 100644 index 0000000..b78b328 --- /dev/null +++ b/aqxml05.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/aqxml06.xml b/aqxml06.xml new file mode 100644 index 0000000..e03ef4a --- /dev/null +++ b/aqxml06.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + aqxmladmn.jms_text_q1 + + + + 1 + + + 1 + + + JMSTEXT + 1 + + scott +
home
+ 0 +
+
+ + + + + + + oracle + + jmsuser + AQProduct + AQ + + + + + Country + USA + + + State + california + + + Zip + 94065 + + + + + All things bright and beautiful + All creatures great and small + All Things wise and Wonderful + The Great Lord made them all. + + + + +
+
+ + + +
+ +
+ diff --git a/aqxml07.xml b/aqxml07.xml new file mode 100644 index 0000000..f884538 --- /dev/null +++ b/aqxml07.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + aqxmladmn.JMS_TEXT_Q1 + 2 + 10 + + + + + + diff --git a/aqxml08.xml b/aqxml08.xml new file mode 100644 index 0000000..2681103 --- /dev/null +++ b/aqxml08.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + aqxmladmn.jms_map_q1 + + + + 1 + + + 1 + + + CARS + 0 + + scott +
home
+ 0 +
+ + + RECP1 + 0 + + +
+ + + + + + + oracle +
redwoodshores
+ 100 +
+ scott + AQProduct + AQ +
+ + + + country + USA + + + State + california + + + + + + make + Toyota + + + Color + Blue + + + Price + 20000 + + + +
+
+
+
+
+ +
diff --git a/aqxml09.xml b/aqxml09.xml new file mode 100644 index 0000000..f0f7227 --- /dev/null +++ b/aqxml09.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + aqxmladmn.jms_map_q1 + RECP1 + + + + diff --git a/aqxml10.xml b/aqxml10.xml new file mode 100644 index 0000000..cf3ba54 --- /dev/null +++ b/aqxml10.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/aqxmlREADME.txt b/aqxmlREADME.txt new file mode 100644 index 0000000..47079a6 --- /dev/null +++ b/aqxmlREADME.txt @@ -0,0 +1,266 @@ +/ +/ $Header: aqxmlREADME.txt 13-may-2008.13:16:32 rbhyrava Exp $ +/ +/ aqxmlREADME.txt +/ +/ Copyright (c) Oracle Corporation 2001. All Rights Reserved. +/ +/ NAME +/ aqxmlREADME.txt +/ +/ DESCRIPTION +/ This document contains list and description of aqxml demos +/ NOTES +/ +/ +/ MODIFIED (MM/DD/YY) +/ rbhyrava 05/13/08 - aqxmlctl args +/ rbhyrava 10/29/04 - OC4J support +/ rbhyrava 03/30/01 - Creation +/ + +The following files are required for running AQXML samples + + aqxmldmo.sql - Setup Users, Queue tables and Queues + aqxmldrp.sql - Drop/Cleanup AQ xml demo users/queue tables/queues + + aqxml01.xml AQXmlSend + Enqueue to ADT single consumer queue with piggyback commit + + aqxml02.xml AQXmlReceive + Dequeue from ADT Single consumer queue with piggyback commit + + aqxml03.xml AQXmlPublish + Enqueue to ADT (with LOB) multi consumer queue + + aqxml04.xml AQXmlReceive + Dequeue from ADT multi consumer queue + + aqxml05.xml AQXmlCommit + commit previous operation + + aqxml06.xml AQXmlSend + Enqueue to JMS Text single consumer queue with piggyback commit + + aqxml07.xml AQXmlReceive + Dequeue from JMS Text single consumer queue with piggyback commit + + aqxml08.xml AQXmlPublish + Enqueue JMS MAP message with recipient into multi consumer queue + + aqxml09.xml AQXmlReceive + Dequeue JMS MAP message from multi consumer queue + + aqxml10.xml AQXmlRollback + rollback previous operation + + aqxmlhtp.sql HTTP Propagation + + AQHttp.java , AQHttpRq.java - Helpers to Post XML Request using HTTPClient + + AQDemoServlet.java - Servlet to Post AQ XML files + AQPropServlet.java - Servlet for AQ HTTP Propagation + +For additional demos using E-business examples unzip +aqbzdemo.tar (aqbzdemo.zip for Windows). + +Steps to run demos using oc4j: +=============================== + +(1) Make sure classpath include the following: + + For JDK1.2.x or JDK1.3.x: + $ORACLE_HOME/jdbc/lib/classes12.zip + $ORACLE_HOME/jdbc/lib/nls_charset12.zip + $ORACLE_HOME/rdbms/jlib/aqapi.jar + $ORACLE_HOME/rdbms/jlib/jmscommon.jar + $ORACLE_HOME/rdbms/jlib/aqxml.jar + $ORACLE_HOME/rdbms/jlib/xsu12.jar + $ORACLE_HOME/rdbms/jlib/xdb.jar + $ORACLE_HOME/jlib/jndi.jar + $ORACLE_HOME/jlib/jta.jar + $ORACLE_HOME/jlib/jssl-1_1.jar + $ORACLE_HOME/jlib/javax-ssl-1_1.jar + $ORACLE_HOME/lib/xmlparserv2.jar + $ORACLE_HOME/lib/xsu12.jar + $ORACLE_HOME/lib/xschema.jar + $ORACLE_HOME/lib/http_client.jar + $ORACLE_HOME/lib/servlet.jar + $ORACLE_HOME/lib/lclasses12.zip + + For JDK1.4.x + $ORACLE_HOME/jdbc/lib/ojdbc14.jar + $ORACLE_HOME/jdbc/lib/orai18n.zip + $ORACLE_HOME/rdbms/jlib/aqapi.jar + $ORACLE_HOME/rdbms/jlib/jmscommon.jar + $ORACLE_HOME/rdbms/jlib/aqxml.jar + $ORACLE_HOME/rdbms/jlib/xdb.jar + $ORACLE_HOME/jlib/jndi.jar + $ORACLE_HOME/jlib/jta.jar + $ORACLE_HOME/jlib/jssl-1_1.jar + $ORACLE_HOME/jlib/javax-ssl-1_1.jar + $ORACLE_HOME/lib/xmlparserv2.jar + $ORACLE_HOME/lib/xsu12.jar + $ORACLE_HOME/lib/xschema.jar + $ORACLE_HOME/lib/http_client.jar + $ORACLE_HOME/lib/servlet.jar + $ORACLE_HOME/lib/lclasses12.zip + + NOTE : + http_client.jar, jssl-1_1.jar, javax-ssl-1_1.jar + are required by HTTPClient used in AQHttp.java AQHttpRq.java. + +(2) Compile AQHttpRq.java: + + cd $ORACLE_HOME/rdbms/demo + javac AQHttpRq.java AQHttp.java + +(3) Database Setup: + + Make sure init.ora file contains: + job_queue_processes=2 + compatible=10.2.0 or above + restart database and listener. + +(4) Users Authentication setup for restricted access and queues: + cd $ORACLE_HOME/rdbms/demo + SQL> @aqxmldmo.sql + +(5) Configure AQDemoServlet: + (deploy,start may be already done at your installation during install, see + step (6)). Otherwise, + + cd $ORACLE_HOME/bin + follow the steps for deploy, start of the servlet + + To Deploy the servlet: sh aqxmlctl deploy welcome + To Start OC4J instance: sh aqxmlctl start welcome + To Stop OC4J instance: sh aqxmlctl stop welcome + +(6) Verify the setup: + + #############------------------------------############## + NOTE: The default deployment is done using https protocol. + #############------------------------------############## + + Refer to $ORACLE_HOME/rdbms/demo/aqxml.ini for status of servlet. + Refer to $ORACLE_HOME/oc4j/j2ee/OC4J_AQ/config/rmi.xml + Refer to $ORACLE_HOME/oc4j/j2ee/OC4J_AQ/config/http-web-site.xml + for information on protocol,port number used for deploying this servlet. + + From the browser try, + https://:/aqserv/servlet/AQDemoServlet + replace hostname, portnumber, protocol with webserver host/port,protocol +used. + Eg: https request + https://my-pc:5760:aqserv/servlet/AQDemoServlet + + Eg: http request + http://my-pc:5740:aqserv/servlet/AQDemoServlet + + This should display (after prompting for user/password- john/welcome) + Sample AQ Servlet + AQxmlServlet is working! + + Refer to OC4J documentation for https configuration using admin.jar. + + (a) Creating an SSL Certificate and generating keystore. + Refer to keytool documentation for maintaining or creating + your own keystore. + + $ORACLE_HOME/rdbms/demo/keystore, + $ORACLE_HOME/rdbms/demo/aqxmloc4j.cert is provided for demo purposes. + + (b) The following tags in + $ORACLE_HOME/oc4j/j2ee/OC4J_AQ/config/http-web-site.xml indicate + the website is secure and keystore is used for SSL authentication. + + Modify http-web-site.html for secure tag and adding ssl-config. + + .... + + + + To make the site to access only http requests, remove the secure="true" and + from the http-web-site.xml. + Re-start the OC4J instance. + + Note: + The above step can also be done using admin.jar provided by OC4J Standalone. + + +(7) Http(s) Access: POST a request: + + Usage: + java AQHttpRq webuser pswd xmlfile xmlfile .. + + Example: + + cd $ORACLE_HOME/rdbms/demo; + Replace 7777,http in the sample requests below with appropriate + values of host, port and protocol(http/https) used in Step (6). + + (a) Enqueue to ADT single consumer queue with piggyback commit: + java AQHttpRq 7777 POST http /aqserv/servlet/AQDemoServlet john welcome aqxml01.xml + + (b) Dequeue from ADT Single consumer queue with piggyback commit: + java AQHttpRq 7777 POST http /aqserv/servlet/AQDemoServlet john welcome aqxml02.xml + + (c) Enqueue to ADT (with LOB) multi consumer queue and Commit + java AQHttpRq 7777 POST http /aqserv/servlet/AQDemoServlet john welcome aqxml03.xml aqxml05.xml + + (d) Dequeue from ADT multi consumer queue and Commit: + java AQHttpRq 7777 POST http /aqserv/servlet/AQDemoServlet john welcome aqxml04.xml aqxml05.xml + + (e) Enqueue to JMS Text single consumer queue with piggyback commit: + java AQHttpRq 7777 POST http /aqserv/servlet/AQDemoServlet john welcome aqxml06.xml + + (f) Dequeue from JMS Text single consumer queue with piggyback commit + java AQHttpRq 7777 POST http /aqserv/servlet/AQDemoServlet john welcome aqxml07.xml + + (g) Enqueue JMS MAP message with recipient into multi consumer queue-Commit + java AQHttpRq 7777 POST http /aqserv/servlet/AQDemoServlet john welcome aqxml08.xml aqxml05.xml + + (h) Dequeue JMS MAP message from multi consumer queue and Rollback + java AQHttpRq 7777 POST http /aqserv/servlet/AQDemoServlet john welcome aqxml09.xml aqxml10.xml + + (i) Dequeue JMS MAP message from multi consumer queue and Commit + to commit dequeue call + java AQHttpRq 7777 POST http /aqserv/servlet/AQDemoServlet john welcome aqxml09.xml aqxml05.xml + +(8) HTTP Propagation: + + (a) Make sure the AQPropServlet is working.See Step(6) + + (b) Run AQ http propagation demo. + Specify arguments protocol, hostname, portnumber for creating dblink. + + SQL>@aqxmlhtp http <7777> + +(9) HTTPS Propagation: + + (a) Make sure the AQPropServlet is working.See Step(6) + (b) Set up Wallet: + -create a new wallet using Oracle Wallet Manager + - Import trusted cerificate ($ORACLE_HOME/rdbms/demo/aqxmloc4j.cert) + - New trustpoint will be added + - select AutoLogin button under Wallet menu option + - Save the wallet to a directory location (eg: $ORACLE_HOME/rdbms/demo) + - Verify the two files created under the specified directory + cwallet.sso, ewallet.p12 + Exit Wallet Manager + + - add to network/admin/sqlnet.ora(replace $ORACLE_HOME) + eg: + oss.source.my_wallet= + (SOURCE=(METHOD=FILE)(METHOD_DATA= + (DIRECTORY=$ORACLE_HOME/rdbms/demo))) + + - from sqlplus + SQL>@aqxmlhtp https <443> + Specify arguments protocol, hostname, portnumber for creating dblink. + +(10) Cleanup: + (a) run aqxmldrp.sql to drop users/queues diff --git a/aqxmldemo.ear b/aqxmldemo.ear new file mode 100644 index 0000000..b453219 Binary files /dev/null and b/aqxmldemo.ear differ diff --git a/aqxmldmo.sql b/aqxmldmo.sql new file mode 100644 index 0000000..4d84833 --- /dev/null +++ b/aqxmldmo.sql @@ -0,0 +1,232 @@ +Rem +Rem $Header: aqxmldmo.sql 15-nov-2004.15:26:34 rbhyrava Exp $ +Rem +Rem aqxmldmo.sql +Rem +Rem Copyright (c) 2001, 2004, Oracle. All rights reserved. +Rem +Rem NAME +Rem aqxmldmo.sql - AQ xml demo - setup users, queues and queue tables +Rem +Rem DESCRIPTION +Rem AQ XML demos to perform AQ operations over the Internet +Rem using the Internet Data Access Presentation +Rem +REM This program is used to setup users, queue tables, queues to +REM demonstrate AQ xml access and propagation. +Rem +Rem NOTES +Rem This sql file creates AQ adminstrator , aq database user +Rem grant required privileges to AQ internet super user +Rem grant database access to internet AQ agents +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbhyrava 11/15/04 - agent +Rem rbhyrava 10/29/04 - add user setup +Rem rbhyrava 05/09/01 - remove REM from plsql blocK +Rem rbhyrava 04/12/01 - Merged rbhyrava_aqxmldemos +Rem rbhyrava 04/11/01 - +Rem rbhyrava 03/30/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +REM SETUP AQXML USERS +REM ================= + +REM +REM create admin and user accounts and grant http access to user +REM +CONNECT SYSTEM/MANAGER; +CREATE USER aqxmladmn IDENTIFIED BY aqxmladmn; +CREATE USER aqxmluser IDENTIFIED BY aqxmluser; + +GRANT CONNECT, RESOURCE, AQ_ADMINISTRATOR_ROLE TO aqxmladmn; +GRANT CONNECT, RESOURCE, AQ_USER_ROLE TO aqxmluser; + +GRANT EXECUTE ON dbms_lock TO aqxmladmn,aqxmluser ; + +REM +REM grant access to admin packages +REM +GRANT EXECUTE ON dbms_aqadm TO aqxmladmn; +GRANT EXECUTE ON dbms_aq TO aqxmluser; + +REM +REM Grant Create proxy session privileges to AQ servlet super-user +REM +GRANT CREATE SESSION TO scott; +ALTER USER aqxmluser GRANT CONNECT THROUGH scott; + +REM +REM Create AQ Agent to access AQ Servlet using HTTP +REM Used for 9.2/10.2 database compatibility for agent names +EXECUTE dbms_aqadm.create_aq_agent(agent_name=>'AQDEMO.COM/JOHN', enable_http =>true); +EXECUTE dbms_aqadm.create_aq_agent(agent_name=>'"AQDEMO.COM/JOHN"', enable_http =>true); + +REM +REM Map AQ Agent to Database user +REM +REM Used for 9.2/10.2 database compatibility for agent names +EXECUTE dbms_aqadm.enable_db_access('AQDEMO.COM/JOHN', 'aqxmluser'); +EXECUTE dbms_aqadm.enable_db_access('"AQDEMO.COM/JOHN"', 'aqxmluser'); + +REM +REM view registered AQ agents +REM +SELECT agent_name, db_username, http_enabled +FROM aq$internet_users ; + + +REM SETUP QUEUES +REM ================= + +CONNECT aqxmladmn/aqxmladmn; +SET SERVEROUTPUT ON + +rem create ADT +CREATE OR REPLACE TYPE book_typ AS OBJECT ( + title VARCHAR2(100), + authors VARCHAR2(100), + ISBN VARCHAR2(20), + price NUMBER); +/ + +GRANT EXECUTE ON book_typ TO PUBLIC ; + +CREATE OR REPLACE TYPE cars_typ AS OBJECT( + carno VARCHAR2(10), + year NUMBER, + model VARCHAR2(20), + color VARCHAR2(10), + car_details CLOB, + price NUMBER(12,2)); +/ + +GRANT EXECUTE ON cars_typ TO PUBLIC ; + +REM +REM create 8.1 compatible single consumer queue +REM +BEGIN +dbms_aqadm.create_queue_table( + queue_table => 'book_queue_tab', + queue_payload_type => 'BOOK_TYP' + ); +END; +/ + +REM +REM Create 8.1 compatible multi consumer queue table for ADT with CLOB +REM +BEGIN +dbms_aqadm.create_queue_table( + queue_table => 'cars_queue_tab', + queue_payload_type => 'CARS_TYP', + multiple_consumers => true + ); +END; +/ + +REM +REM Create single consumer queue table for JMS TEXT Message +REM +BEGIN +dbms_aqadm.create_queue_table( + queue_table => 'jmstext_queue_tab', + queue_payload_type => 'SYS.AQ$_JMS_TEXT_MESSAGE' + ); +END; +/ + +REM +REM Create multi consumer queue table for JMS MAP Message +REM +BEGIN +dbms_aqadm.create_queue_table( + queue_table => 'jmsmap_queue_tab', + queue_payload_type => 'SYS.AQ$_JMS_MAP_MESSAGE', + multiple_consumers => true + ); +END; +/ + +REM create queues +REM +BEGIN +dbms_aqadm.create_queue( queue_name => 'book_q1', + queue_table => 'book_queue_tab'); + +dbms_aqadm.create_queue( queue_name => 'cars_q1', + queue_table => 'cars_queue_tab'); + +dbms_aqadm.create_queue( queue_name => 'cars_q2', + queue_table => 'cars_queue_tab'); + +dbms_aqadm.create_queue( queue_name => 'jms_text_q1', + queue_table => 'jmstext_queue_tab'); + +dbms_aqadm.create_queue( queue_name => 'jms_map_q1', + queue_table => 'jmsmap_queue_tab'); +END; +/ + +REM +Rem Add subscribers to multi consumer queues +REM +BEGIN + dbms_aqadm.add_subscriber( queue_name=> 'CARS_Q1', + subscriber=> sys.aq$_agent('DEALS_CARS_Q1',null, null), + rule => 'tab.user_data.price > 30000'); + + dbms_aqadm.add_subscriber( queue_name=> 'CARS_Q2', + subscriber=> sys.aq$_agent('DEALS_CARS_Q2',null, null)); + + + dbms_aqadm.add_subscriber( queue_name=> 'JMS_MAP_Q1', + subscriber=> sys.aq$_agent('SUB1MAP',null, null)); + +END; +/ + +REM +REM Start queues +REM +BEGIN + dbms_aqadm.start_queue(queue_name => 'BOOK_Q1'); + dbms_aqadm.start_queue(queue_name => 'CARS_Q1'); + dbms_aqadm.start_queue(queue_name => 'CARS_Q2'); + dbms_aqadm.start_queue(queue_name => 'JMS_TEXT_Q1'); + dbms_aqadm.start_queue(queue_name => 'JMS_MAP_Q1'); +END; +/ + +REM +REM grant enqueue/dequeue privileges to aq database user +REM +BEGIN + dbms_aqadm.grant_queue_privilege('ENQUEUE', 'BOOK_Q1', 'aqxmluser', FALSE) ; + dbms_aqadm.grant_queue_privilege('DEQUEUE', 'BOOK_Q1', 'aqxmluser', FALSE) ; + + dbms_aqadm.grant_queue_privilege('ENQUEUE', 'CARS_Q1', 'aqxmluser', FALSE) ; + dbms_aqadm.grant_queue_privilege('DEQUEUE', 'CARS_Q1', 'aqxmluser', FALSE) ; + + dbms_aqadm.grant_queue_privilege('ENQUEUE', 'CARS_Q2', 'aqxmluser', FALSE) ; + dbms_aqadm.grant_queue_privilege('DEQUEUE', 'CARS_Q2', 'aqxmluser', FALSE) ; + + dbms_aqadm.grant_queue_privilege('ENQUEUE', 'JMS_TEXT_Q1','aqxmluser',FALSE) ; + dbms_aqadm.grant_queue_privilege('DEQUEUE', 'JMS_TEXT_Q1','aqxmluser',FALSE) ; + + dbms_aqadm.grant_queue_privilege('ENQUEUE', 'JMS_MAP_Q1','aqxmluser',FALSE) ; + dbms_aqadm.grant_queue_privilege('DEQUEUE', 'JMS_MAP_Q1','aqxmluser',FALSE) ; +END; +/ + +EXIT ; + diff --git a/aqxmldrp.sql b/aqxmldrp.sql new file mode 100644 index 0000000..336caae --- /dev/null +++ b/aqxmldrp.sql @@ -0,0 +1,90 @@ +Rem +Rem $Header: aqxmldrp.sql 02-nov-2004.17:21:31 rbhyrava Exp $ +Rem +Rem aqxmldrp.sql +Rem +Rem Copyright (c) 2001, 2004, Oracle. All rights reserved. +Rem +Rem NAME +Rem aqxmldrp.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbhyrava 11/02/04 - drop users +Rem rbhyrava 04/12/01 - Merged rbhyrava_aqxmldemos +Rem rbhyrava 04/09/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +connect aqxmladmn/aqxmladmn +REM Stop queues +BEGIN + dbms_output.put_line ('Stopping Queues ...'); + dbms_aqadm.stop_queue(queue_name => 'BOOK_Q1'); + dbms_aqadm.stop_queue(queue_name => 'CARS_Q1'); + dbms_aqadm.stop_queue(queue_name => 'CARS_Q2'); + dbms_aqadm.stop_queue(queue_name => 'JMS_TEXT_Q1'); + dbms_aqadm.stop_queue(queue_name => 'JMS_MAP_Q1'); +END; +/ + +REM Drop queues +BEGIN + dbms_output.put_line ('Dropping Queues ...'); + dbms_aqadm.drop_queue(queue_name => 'BOOK_Q1'); + dbms_aqadm.drop_queue(queue_name => 'CARS_Q1'); + dbms_aqadm.drop_queue(queue_name => 'CARS_Q2'); + dbms_aqadm.drop_queue(queue_name => 'JMS_TEXT_Q1'); + dbms_aqadm.drop_queue(queue_name => 'JMS_MAP_Q1'); +END; +/ + +BEGIN + dbms_output.put_line ('Dropping Queue Tables ...'); + dbms_aqadm.drop_queue_table ( + queue_table => 'book_queue_tab', + force => TRUE + ); + dbms_output.put_line ('Dropped Queue Table book_queue_tab.'); + dbms_aqadm.drop_queue_table ( + queue_table => 'cars_queue_tab', + force => TRUE + ); + dbms_output.put_line ('Dropped Queue Table cars_queue_tab.'); + + dbms_aqadm.drop_queue_table ( + queue_table => 'jmstext_queue_tab', + force => TRUE + ); + dbms_output.put_line ('Dropped Queue Table jmstext_queue_tab.'); + + dbms_aqadm.drop_queue_table ( + queue_table => 'jmsmap_queue_tab', + force => TRUE + ); + dbms_output.put_line ('Dropped Queue Table jmsmap_queue_tab.'); + +END; +/ + +connect system/manager + +EXECUTE dbms_aqadm.drop_aq_agent('"aqdemo.com/john"') ; +EXECUTE dbms_aqadm.drop_aq_agent('"AQDEMO.COM/JOHN"') ; +ALTER USER aqxmluser REVOKE CONNECT THROUGH scott; + +drop user aqxmladmn cascade ; +drop user aqxmluser cascade ; + diff --git a/aqxmlhtp.sql b/aqxmlhtp.sql new file mode 100644 index 0000000..9516449 --- /dev/null +++ b/aqxmlhtp.sql @@ -0,0 +1,190 @@ +Rem +Rem $Header: aqxmlhtp.sql 02-nov-2004.22:26:43 rbhyrava Exp $ +Rem +Rem aqxmlhtp.sql +Rem +Rem Copyright (c) 2001, 2004, Oracle. All rights reserved. +Rem +Rem NAME +Rem aqxmlhtp.sql - AQ xml HTTP Propagation Demo +Rem +Rem DESCRIPTION +Rem args passed : PROTOCOL,HOST, PORT arguments with appropriate values +Rem PROTOCOL is http or https +Rem HOST is webserver hostname +Rem PORT is http/(s) port number +Rem for eg: http://my-pc:18081/aqserv/servlet/AQPropServlet +Rem HOST is my-pc, PORT is 18081 +Rem NOTES +Rem See aqxmlREADME.txt for setup instructions +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbhyrava 11/02/04 - use oc4j +Rem rbhyrava 07/20/01 - args +Rem rbhyrava 06/20/01 - comments- dblink creation +Rem rbhyrava 05/09/01 - dequeue all messages +Rem rbhyrava 04/12/01 - Merged rbhyrava_aqxmldemos +Rem rbhyrava 03/30/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +REM create database link using http protocol for aq http propagation demo +REM john is http user using propagation with password welcome + +spool aqxmlhtp.log + +set serveroutput on +CONNECT / as sysdba ; +GRANT EXECUTE ON dbms_aqjms TO scott; +GRANT EXECUTE ON dbms_aqadm TO scott; +GRANT EXECUTE ON dbms_aqjms TO aqxmluser; +GRANT EXECUTE ON dbms_aqadm TO aqxmluser; +GRANT EXECUTE ON dbms_aq TO aqxmladmn ; + +REM create database link using http protocol +REM ---------------------------------------- + +drop public database link dba ; + +CREATE PUBLIC DATABASE LINK dba + CONNECT TO '"aqdemo.com/john"' IDENTIFIED BY "welcome" USING + '(DESCRIPTION=(ADDRESS=(PROTOCOL=&1)(HOST=&2)(PORT=&3)))' ; + +REM Verify the dblink status + + +SELECT owner, db_link, username, host, created + FROM dba_db_links + WHERE username IS NOT NULL ; + +connect aqxmladmn/aqxmladmn +set serveroutput on + +REM setup remote subscribers +BEGIN + + dbms_aqadm.remove_subscriber( queue_name=> 'CARS_Q1', + subscriber=> sys.aq$_agent( + 'HTTP_DEALS_CARS_Q1Q2','aqxmladmn.CARS_Q2@dba', NULL)); + +END; +/ + +BEGIN + dbms_aqadm.add_subscriber( queue_name=> 'CARS_Q1', + subscriber=> sys.aq$_agent( + 'HTTP_DEALS_CARS_Q1Q2','aqxmladmn.CARS_Q2@dba', NULL)); +END; +/ + +REM Schedule propagation +BEGIN + dbms_aqadm.unschedule_propagation(queue_name => 'aqxmladmn.CARS_Q1', + destination => 'dba'); +END; +/ + +BEGIN + dbms_aqadm.schedule_propagation(queue_name => 'aqxmladmn.CARS_Q1', + destination => 'dba'); +END; +/ + +connect aqxmluser/aqxmluser +set serveroutput on + +REM Enqueue messages + +CREATE OR REPLACE PROCEDURE ENQUEUE_CARS( cars aqxmladmn.CARS_TYP, pri in number) as +enq_msgid RAW(16); +eopt dbms_aq.enqueue_options_t; +mprop dbms_aq.message_properties_t; +rcpt dbms_aq.aq$_recipient_list_t; + +BEGIN + + mprop.priority := pri; + + dbms_aq.enqueue( + queue_name => 'aqxmladmn.cars_q1', + enqueue_options => eopt, + message_properties => mprop, + payload => cars, + msgid => enq_msgid); + dbms_output.put_line ('Enqueued ' || cars.car_details) ; +END ENQUEUE_CARS; +/ +show errors + +DECLARE + carspayload aqxmladmn.cars_typ ; +BEGIN + carspayload := aqxmladmn.cars_typ( + '3MEW123', 1999, 'BMW', 'RED','1999 Model BMW RED car', 45000) ; + enqueue_cars(carspayload, 1) ; + + carspayload := aqxmladmn.cars_typ( + '4MAT567', 2001, 'LEXUS', 'BLACK','2001 Model LEXUS BLACK car', 48000); + enqueue_cars(carspayload, 2) ; + +END; +/ +commit ; + +REM Dequeue Messages Now + + +CREATE OR REPLACE PROCEDURE DEQUEUE_CARS(appname varchar2) AS + deq_msgid RAW(16); + dopt dbms_aq.dequeue_options_t; + mprop dbms_aq.message_properties_t; + payload aqxmladmn.cars_typ; + no_messages exception; + pragma exception_init(no_messages, -25228); + +BEGIN + + dopt.consumer_name := appname; + dopt.wait := 30; + dopt.navigation := DBMS_AQ.FIRST_MESSAGE; + loop + dbms_aq.dequeue( + queue_name => 'aqxmladmn.cars_q2', + dequeue_options => dopt, + message_properties => mprop, + payload => payload, + msgid => deq_msgid); + + dbms_output.put_line ('-Carno:' || payload.carno || + ' Year :' || payload.year || + ' Model:' || payload.Model || + ' Color:' || payload.color || + ' Price:' || payload.Price ) ; + + commit; + end loop; + +EXCEPTION + WHEN no_messages THEN + dbms_output.put_line('No more messages in queue '); + commit; + +END DEQUEUE_CARS; +/ +show errors + +execute dbms_lock.sleep(100) ; + +BEGIN + DEQUEUE_CARS ('HTTP_DEALS_CARS_Q1Q2' ) ; +END; +/ +commit ; +spool off diff --git a/blobdemo.dat b/blobdemo.dat new file mode 100644 index 0000000..2bebc2f --- /dev/null +++ b/blobdemo.dat @@ -0,0 +1,2 @@ +1234567890 + diff --git a/calldemo.sql b/calldemo.sql new file mode 100644 index 0000000..8b9f7c9 --- /dev/null +++ b/calldemo.sql @@ -0,0 +1,87 @@ +rem +rem $Header: calldemo.sql 21-sep-2004.11:03:44 stsun Exp $ +rem +rem Copyright (c) 1991, 2004, Oracle. All rights reserved. +rem +rem NAME +rem calldemo.sql - +rem DESCRIPTION +rem +rem RETURNS +rem +rem NOTES +rem +rem MODIFIED (MM/DD/YY) +rem stsun 09/21/04 - add order by the query +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem rkooi2 11/27/92 - Creation +CREATE OR REPLACE PACKAGE calldemo AS + + TYPE char_array IS TABLE OF VARCHAR2(20) + INDEX BY BINARY_INTEGER; + TYPE num_array IS TABLE OF FLOAT + INDEX BY BINARY_INTEGER; + + PROCEDURE get_employees( + dept_number IN number, -- department to query + batch_size IN INTEGER, -- rows at a time + found IN OUT INTEGER, -- rows actually returned + done_fetch OUT INTEGER, -- all done flag + emp_name OUT char_array, + job OUT char_array, + sal OUT num_array); + +END calldemo; +/ + +CREATE OR REPLACE PACKAGE BODY calldemo AS + + CURSOR get_emp (dept_number IN number) IS + SELECT ename, job, sal FROM emp + WHERE deptno = dept_number + ORDER BY ename, job, sal; + + -- Procedure "get_employees" fetches a batch of employee + -- rows (batch size is determined by the client/caller + -- of the procedure). It can be called from other + -- stored procedures or client application programs. + -- The procedure opens the cursor if it is not + -- already open, fetches a batch of rows, and + -- returns the number of rows actually retrieved. At + -- end of fetch, the procedure closes the cursor. + + PROCEDURE get_employees( + dept_number IN number, + batch_size IN INTEGER, + found IN OUT INTEGER, + done_fetch OUT INTEGER, + emp_name OUT char_array, + job OUT char_array, + sal OUT num_array) IS + + BEGIN + IF NOT get_emp%ISOPEN THEN -- open the cursor if + OPEN get_emp(dept_number); -- not already open + END IF; + + -- Fetch up to "batch_size" rows into PL/SQL table, + -- tallying rows found as they are retrieved. When all + -- rows have been fetched, close the cursor and exit + -- the loop, returning only the last set of rows found. + + done_fetch := 0; -- set the done flag FALSE + found := 0; + + FOR i IN 1..batch_size LOOP + FETCH get_emp INTO emp_name(i), job(i), sal(i); + IF get_emp%NOTFOUND THEN -- if no row was found + CLOSE get_emp; + done_fetch := 1; -- indicate all done + EXIT; + ELSE + found := found + 1; -- count row + END IF; + END LOOP; + END; +END; +/ diff --git a/case1.rcv b/case1.rcv new file mode 100644 index 0000000..cf19e5b --- /dev/null +++ b/case1.rcv @@ -0,0 +1,260 @@ +# +# $Header: case1.rcv 11-apr-2001.15:20:02 banand Exp $ +# +# Copyright (c) 1995, 2000 Oracle Corporation. All rights reserved. +# +# NAME +# case1.rcv +# +# DESCRIPTION +# This case study can be used as the basis for developing your own backup, +# maintenance, restore, and recovery scripts for a single instance database +# running in no-archivelog mode. +# +# NOTES +# You should not run all of the commands in this file in a single RMAN +# session. Rather, the various sections in this file should be separated +# into individual RMAN scripts which can be run to configure, backup, +# restore, and recover the database. +# +# MODIFIED (MM/DD/YY) +# banand 04/11/01 - re-write this case for no-archivelog mode database +# banand 04/11/01 - Creation +# +# Organization: +# This case study is divided into the following sections: +# 1. Configuring RMAN parameters +# 2. Backup +# - start script for backup cycle +# (full level 0 consistent backups) +# - script for other days of backup cycle +# (differential incremental level 1 consistent backups) +# - taking backups of read-only tablespace +# 3. Restore validation +# - command to verify database is restorable. +# 4. Recovery Catalog maintenance +# 5. Restore and Recovery +# +# How to run a file containing RMAN commands: +# +# Here is an example of how to run a file that contains RMAN commands: +# rman target internal/pwd@prod1 catalog rman/rman@rcat cmdfile command.rcv +# +# See the Recovery Manager Users Guide for more options on how to connect. +# + +# Section 1 - CONFIGURATION +#----------------------------------------------------------------------------- + +# There are various parameters that can be used to configure RMAN operations +# to suit your needs. Some of the things that you can configure are: +# - the required number of backups of each datafile +# - the number of server processes that will do backup/restore operations +# in parallel +# - the directory where on-disk backups will be stored +# +# This case study assumes that you want: +# - 5 backups of each datafile +# - backups to be stored on disk in the /backup directory +# - 2 server processes to do backup/restore operations in parallel +# - no backups for tablespace tbl_exclude, because it is easy to recreate +# +# It should be noted that configuration settings are stored persistently, and +# will be used by RMAN for all subsequent backup, restore, recovery, and +# maintenance operations. + +# Configure backups to be written to disk. +CONFIGURE DEFAULT DEVICE TYPE TO DISK; + +# Configure RMAN to keep at least 5 backups of each datafile. +# If you have certain backups which must be retained longer than this +# retention policy, you can use the KEEP option with the BACKUP command when +# creating those backups. +CONFIGURE RETENTION POLICY TO REDUNDANCY 5; + +# Configure RMAN to use two disk channels for backup, restore, recovery, and +# maintenance operations. +CONFIGURE DEVICE TYPE DISK PARALLELISM 2; + +# Configure RMAN to write disk backups to the /backup directory. +# The format specifier %t is replaced with a 4-byte timestamp, %s with the +# backup set number, and %p with the backup piece number. +CONFIGURE CHANNEL DEVICE TYPE DISK FORMAT '/backup/ora_df%t_s%s_s%p'; + +# Configure RMAN to back up the control file after each backup. +CONFIGURE CONTROLFILE AUTOBACKUP ON; + +# Configure RMAN to write controlfile autobackups to the /backup directory. +CONFIGURE CONTROLFILE AUTOBACKUP FORMAT FOR DEVICE TYPE DISK TO '/backup/ora_cf%F'; + +# Excludes tbs_exclude from full database backups. NOEXCLUDE can be specified +# with the BACKUP command to override this configuration. +CONFIGURE EXCLUDE FOR TABLESPACE tbl_exclude; + +# NOTES: +# - If you want backups to go to tape, refer to the configuration +# section in case2.rcv on how to configure tape backups. +# However in case of disaster recover if RMAN is not connected to +# recovery catalog, you will have to manually allocate all channels where +# backups were taken. +# +# - Use the SHOW ALL command to see your current configuration settings. +# +# - Save the database id displayed in the RMAN output if you are taking +# RMAN backups in nocatalog mode or database name is ambigious in recovery +# catalog. The database id is required during disaster recovery (See +# Section 5). You will see the database id in RMAN output on connecting +# to target database like : +# +# connected to target database: INVENTORY (DBID=1670954628) + +# Section 2 - BACKUP +# ----------------------------------------------------------------------------- +# Since you are operating the database in no-archivelog mode, only the +# following kinds of backups are allowed: +# - whole database backups when the database is cleanly closed and the +# instance is mounted +# - tablespace backups of tablespaces that are offline clean or read only + +# The following scenario assumes that you want to take one full database +# backup every week, and one incremental database backup every day. The +# backup cycle starts on Friday. A full backup is taken on Friday, and an +# incremental backup is taken every other day. The retention policy of +# REDUNDANCY 5 applies only to full (not incremental) backups, so the +# combination of that policy and this backup schedule ensures that you can +# restore to any incremental backup time for the last 5 weeks. + +# Section 2.1 - Start script for backup cycle +# ------------------------------------------------------ +# The following commands are run each Friday to start the backup cycle. +# The steps are: +# - Re-start the database to perform crash recovery, in case the database is +# not currently open, and was not shut down consistently. The database is +# started in DBA mode so that normal users cannot connect. +# - Shut down with the IMMEDIATE option to close the database consistently. +# - Startup and mount the database. +# - Backup database with incremental level 0. +# - Open database for normal operation. + +STARTUP FORCE DBA; +SHUTDOWN IMMEDIATE; +STARTUP MOUNT; +BACKUP INCREMENTAL LEVEL 0 DATABASE FILESPERSET 4; +ALTER DATABASE OPEN; + + +# If the above backup fails for any reaon, you can use the NOT BACKED UP SINCE +# option on the BACKUP command (9i restartable backup feature) to continue +# from the point of failure. The small value of FILESPERSET is good for +# restartable backups. However you should note that smaller FILESPERSET +# produces more backup sets. + +# To re-start from the point of failure, run following commands +BACKUP INCREMENTAL LEVEL 0 DATABASE FILESPERSET 4 + NOT BACKED UP SINCE TIME 'SYSDATE-1'; +ALTER DATABASE OPEN; + + +# Section 2.2 - script for other days of the backup cycle +# ------------------------------------------------------------- +# The following commands can be run from Saturday through Thursday to take +# cumulative incremental backups. They are same as in section 2.1, except +# that LEVEL 1 is specified on BACKUP command. +# The steps are the same as in section 2.1, except that the options +# LEVEL 1 CUMULATIVE indicate that only the blocks that have changed +# since the last level 0 backup will be backed up. If the CUMULATIVE +# option was not specified, then only the blocks that have changed since +# the last level 1 backup will be backed up. The advantage of a cumulative +# backup is that only one incremental backup ever needs to be applied +# during recovery. + +STARTUP FORCE DBA; +SHUTDOWN IMMEDIATE; +STARTUP MOUNT; +BACKUP INCREMENTAL LEVEL 1 CUMULATIVE DATABASE FILESPERSET 4; +ALTER DATABASE OPEN; + + +# Section 2.3 - Taking backups of readonly tablespaces +# ---------------------------------------------------- +# The database does not have to be closed to back up a readonly tablespace. +# The following command can be used to backup a readonly tablespace. + +BACKUP TABLESPACE read_only_tablespace_name; + +# Section 3 - RESTORE VALIDATION +#----------------------------------------------------------------------------- +# The following commands can be run any time to check if RMAN is capable of +# restoring database/tablespace using existing backups. + +RESTORE DATABASE VALIDATE; # checks if database + # can be restored +RESTORE TABLESPACE read_only_tablespace_name VALIDATE; # check if tablespace + # is restorable + +# Section 4 - MAINTENANCE COMMANDS +#----------------------------------------------------------------------------- +# Basic steps for maintenance are: + +# - Verify all backups on backup media are intact +CROSSCHECK BACKUP OF DATABASE; + +# - Display a list of files that need to be backed up based on the retention +# policy. For this case study, files that don't have at least 5 backups +# will be reported. +REPORT NEED BACKUP; + +# - delete un-necessary backups. This command deletes backups based on the +# retention policy. For this case study, all backups older than the 5 most +# recent backups of each datafile will be deleted. +DELETE OBSOLETE; + +# - get complete list of existing backups +LIST BACKUP SUMMARY; + + +# Section 5 - RESTORE AND RECOVERY +#----------------------------------------------------------------------------- +# In case of any user error or media failure you would have to do complete +# database recovery. However using the SET UNTIL command, it is possible to +# recover to different points in time when incrementals were taken. Because +# redo logs are not archived, only full and incremental backups are available +# for restore and recovery. +# + +# It is assumed that you have all the configuration files like the server +# parameter file (spfile - equivalent of init.ora in 9i), tnsnames.ora, and +# listener.ora in the appropriate places, and that you can startup the Oracle +# instance in nomount mode and connect from RMAN to the target instance. + +# +# The steps are: +# - If not using a recovery catalog, or if the database name is ambiguous in, +# the recovery catalog you need to start RMAN without TARGET option and +# set the dbid before restoring the controlfile from autobackup. +# - Startup database in nomount mode (you should have restored initialization +# files for database, and listener files (only if connecting over SQLNET)). +# - restore controlfile. +# - restore all database files. Use CHECK READONLY, to make sure all read-only +# files are correct. If not RMAN will restore them. +# - apply all incrementals. +# - open database with resetlogs mode to re-create online logs. + + +SET DBID ; +CONNECT TARGET ; +STARTUP NOMOUNT; +RUN +{ + # uncomment the SET UNTIL command to restore database to the incremental + # backup taken three days ago. + # SET UNTIL TIME 'SYSDATE-3'; + SET CONTROLFILE AUTOBACKUP FORMAT FOR DEVICE TYPE DISK TO '/backup/ora_cf%F'; + RESTORE CONTROLFILE FROM AUTOBACKUP; + ALTER DATABASE MOUNT; + RESTORE DATABASE CHECK READONLY; + RECOVER DATABASE NOREDO; + ALTER DATABASE OPEN RESETLOGS; +} + +#-end of file- diff --git a/case2.rcv b/case2.rcv new file mode 100644 index 0000000..1b3a9ab --- /dev/null +++ b/case2.rcv @@ -0,0 +1,480 @@ +# +# $Header: case2.rcv 27-apr-2001.12:41:14 banand Exp $ +# +# Copyright (c) 1995, 2001, Oracle Corporation. All rights reserved. */ +# +# NAME +# case2.rcv +# +# DESCRIPTION +# This case study can be used as basis for developing your own backup, +# maintenance, restore, and recovery scripts for a single instance database +# running in archivelog mode. +# +# The examples provided in this case study will use a disk area (/backup +# directory) to hold the most recent one week of backups, in order to +# expedite backup/restore operations. The size of this area may vary +# depending on database size, redo generated, etc. If you want all backups +# to go to tape, remove DEVICE TYPE DISK option from the BACKUP commands +# given in this case study. + +# Only the incremental backups are stored on disk for one week. The level 0 +# backup goes immediately to tape. This means that RMAN will always have to +# read tape for recovery. + +# +# NOTES +# You should not run all of the commands in this file in a single RMAN +# session. Rather, the various sections in this file should be separated +# into individual RMAN scripts which can be run to configure, backup, +# restore, and recover the database. +# +# +# MODIFIED (MM/DD/YY) +# banand 04/11/01 - re-write this case for archivelog mode database +# banand 04/11/01 - Creation +# +# Organization: +# +# This case study is divided into the following sections: +# 1. Configuring RMAN parameters +# 2. Backup +# - start script for backup cycle +# (full database backup and archivelog backups) +# - script for other days of backup cycle +# (cumulative incremental level 1 backups and archivelog backups) +# 3. Restore validation +# - verify that the database/tablespace is restorable +# 4. Maintenance commands +# 5. Restore and Recovery +# - Datafile recovery +# - Tablespace recovery +# - Controlfile recovery +# - Block recovery +# - Disaster recovery +# - Database Point-in-time recovery +# +# How to run the file containing RMAN commands: +# +# Here is an example of how to run the file that contains RMAN commands: +# +# rman target internal/pwd@prod1 catalog rman/rman@rcat cmdfile command.rcv +# +# See the Recovery Manager readme.doc and the Oracle8 Backup and +# Recovery Guide for more options on how to connect. +# +# + +# Section 1 - CONFIGURATION +# ---------------------------------------------------------------------------- + +# There are various parameters that can be used to configure RMAN operations +# to suit your needs. Some of the things that you can configure are: +# - the recovery window, to keep backups so that it is possible to recover +# the database to any point in time during last X days. +# - the number of server processes that can do backups/restore operations +# in parallel +# - default device type for backups +# - the directory where on-disk backups will be stored +# +# This case study assumes that you +# - have 1 tape drive +# - want parallelization for disk to two and for tape to one +# - want to be able to recover your database to any point in time during the +# last 30 days +# - want all full database backups to go only to tape +# - want to keep incrementals on disk for seven days +# - want to leave archivelogs on disk for seven days +# - want one copy of each archivelog backup saved on tape +# - want to back up archivelogs once per day +# - want to exclude tablespace tbl_exclude from database backups and +# restores because it is easier to re-create it than to restore and +# recover it. +# +# It should be noted that configuration setting is done just once, and these +# settings are used by RMAN to perform all subsequent backup, restore, +# recovery, and maintenance operations. + +# Configure backups to be written to tape, via a 3rd-party media managment +# product. +CONFIGURE DEFAULT DEVICE TYPE TO SBT; + +# If the media manager requires an RMAN PARMS string, configure it here. +# The media manager documentation will specify whether this configuration is +# needed. +CONFIGURE CHANNEL DEVICE TYPE SBT PARMS ''; + +# Configure the number of server processes (channels) that write backups to +# DISK. You can delete these three lines if you want to only back up to tape. +CONFIGURE DEVICE TYPE DISK PARALLELISM 2; +CONFIGURE CHANNEL DEVICE TYPE DISK FORMAT '/backup/ora_df%t_s%s_s%p'; +CONFIGURE CONTROLFILE AUTOBACKUP FORMAT FOR DEVICE TYPE DISK TO '/backup/%F'; + +# Set the retention policy to a recovery window of 30 days. This ensures that +# RMAN retains all backups needed to recover the database to any point in time +# in the last 30 days. You can use the DELETE OBSOLETE command to delete +# backups that are no longer required by the retention policy. To exclude a +# backup from consideration by the policy, you can use KEEP option with the +# BACKUP command. +CONFIGURE RETENTION POLICY TO RECOVERY WINDOW OF 30 DAYS; + +# Enable the autobackup feature to backup the controlfile after each database +# or archivelog backup. +CONFIGURE CONTROLFILE AUTOBACKUP ON; + +# Enable the backup optimization feature introduced in 9i to make sure that +# RMAN won't backup an archivelog or datafile if there already exists a backup +# of that file. The FORCE option can be used to override optimization on a +# specific BACKUP command. +CONFIGURE BACKUP OPTIMIZATION ON; + +# Exclude tbs_exclude from full database backups. NOEXCLUDE can be specified +# with backup command to override this configuration. +CONFIGURE EXCLUDE FOR TABLESPACE tbl_exclude; + +# IMPORTANT: Save the database id displayed in the RMAN output if you are +# operating RMAN backups in nocatalog mode, since it is required during +# disaster recovery. You will see the database id in output from RMAN on +# connecting to target database like: +# +# connected to target database: INVENTORY (DBID=1670954628) + +# Use the SHOW ALL command to see the current configuration settings. + +# Section 2 - BACKUP +#----------------------------------------------------------------------------- +# Running database in archivelog mode provides following advantages +# - high availability, i.e., database is available during backups. +# - point in time recovery within recovery window for database/tablespace. + +# You can also follow the procedure given in case1.rcv for taking consistent +# backups. Only disadvantage of taking consistent backups is that you have to +# close database cleanly, and open in restricted mode. Hence database is not +# available for general use during consistent backup. +# +# Following scenario assumes that you want to take one full database once a +# week, doing every day incrementals. Backup cycle starts on friday, +# i.e., every friday full backup, and on other days incrementals. + + +# Section 2.1 - Start script for backup cycle +# ------------------------------------------- +# The following commands are run each Friday to start the backup cycle. +# The steps are: +# - Take an incremental level 0 backup of the database. A level 0 backup is +# a complete backup of the entire file which can be used as the basis +# for a subsequent incremental backup. +# - Backup all archivelogs that have not already been backed up. +# - Delete on-disk archivelogs older than seven days. + +BACKUP INCREMENTAL LEVEL 0 DATABASE FILESPERSET 4; +BACKUP ARCHIVELOG ALL; +DELETE ARCHIVELOG UNTIL TIME 'SYSDATE-7'; + +# If the above backup fails for any reaon, you can use the NOT BACKED UP SINCE +# option on the BACKUP command (9i restartable backup feature) to continue +# from the point of failure. The small value of FILESPERSET is good for +# restartable backups. However you should note that smaller FILESPERSET +# produces more backup sets. + +# Use the following commands to re-start backups after a failure: +BACKUP INCREMENTAL LEVEL 0 DATABASE FILESPERSET 4 + NOT BACKED UP SINCE TIME 'SYSDATE-1'; +BACKUP ARCHIVELOG ALL; +DELETE ARCHIVELOG UNTIL TIME 'SYSDATE-7'; + +# Section 2.2 - script for other days of backup cycle +# ----------------------------------------------------- +# The following commands can be run from Saturday through Thursday to take +# cumulative incremental backups. +# The steps are: +# - delete incrementals on disk that were taken before 7 days. +# - take differential incremental backup of complete database. +# - copy incrementals to tape. +# - backup all archiveogs that are not backed up. +# - deletes any copies of archivelog on disk older than 7 days. + +DELETE BACKUP COMPLETED BEFORE 'SYSDATE-7' DEVICE TYPE DISK; +BACKUP INCREMENTAL LEVEL 1 CUMULATIVE DEVICE TYPE DISK DATABASE FILESPERSET 4; +BACKUP BACKUPSET ALL; # copies backups from disk to tape +BACKUP ARCHIVELOG ALL; +DELETE ARCHIVELOG UNTIL TIME 'SYSDATE-7'; + +# CONCEPT NOTE ON CUMULATIVE INCREMENTAL BACKUPS: Cumulative incremental level +# 1 backups will backup the blocks that changed since the last level 0 backup. +# Incremental backups are similar in function to archived logs and RMAN uses +# them in favor of archived logs during recovery. If the CUMULATIVE option +# was not specified, then only the blocks that have changed since the last +# level 1 backup will be backed up. The advantage of a cumulative backup is +# that only one incremental backup ever needs to be applied during recovery. + +# As in section 2.1, you can use the NOT BACKED UP SINCE option with the +# BACKUP command (9i re-startable backup feature) to continue from the point +# of failure. + +# Use the following commands to re-start backups after a failure: +DELETE BACKUP COMPLETED BEFORE 'SYSDATE-7' DEVICE TYPE DISK; +BACKUP INCREMENTAL LEVEL 1 CUMULATIVE DEVICE TYPE DISK DATABASE FILESPERSET 4 + NOT BACKED UP SINCE TIME 'SYSDATE -1 '; +BACKUP BACKUPSET ALL; # copies backups from disk to tape +BACKUP ARCHIVELOG ALL; +DELETE ARCHIVELOG UNTIL TIME 'SYSDATE-7'; + +# Section 3 - RESTORE VALIDATION +# ---------------------------------------------------------------------------- +# The following commands can be run any time to check if RMAN is capable of +# restoring the database/tablespace using existing backups. + +# check if database can be restored +RESTORE DATABASE VALIDATE; + +# check if tablespace tst_tbs can be restored +RESTORE TABLESPACE tst_tbs VALIDATE; + +# check if controlfile can be restored +RESTORE CONTROLFILE VALIDATE; + +# check if archivelogs for the past two weeks can be restored +RESTORE ARCHIVELOG FROM TIME 'SYSDATE-14' VALIDATE; + + +# Section 4 - MAINTENANCE COMMANDS +#----------------------------------------------------------------------------- +# The following commands can be run any time for maintenance of backups. + +# Verify that all backups which RMAN thinks are stored by the third-party +# media manager still exist, and generate a report of backups that need to be +# taken to satisy the retention policy. +CROSSCHECK BACKUP; +REPORT NEED BACKUP; + +# Delete backups that are no longer needed to satisfy the retention policy. +# Since we have set the retention policy to a recovery window of 30 days, any +# datafile backups (generated without the KEEP option) not required to recover +# within 30 days are deleted. After deciding which datafile backups are no +# longer needed, RMAN can then decide which archivelog backups are no longer +# needed. Archivelog backups are not needed if they are older than ANY +# existing datafile backup. +DELETE OBSOLETE; + +# get complete list of existing backups +LIST BACKUP SUMMARY; + + +# Section 5 - RESTORE AND RECOVERY +#----------------------------------------------------------------------------- +# +# Section 5.1 - Datafile recovery +#----------------------------------------------------- +# +# This section assumes that datafile 5 has been damaged and needs to be +# restored and recovered, and that the current controlfile and all other +# datafiles are intact. The database is open during the restore and recovery. +# +# The steps are: +# - offline the datafile that needs recovery +# - restore the datafile from backups +# - apply incrementals and archivelogs as necessary to recover. +# - make online recovered datafile + +RUN +{ + SQL 'ALTER DATABASE DATAFILE 5 OFFLINE'; + + # If you want to restore to a different location, uncomment the following + # command. + # SET NEWNAME FOR DATAFILE 5 TO '/newdirectory/new_filename.f'; + + RESTORE DATAFILE 5; + + # If you restored to a different location, uncomment the command below to + # switch the controlfile to point to the file in the new location. + # SWITCH DATAFILE ALL; + + RECOVER DATAFILE 5; + SQL 'ALTER DATABASE DATAFILE 5 ONLINE'; +} + +# Section 5.2 - Tablespace recovery +#------------------------------------------------------- +# +# This section assumes that tablespace tbs_5, containing datafiles 5, 6, and 7 +# has been damaged and needs to be restored and recovered, and that the +# current controlfile and all other datafiles are intact. The database is +# open during the restore and recovery. +# +# The steps are: +# - Offline the tablespace that needs recovery. +# - Restore the tablespace from backups. +# - Apply incrementals and archivelogs as necessary to recover. +# - Online the recovered tablespace. + +RUN +{ + SQL 'ALTER TABLESPACE TBS_5 OFFLINE'; + + # If you want to restore to a different location, uncomment the following + # commands. + # SET NEWNAME FOR DATAFILE 5 TO '/newdirectory/new_filename_for_5.f'; + # SET NEWNAME FOR DATAFILE 6 TO '/newdirectory/new_filename_for_6.f'; + # SET NEWNAME FOR DATAFILE 7 TO '/newdirectory/new_filename_for_7.f'; + + RESTORE TABLESPACE TBS_5; + + # If you restored to different locations, uncomment the commands below to + # switch the controlfile to point to the files in their new locations. + # SWITCH DATAFILE ALL; + + RECOVER TABLESPACE TBS_5; + SQL 'ALTER TABLESPACE TBS_5 ONLINE'; +} + +# Section 5.3 - Controlfile recovery +#----------------------------------- +# + +# Oracle strongly recommends that you specify multiple controlfiles, on +# separate physical disks and controllers, in the CONTROL_FILES initialization +# parameter. +# - If one copy is lost due to media failure, copy one of the others over the +# lost controlfile and restart the instance. +# - If you lose all copies of the controlfile, you must re-create it using +# the CREATE CONTROLFILE sql command. +# +# You should use RMAN to recover a backup controlfile only if you have lost +# all copies of the current controlfile, because after restoring a backup +# controlfile, you will have to open RESETLOGS and take a new whole database +# backup. +# +# This section assumes that all copies of the current controlfile have been +# lost, and that all initialization parameter files, datafiles and online logs +# are intact. +# +# Ensure you set your NLS_LANG environment variable. +# e.g. in unix (csh): +# > setenv NLS_LANG american_america.we8dec +# +# Start RMAN without the TARGET option, and use the following commands to +# restore and recover the database: + +SET DBID ; # use database id from RMAN output as + # explained in Section 2.1, + # not required if using recovery catalog +CONNECT TARGET ; +STARTUP NOMOUNT; +RUN +{ + # You need to allocate channels if not using recovery catalog. Media + # manager parameter string must be same as in Section 1. + ALLOCATE CHANNEL FOO TYPE SBT PARMS ''; + ALLOCATE CHANNEL FOO2 TYPE DISK; + + RESTORE CONTROLFILE FROM AUTOBACKUP; + ALTER DATABASE MOUNT; + RECOVER DATABASE; + ALTER DATABASE OPEN RESETLOGS; + + # You must take a new whole database backup after resetlogs (as + # in Section 2.1), since backups of previous incarnation are not easily + # usable. +} + + +# Section 5.4 - Block recovery +#----------------------------- +# Block recovery can be used to recover a corrupted block(s). It is not +# intended to recover complete datafile. +# Usually, the corruption is reported in alert logs, trace files or +# results of SQL commands +# +# For example, as a result of SQL command +# SQL> select * from emp; +# +#NAME +#------------------------------ +#ORA-01578: ORACLE data block corrupted (file # 7, block # 233) +#ORA-01578: ORACLE data block corrupted (file # 7, block # 235) +#ORA-01578: ORACLE data block corrupted (file # 4, block # 101) +#ORA-01110: data file 7: '/oracle/dbs/tbs_07.f' +#ORA-01110: data file 4: '/oracle/dbs/tbs_04.f' + +# Use the following BLOCKRECOVER command to recover the corrupted blocks +# listed above: +BLOCKRECOVER DATAFILE 7 BLOCK 233, 235 DATAFILE 4 BLOCK 101; + +# The BLOCKRECOVER command can also be used to repair all corrupted blocks +# listed in V$BACKUP_CORRUPTION and V$COPY_CORRUPTION. These views are +# populated whenever an RMAN process peforms a complete scan of a file for the +# purpose of backing it up, such as with the BACKUP or COPY command. Use the +# following command to repair all blocks listed in the V$xxx_CORRUPTION views: +# command: +BLOCKRECOVER CORRUPTION LIST; + +# Section 5.5 - Disaster recovery +#-------------------------------- +# A disaster recovery scenario assumes that you have lost everything. To +# perform recovery in this case, you would have to restore initialization +# parameters manually. Then use RMAN to restore and recover the database as +# described in this section. +# +# The commands below assume that all initialization parameter files are in +# place and the complete directory structure for datafiles is recreated. +# +# Ensure you set your NLS_LANG environment variable. +# e.g. in unix (csh): +# > setenv NLS_LANG american_america.we8dec +# +# Start RMAN without the TARGET option, and use the following commands to +# restore and recover the database: + +SET DBID ; # use database id from RMAN output as + # explained in Section 2.1, + # not required if using recovery catalog +CONNECT TARGET ; +STARTUP NOMOUNT; +RUN +{ + # You need to allocate channels if not using recovery catalog. Media + # manager parameter string must be same as in Section 1. + ALLOCATE CHANNEL FOO TYPE SBT PARMS ''; + ALLOCATE CHANNEL FOO2 TYPE DISK; + + # Optionally you can use SET NEWNAME and SWITCH commands as described in + # Section 5.2 to restore datafiles to a new location. + RESTORE CONTROLFILE FROM AUTOBACKUP; + ALTER DATABASE MOUNT; + RESTORE DATABASE; + RECOVER DATABASE; + ALTER DATABASE OPEN RESETLOGS; + + # You must take a new whole database backup after resetlogs (as + # in Section 2.1), since backups of previous incarnation are not easily + # usable. +} + + +# Section 5.6 - Database Point-in-time recovery +# --------------------------------------------- +# This scenario assumes that all initialization files and the current +# controlfile are in place and you want to recover to a point in time +# '2001-04-09:14:30:00'. +# +# Ensure you set your NLS_LANG environment variable. +# e.g. in unix (csh): +# > setenv NLS_LANG american_america.we8dec + +STARTUP MOUNT FORCE; +RUN +{ + SET UNTIL TIME "TO_DATE('2001-04-09:14:30:00','yyyy-dd-mm:hh24:mi:ss')"; + RESTORE DATABASE; + RECOVER DATABASE; + ALTER DATABASE OPEN RESETLOGS; + + # You must take a new whole database backup after resetlogs (as + # in Section 2.1), since backups of previous incarnation are not easily + # usable. +} + + +#-end of file- diff --git a/case3.rcv b/case3.rcv new file mode 100644 index 0000000..c9b62ae --- /dev/null +++ b/case3.rcv @@ -0,0 +1,261 @@ +# +# $Header: case3.rcv 26-apr-2001.12:18:39 banand Exp $ +# +# Copyright (c) 1995, 2001, Oracle Corporation. All rights reserved. +# +# NAME +# case3.rcv +# +# DESCRIPTION +# This case study outlines the basic steps to perform tablespace +# point-in-time recovery (TSPITR) using Recovery Manager. +# +# The examples in this case study assume that all backups are stored on +# disk. However if you have backups on tape and channels are configured as +# described in case2.rcv, Section 1, the same procedures will work. +# +# This case study assumes that +# - You want to recover tablespaces TBS1 and TBS2 to the point in time +# '2000-APR-01:07:05:30'. +# - TSPITR is performed on the same machine as the target database. +# - ORACLE_HOME is /oracle. +# - ORACLE_SID for the target database is PROD. +# - target database files and online logs are in $ORACLE_HOME/dbs/. +# - ORACLE_SID for the auxiliary instance is AUX. +# - all temporary files (except password file) for the auxiliary +# instance are created in $ORACLE_HOME/auxiliary. +# +# NOTES +# You should not run all of the commands in this file in a single RMAN +# session. Rather, the various sections in this file should be studied +# thoroughly before performing TSPITR. +# +# MODIFIED (MM/DD/YY) +# banand 04/17/01 - re-write case for tablespace point-in-time recovery +# banand 04/17/01 - Creation +# +# Organization: +# +# This case study is organized into the following sections: +# 1. TSPITR usage and restrictions +# 2. Resolving referential dependencies +# 3. Preparing for TSPITR - setup auxiliary instance +# 4. Performing TSPITR +# 5. Preparing the target database to use recovered files +# 6. Cleaning up the auxiliary instance and temporary files +# + +Section 1 - TSPITR usage and restrictions +----------------------------------------- + +Section 1.1 - When to do TSPITR +------------------------------- + TSPITR can be performed: + - to recover from an erroneous drop or truncate table operation + - to recover a table that has become logically corrupted + - to recover from a batch job or DML that has affected only a subset of the + database + +Section 1.2 - Restrictions of TSPITR +------------------------------------ + It should be noted that TSPITR: + - cannot recover a dropped tablespace + - cannot recover a tablespace that was dropped and recreated with same name + - will not recover optimizer statistics; statistics must be recalculated + after TSPITR + - cannot recover a tablespace containing any of the following object types: + - replicated master tables + - tables with varray columns + - tables with nested tables + - tables with external bfiles + - snapshot logs + - snapshot tables + - IOTs + - objects owned by SYS (including rollback segments) + + After TSPITR you should take a new backup of the recovered tablespace(s), + since it is not possible to recover using the pre-TSPITR backups. + +Section 1.3 - RMAN specific restrictions for TSPITR +--------------------------------------------------- + RMAN specific TSPITR restrictions are : + - cannot recover partitioned tables unless all partitions are contained + in the recovery set + - cannot recover tablespaces containing rollback segments + +Section 2. Resolving referential dependencies +----------------------------------------------------------------------------- + The main issue to consider when deciding whether or not to proceed with + TSPITR is the possibility of application-level inconsistencies between + tables in recovered and unrecovered tablespaces due to implicit rather than + explicit referential dependencies. You should understand these dependencies + and have means to resolve any possible inconsistencies before proceeding. + + Oracle provides the TS_PITR_CHECK view to assert that no referential + integrity constraints will be broken after TSPITR. If this view returns + rows when queried then the reason should be investigated and resolved. Only + when TS_PITR_VIEW returns no rows TSPITR will be able to proceed (since + this view is checked by imp/exp utilities called by RMAN during + TSPITR). All actions taken at this stage should be noted in order that + these relationship can be rebuilt after TSPITR is complete. + + You should check view TS_PITR_OBJECTS_TO_BE_DROPPED to see which objects + will be lost after TSPITR. If you want certain object listed by this view, + then TSPITR should not be performed. + + Run the following queries to prepare for performing TSPITR on TBS1 and TBS2 + to time '2000-APR-01:07:05:30': + + SELECT OWNER, NAME, TABLESPACE_NAME FROM SYS.TS_PITR_OBJECTS_TO_BE_DROPPED + WHERE TABLESPACE_NAME IN ('TBS1', 'TBS2') AND + CREATION_TIME > TO_DATE('2000-APR-01:07:05:30', + 'YYYY-MON-DD:HH24:MI:SS') + ORDER BY TABLESPACE_NAME, CREATION_TIME; + + SELECT * FROM SYS.TS_PITR_CHECK + WHERE (TS1_NAME IN ('TBS1', 'TBS2') AND + TS2_NAME NOT IN ('TBS1', 'TBS2')) OR + (TS1_NAME NOT IN ('TBS1', 'TBS2') AND + TS2_NAME IN ('TBS1', 'TBS2')); + +Section 3 - Preparing for TSPITR +----------------------------------------------------------------------------- + This section shows how to set up the auxiliary instance which will be used + by RMAN to perform TSPITR on the desired tablespaces. RMAN will connect + to this database using the AUXILIARY connect option. + +Section 3.1 - Setting up the auxiliary instance +----------------------------------------------- + +Section 3.1.1 - Preparing to connect to the auxiliary instance +-------------------------------------------------------------- + The following steps should be followed to connect to the auxiliary + instance: + + - create a password file for the auxiliary instance using the + orapwd utility: + + orapwd file=/oracle/dbs/orapwAUX password=auxpwd entries=100 + + - Add listener.ora and tnsnames.ora entries so that RMAN can connect to + the auxiliary database. + +Section 3.1.2 - Preparing the parameter file for the auxiliary instance +----------------------------------------------------------------------- + You can use the production instance parameter file as the basis for the + auxiliary instance. However certain parameters like db_block_buffers, + shared_pool_size, large_pool_size, enqueue_resources, etc which allocate + shared memory can probably be reduced, because the auxiliary instance + does not have the same memory requirements as the production instance. + + The following parameters must be set for the auxiliary instance: + + # db_name must be the same as in the production instance + db_name=PROD + + # control_files must be different than the production instance + control_files=/oracle/auxiliary/ctl.f + + # lock_name_space must be different than the production instance + lock_name_space=_PROD + + # db_file_name_convert and log_file_name_convert are used only in + # the parameter file of the auxiliary instance. They establish + # the rules that are used to convert the datafile and log file + # names from the production to the auxiliary database. Note that + # starting in Oracle9i, more than one pair of substitutions can + # be specified in both of these parameters, which allows more + # flexibility in converting file names. Use the RMAN SET NEWNAME + # command to convert any file names that cannot be converted with + # the xxx_file_name_convert parameters. + db_file_name_convert=('/dbs/', '/auxiliary/') + log_file_name_convert=('/dbs/', '/auxiliary/') + + # log_archive_dest_n and log_archive_format can be the same as the + # target instance + log_archive_dest_1='LOCATION=/oracle/log' + log_archive_format=r_%t_%s.arc + + It is important to note that ALL controlfiles, online logs, and datafiles + must have different names at the auxiliary instance than they have at the + production instance, otherwise RMAN may restore files to those locations, + and overwrite the production files. Use the control_files, + db_file_name_convert, and log_file_name_convert parameters to make sure + that the files at the auxiliary instance all have different names. + +Section 3.1.3 - Starting the auxiliary instance +----------------------------------------------- + You should start the auxiliary instance in nomount mode before performing + TSPITR. You can connect using SQLPLUS and start the auxiliary using the + following commands : + + CONNECT sys/syspwd@auxiliary_db_connect_string as sysdba; + STARTUP PFILE=/oracle/auxiliary/initAUX.ora NOMOUNT; + +Section 4 - Performing TSPITR using RMAN +------------------------------------------------------------------------------ + The auxiliary database must be in nomount state and the target instance + must be mounted or open state to perform TSPITR. The steps in RMAN TSPITR + are: + - connect to auxiliary instance + - connect to target database + - connect to recovery catalog (optional) + - recover tablespace TBS1 and TBS2 + + CONNECT AUXILIARY + CONNECT TARGET + CONNECT CATALOG + + RUN + { + # optionally, use SET NEWNAME here for file name translation + # SET NEWNAME FOR DATAFILE 1 TO '/oracle/auxiliary/file1.f' + # SET NEWNAME FOR DATAFILE 2 TO '/oracle/auxiliary/file2.f' + + RECOVER TABLESPACE TBS1, TBS2 UNTIL TIME + "TO_DATE('2000-APR-01:07:05:30', 'YYYY-MON-DD:HH24:MI:SS')"; + } + + All the recovered tablespaces will be OFFLINE in target database on + successful execution of RECOVER command. If the RECOVER command fails, + then after resolving the error you can re-execute the commands. + + If export fails due to lack of temporary space, you can create a temporary + tablespace. Search for tspitr_7 in /oracle/rdbms/admin/recover.bsq and + see comments to create temporary tablespace. + + If import fails because of import tables not existing, you can run + CATEXP.SQL on target database to create import schema. + +Section 5 - Preparing the target database to use the recovered tablespaces +-------------------------------------------------------------------------- + + After the RECOVER command in Section 4 runs successfully, you should backup + the recovered tablespaces, because after they are brought online, they can + no longer be recovered using backups taken prior to the TSPITR. + + CONNECT TARGET sys/syspwd@target_db_connect_string; + BACKUP TABLESPACE TBS1, TBS2; + SQL 'ALTER TABLESPACE TBS1, TBS2 ONLINE'; + +Section 6 - Cleanup auxiliary instance +-------------------------------------- + The auxiliary instance is not usable after successful completion of + TSPITR. This instance must be cleaned using following steps: + + - Connect to the auxiliary instance as explained in Section 3.1.3 + - mount the database using 'ALTER DATABASE MOUNT CLONE DATABASE' + - Delete the temporary files restored by RMAN when performing TSPITR. + You can use following queries to list them: + + SELECT d.name FROM v$datafile d, v$tablespace t + WHERE d.ts#=t.ts# AND status in ('SYSTEM', 'ONLINE') AND + t.name not in ('TBS1', 'TBS2'); + SELECT member FROM v$logfile; + SELECT name FROM v$controlfile; + + - Shutdown the auxiliary instance and delete the above files. + All these files in this case should be in the /oracle/auxiliary directory. + - You can also delete initAUX.ora and orapwAUX + +#-end of file- diff --git a/case4.rcv b/case4.rcv new file mode 100644 index 0000000..830cd88 --- /dev/null +++ b/case4.rcv @@ -0,0 +1,157 @@ +# +# $Header: case4.rcv 13-sep-2000.13:30:16 molagapp Exp $ +# +# Copyright (c) 1995, 2000 Oracle Corporation. All rights reserved. +# +# NAME +# case4.rcv +# +# DESCRIPTION +# Example of how to duplicate a database using Recovery Manager +# +# NOTES +# +# MODIFIED (MM/DD/YY) +# banand 04/23/01 - rename case5 to case4 +# molagapp 09/13/00 - fix for 8.2 +# mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +# rlu 02/18/99 - fix typo +# fsanchez 11/06/98 - Creation +# +# +# The following script creates a duplicate database that you can use +# for testing purposes. This scenario assumes: +# - You wish to duplicate the target database to a new database +# named newdb. +# - The target database is mounted or open. +# - The auxiliary instance is started in NOMOUNT state. +# - The INIT.ORA file of the duplicate database must contain: +# - DB_NAME = newdb +# - CONTROL_FILES = ... (see script) +# - The INIT.ORA file of the duplicate database can also contain: +# - DB_FILE_NAME_CONVERT = ... (see script) +# - LOG_FILE_NAME_CONVERT = ... (see script) +# - Any other parameters required by the auxiliary database. +# +# The following script creates a duplicate database using the most recent +# backup. After the DUPLICATE command has finished succesfully, +# you can register the duplicate database (if using a recovery catalog) +# and perform backups as with any other database. +# +# Make sure to set your NLS_LANG and NLS_DATE_FORMAT environment variables. +# You can set these values to whatever you wish. The UNIX example +# below keeps the date format to the standard date format used +# for recovery: +# +# %> setenv NLS_LANG AMERICAN +# %> setenv NLS_DATE_FORMAT 'YYYY-MM-DD:hh24:mi:ss' +# +# +# Connect to RMAN and run the script by executing the following at +# the O/S command line +# (a single-line command is shown here on multiple lines for the +# sake of clarity): +# rman +# TARGET +# @ +# CATALOG +# /@ +# AUXILIARY +# /@ +# @case4.rcv +# LOG case4.log +# +# For more information about the commands in this script, see the "Recovery +# Manager Command Syntax" in the Oracle8i Backup and Recovery Guide. +# For a description of the procedures for creating a duplicate database, +# see the chapter "Creating a Duplicate Database." + +RUN +{ + +# The target database can be mounted with the following command +# if not already opened or mounted: + +# STARTUP MOUNT ; + +# By default the DUPLICATE command will try to create the duplicate database +# using the most recent backup of the target database. If you wish to +# recover the duplicate database to a non-current time issue a SET UNTIL +# command to speceify the time. + +# SET UNTIL TIME '1998-10-31:14:30:00'; + +# There are several ways to convert the filenames for the duplicate +# database. For a complete account, see the chapter "Creating a +# Duplicate Database" in the Oracle8i Backup and Recovery Guide. Note +# the following guidelines: + +# (1) If the duplicate database is in the same host as the target, +# and the target datafiles cannot be transformed with +# DB_FILE_NAME_CONVERT rule from the INIT.ORA file of the +# duplicate database, then issue a SET NEWNAME command for each +# datafile that cannot be converted automatically. +# +# (2) If you are connected to a recovery catalog database and have issued +# SET AUXNAME commands for some datafiles, the DUPLICATE command +# will use the AUXNAME value. Disable the use of the AUXNAME +# with the command: SET AUXNAME FOR DATAFILE ... TO NULL; +# +# (3) When the duplicate database is in a different host from the +# target database, the same disk structure is present at the new +# host, and you want to keep the same datafile names, then use +# the NOFILENAMECHECK clause + +# SET NEWNAME FOR DATAFILE 1 TO '?/dbs/newdb_datafile1.dbf'; +# SET NEWNAME FOR DATAFILE 2 TO '?/dbs/newdb_datafile2.dbf'; +# ... +# SET NEWNAME FOR DATAFILE 10 TO '?/dbs/newdb_datafile10.dbf'; +# ... + +# You must allocate at least one auxiliary channel needs before issuing +# the DUPLICATE command. The channel type (DISK or SBT) must match +# the media where the backups of the target database are stored. If you +# allocate TYPE DISK, then the more channels that are allocated, the +# faster the duplicate process will be. For other types the number of +# channels should be limited to the actual number of devices available +# for the operation: + + ALLOCATE AUXILIARY CHANNEL ch1 TYPE DISK; +# ALLOCATE AUXILIARY CHANNEL ch2 TYPE SBT; + +# newdb is the name of the auxiliary database as specified in the +# INIT.ORA parameter DB_NAME: + + DUPLICATE TARGET DATABASE TO newdb; + +# The LOGFILE clause is needed if the online logs cannot be +# automatically generated from the target datafile names after +# applying the LOG_FILE_NAME_CONVERT parameter of the +# auxiliary database. +# for example, for two groups each with two members of 512K bytes: + +# LOGFILE +# GROUP 1 ('?/dbs/new_g1_l1.dbf', +# '?/dbs/new_g1_l2.dbf') SIZE 512K, +# GROUP 2 ('?/dbs/new_g2_l1.dbf', +# '?/dbs/new_g2_l2.dbf') SIZE 512K + +# If restoring to a host with the same structure as the target host, use the +# NOFILENAMECHECK clause: + +# NOFILENAMECHECK + +# Note that read-only datafiles are duplicated by default. If this is not +# desired, use the SKIP READONLY clause: + +# SKIP READONLY + + ; + +# release the auxiliary channel + + RELEASE CHANNEL ch1; +# RELEASE CHANNEL ch2; + +} + diff --git a/cbdem1.cob b/cbdem1.cob new file mode 100644 index 0000000..4e58885 --- /dev/null +++ b/cbdem1.cob @@ -0,0 +1,481 @@ + * + * $Header: cbdem1.cob 14-jul-99.14:30:27 mjaeger Exp $ + * + * Copyright (c) 1991, 1999, Oracle Corporation. All rights reserved. + * + * NAME + * cbdem1.cob - Cobol demo program # 1 + * MODIFIED (MM/DD/YY) + * mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + * plocke 11/14/95 - to update for v7.3 + * dchatter 07/20/95 - merge changes from branch 1.1.720.1 + * dchatter 04/14/95 - fix test to work on sun + * sjain 03/16/92 - Creation + * --------------------------------------------------------- + * CBDEM1 IS A SIMPLE EXAMPLE PROGRAM WHICH ADDS + * NEW EMPLOYEE ROWS TO THE PERSONNEL DATA BASE. CHECKING + * IS DONE TO INSURE THE INTEGRITY OF THE DATA BASE. + * THE EMPLOYEE NUMBERS ARE AUTOMATICALLY SELECTED USING + * THE CURRENT MAXIMUM EMPLOYEE NUMBER AS THE START. + * IF ANY EMPLOYEE NUMBER IS A DUPLICATE, IT IS SKIPPED. + * THE PROGRAM QUERIES THE USER FOR DATA AS FOLLOWS: + * + * Enter employee name : + * Enter employee job : + * Enter employee salary: + * Enter employee dept : + * + * TO EXIT THE PROGRAM, ENTER A CARRIAGE RETURN AT THE + * PROMPT FOR EMPLOYEE NAME. + * + * IF THE ROW IS SUCCESSFULLY INSERTED, THE FOLLOWING + * IS PRINTED: + * + * ENAME added to DNAME department as employee # NNNNN + * + * THE MAXIMUM LENGTHS OF THE 'ENAME', 'JOB', AND 'DNAME' + * COLUMNS WILL BE DETERMINED BY THE ODESCR CALL. + * + *---------------------------------------------------------- + + + IDENTIFICATION DIVISION. + PROGRAM-ID. CBDEM1. + ENVIRONMENT DIVISION. + DATA DIVISION. + WORKING-STORAGE SECTION. + 01 LDA. + 02 LDA-V2RC PIC S9(4) COMP. + 02 FILLER PIC X(10). + 02 LDA-RC PIC S9(4) COMP. + 02 FILLER PIC X(50). + 01 HDA PIC X(512). + + 01 CURSOR-1. + 02 C-V2RC PIC S9(4) COMP. + 02 C-TYPE PIC S9(4) COMP. + 02 C-ROWS PIC S9(9) COMP. + 02 C-OFFS PIC S9(4) COMP. + 02 C-FNC PIC S9(4) COMP. + 02 C-RC PIC S9(4) COMP. + 02 FILLER PIC X(50). + 01 CURSOR-2. + 02 C-V2RC PIC S9(4) COMP. + 02 C-TYPE PIC S9(4) COMP. + 02 C-ROWS PIC S9(9) COMP. + 02 C-OFFS PIC S9(4) COMP. + 02 C-FNC PIC S9(4) COMP. + 02 C-RC PIC S9(4) COMP. + 02 FILLER PIC X(50). + + 77 USER-ID PIC X(5) VALUE "SCOTT". + 77 USER-ID-L PIC S9(9) VALUE 5 COMP. + 77 PSW PIC X(5) VALUE "tiger". + 77 PSW-L PIC S9(9) VALUE 5 COMP. + 77 CONN PIC S9(9) VALUE 0 COMP. + 77 CONN-L PIC S9(9) VALUE 0 COMP. + 77 CONN-MODE PIC S9(9) VALUE 0 COMP. + + 77 SQL-SEL PIC X(38) VALUE + "SELECT DNAME FROM DEPT WHERE DEPTNO=:1". + 77 SQL-SEL-L PIC S9(9) VALUE 38 COMP. + + 77 SQL-INS PIC X(150) VALUE + "INSERT INTO EMP (EMPNO,ENAME,JOB,SAL,DEPTNO) + - " VALUES (:EMPNO,:ENAME,:JOB,:SAL,:DEPTNO)". + 77 SQL-INS-L PIC S9(9) VALUE 150 COMP. + + 77 SQL-SELMAX PIC X(33) VALUE + "SELECT NVL(MAX(EMPNO),0) FROM EMP". + 77 SQL-SELMAX-L PIC S9(9) VALUE 33 COMP. + + 77 SQL-SELEMP PIC X(26) VALUE + "SELECT ENAME,JOB FROM EMP". + 77 SQL-SELEMP-L PIC S9(9) VALUE 26 COMP. + + 77 EMPNO PIC S9(9) COMP. + 77 EMPNO-D PIC ZZZZ9. + 77 ENAME PIC X(12). + 77 JOB PIC X(12). + 77 SAL PIC X(10). + 77 DEPTNO PIC X(10). + 77 FMT PIC X(6). + 77 CBUF PIC X(10). + 77 DNAME PIC X(15). + 77 ENAME-L PIC S9(9) VALUE 12 COMP. + 77 ENAME-SIZE PIC S9(4) COMP. + 77 JOB-L PIC S9(9) VALUE 12 COMP. + 77 JOB-SIZE PIC S9(4) COMP. + 77 SAL-L PIC S9(9) VALUE 10 COMP. + 77 DEPTNO-L PIC S9(9) VALUE 10 COMP. + 77 DNAME-L PIC S9(9) VALUE 15 COMP. + 77 DNAME-SIZE PIC S9(4) COMP. + + 77 EMPNO-N PIC X(6) VALUE ":EMPNO". + 77 ENAME-N PIC X(6) VALUE ":ENAME". + 77 JOB-N PIC X(4) VALUE ":JOB". + 77 SAL-N PIC X(4) VALUE ":SAL". + 77 DEPTNO-N PIC X(7) VALUE ":DEPTNO". + + 77 EMPNO-N-L PIC S9(9) VALUE 6 COMP. + 77 ENAME-N-L PIC S9(9) VALUE 6 COMP. + 77 JOB-N-L PIC S9(9) VALUE 4 COMP. + 77 SAL-N-L PIC S9(9) VALUE 4 COMP. + 77 DEPTNO-N-L PIC S9(9) VALUE 7 COMP. + + 77 INTEGER PIC S9(9) COMP VALUE 3. + 77 ASC PIC S9(9) COMP VALUE 1. + 77 ZERO-A PIC S9(9) COMP VALUE 0. + 77 ZERO-B PIC S9(4) COMP VALUE 0. + 77 ONE PIC S9(9) COMP VALUE 1. + 77 TWO PIC S9(9) COMP VALUE 2. + 77 FOUR PIC S9(9) COMP VALUE 4. + 77 SIX PIC S9(9) COMP VALUE 6. + 77 EIGHT PIC S9(9) COMP VALUE 8. + 77 ERR-RC PIC S9(4) COMP. + 77 ERR-FNC PIC S9(4) COMP. + 77 ERR-RC-D PIC ZZZ9. + 77 ERR-FNC-D PIC ZZ9. + 77 MSGBUF PIC X(160). + 77 MSGBUF-L PIC S9(9) COMP VALUE 160. + + 77 ASK-EMP PIC X(25) VALUE + "Enter employee name: ". + 77 ASK-JOB PIC X(25) VALUE + "Enter employee job: ". + 77 ASK-SAL PIC X(25) VALUE + "Enter employee salary: ". + 77 ASK-DEPTNO PIC X(25) VALUE + "Enter employee dept: ". + + PROCEDURE DIVISION. + BEGIN. + + *---------------------------------------------------------- + * CONNECT TO ORACLE IN NON-BLOCKING MODE. + * HDA MUST BE INITIALIZED TO ALL ZEROS BEFORE CALL TO OLOG. + *---------------------------------------------------------- + + MOVE LOW-VALUES TO HDA. + + CALL "OLOG" USING LDA, HDA, USER-ID, USER-ID-L, + PSW, PSW-L, CONN, CONN-L, CONN-MODE. + + IF LDA-RC NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-STOP. + + DISPLAY "Connected to ORACLE as user ", USER-ID. + + *---------------------------------------------------------- + * OPEN THE CURSORS. + *---------------------------------------------------------- + + CALL "OOPEN" USING CURSOR-1, LDA. + IF C-RC IN CURSOR-1 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOF. + + CALL "OOPEN" USING CURSOR-2, LDA. + IF C-RC IN CURSOR-2 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOF. + + *---------------------------------------------------------- + * DISABLE AUTO-COMMIT. + * NOTE: THE DEFAULT IS OFF, SO THIS COULD BE OMITTED. + *---------------------------------------------------------- + + CALL "OCOF" USING LDA. + IF LDA-RC NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + *---------------------------------------------------------- + * RETRIEVE THE CURRENT MAXIMUM EMPLOYEE NUMBER. + *---------------------------------------------------------- + + CALL "OPARSE" USING CURSOR-1, SQL-SELMAX, SQL-SELMAX-L, + ZERO-A, TWO. + IF C-RC IN CURSOR-1 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + CALL "ODEFIN" USING CURSOR-1, ONE, EMPNO, FOUR, + INTEGER, ZERO-A, ZERO-B, FMT, ZERO-A, ZERO-A, + ZERO-B, ZERO-B. + IF C-RC IN CURSOR-1 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + CALL "OEXEC" USING CURSOR-1. + IF C-RC IN CURSOR-1 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + CALL "OFETCH" USING CURSOR-1. + IF C-RC IN CURSOR-1 NOT = 0 + IF C-RC IN CURSOR-1 NOT = 1403 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE + ELSE + MOVE 10 TO EMPNO. + + *---------------------------------------------------------- + * DETERMINE THE MAX LENGTH OF THE EMPLOYEE NAME AND + * JOB TITLE. PARSE THE SQL STATEMENT - + * IT WILL NOT BE EXECUTED. + * DESCRIBE THE TWO FIELDS SPECIFIED IN THE SQL STATEMENT. + *---------------------------------------------------------- + + CALL "OPARSE" USING CURSOR-1, SQL-SELEMP, SQL-SELEMP-L, + ZERO-A, TWO. + IF C-RC IN CURSOR-1 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + CALL "ODESCR" USING CURSOR-1, ONE, ENAME-SIZE, ZERO-B, + CBUF, ZERO-A, ZERO-A, ZERO-B, ZERO-B, ZERO-B. + IF C-RC IN CURSOR-1 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + CALL "ODESCR" USING CURSOR-1, TWO, JOB-SIZE, ZERO-B, + CBUF, ZERO-A, ZERO-A, ZERO-B, ZERO-B, ZERO-B. + IF C-RC IN CURSOR-1 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + IF ENAME-SIZE > ENAME-L + DISPLAY "ENAME too large for buffer." + GO TO EXIT-CLOSE. + IF JOB-SIZE > JOB-L + DISPLAY "JOB too large for buffer." + GO TO EXIT-CLOSE. + + *---------------------------------------------------------- + * PARSE THE INSERT AND SELECT STATEMENTS. + *---------------------------------------------------------- + + CALL "OPARSE" USING CURSOR-1, SQL-INS, SQL-INS-L, + ZERO-A, TWO. + IF C-RC IN CURSOR-1 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + CALL "OPARSE" USING CURSOR-2, SQL-SEL, SQL-SEL-L, + ZERO-A, TWO. + IF C-RC IN CURSOR-2 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + *---------------------------------------------------------- + * BIND ALL SQL SUBSTITUTION VARIABLES. + *---------------------------------------------------------- + + CALL "OBNDRV" USING CURSOR-1, EMPNO-N, EMPNO-N-L, + EMPNO, FOUR, INTEGER, ZERO-A. + IF C-RC IN CURSOR-1 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + CALL "OBNDRV" USING CURSOR-1, ENAME-N, ENAME-N-L, + ENAME, ENAME-L, ASC. + IF C-RC IN CURSOR-1 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + CALL "OBNDRV" USING CURSOR-1, JOB-N, JOB-N-L, + JOB, JOB-L, ASC. + IF C-RC IN CURSOR-1 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + CALL "OBNDRV" USING CURSOR-1, SAL-N, SAL-N-L, SAL, + SAL-L, ASC. + IF C-RC IN CURSOR-1 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + CALL "OBNDRV" USING CURSOR-1, DEPTNO-N, DEPTNO-N-L, + DEPTNO, DEPTNO-L, ASC. + IF C-RC IN CURSOR-1 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + *---------------------------------------------------------- + * BIND THE DEPTNO SUBSTITUTION VAR IN THE SELECT STATEMENT. + *---------------------------------------------------------- + + CALL "OBNDRN" USING CURSOR-2, ONE, DEPTNO, + DEPTNO-L, ASC. + IF C-RC IN CURSOR-2 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + *---------------------------------------------------------- + * DESCRIBE THE 'DNAME' COLUMN - ONLY THE LENGTH. + *---------------------------------------------------------- + + CALL "ODSC" USING CURSOR-2, ONE, DNAME-SIZE. + IF C-RC IN CURSOR-2 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + IF DNAME-SIZE > DNAME-L + DISPLAY "DNAME is to large for buffer." + GO TO EXIT-CLOSE. + + *---------------------------------------------------------- + * DEFINE THE BUFFER TO RECEIVE 'DNAME'. + *---------------------------------------------------------- + + CALL "ODEFIN" USING CURSOR-2, ONE, DNAME, + DNAME-L, ASC. + IF C-RC IN CURSOR-2 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + *---------------------------------------------------------- + * ASK THE USER FOR EMPLOYEE NAME, JOB, SAL, AND DEPTNO. + *---------------------------------------------------------- + + NEXT-EMP. + + DISPLAY ASK-EMP WITH NO ADVANCING. + ACCEPT ENAME. + IF ENAME = " " + GO TO EXIT-CLOSE. + + DISPLAY ASK-JOB WITH NO ADVANCING. + ACCEPT JOB. + + DISPLAY ASK-SAL WITH NO ADVANCING. + ACCEPT SAL. + + ASK-DPT. + DISPLAY ASK-DEPTNO WITH NO ADVANCING. + ACCEPT DEPTNO. + + *---------------------------------------------------------- + * CHECK FOR A VALID DEPARTMENT NUMBER BY EXECUTING. + * THE SELECT STATEMENT. + *---------------------------------------------------------- + + CALL "OEXEC" USING CURSOR-2. + IF C-RC IN CURSOR-2 NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + *---------------------------------------------------------- + * FETCH THE ROWS - DEPTNO IS A PRIMARY KEY SO A MAX. + * OF 1 ROW WILL BE FETCHED. + * IF THE CURSOR RETURN CODE IS 1403 THEN + * NO SUCH DEPARTMENT EXISTS. + *---------------------------------------------------------- + + MOVE SPACES TO DNAME. + + CALL "OFETCH" USING CURSOR-2. + IF C-RC IN CURSOR-2 = 0 THEN GO TO ADD-ROW. + IF C-RC IN CURSOR-2 = 1403 + DISPLAY "No such department." + GO TO ASK-DPT. + + *---------------------------------------------------------- + * INCREMENT EMPNO BY 10. + * EXECUTE THE INSERT STATEMENT. + *---------------------------------------------------------- + + ADD-ROW. + + ADD 10 TO EMPNO. + IF EMPNO > 9999 + MOVE EMPNO TO EMPNO-D + DISPLAY "Employee number " EMPNO-D " too large." + GO TO EXIT-CLOSE. + + CALL "OEXEC" USING CURSOR-1. + IF C-RC IN CURSOR-1 = 0 THEN GO TO PRINT-RESULT. + + *---------------------------------------------------------- + * IF THE RETURN CODE IS 1 (DUPLICATE VALUE IN INDEX), + * THEN GENERATE THE NEXT POSSIBLE EMPLOYEE NUMBER. + *---------------------------------------------------------- + + IF C-RC IN CURSOR-1 = 1 + ADD 10 TO EMPNO + GO TO ADD-ROW + ELSE + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + + PRINT-RESULT. + + MOVE EMPNO TO EMPNO-D. + DISPLAY ENAME " added to the " DNAME + " department as employee number " EMPNO-D. + + *---------------------------------------------------------- + * THE ROW HAS BEEN ADDED - COMMIT THIS TRANSACTION. + *---------------------------------------------------------- + + CALL "OCOM" USING LDA. + IF LDA-RC NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE. + GO TO NEXT-EMP. + + *---------------------------------------------------------- + * CLOSE CURSORS AND LOG OFF. + *---------------------------------------------------------- + + EXIT-CLOSE. + + CALL "OCLOSE" USING CURSOR-1. + IF C-RC IN CURSOR-1 NOT = 0 + PERFORM ORA-ERROR. + + CALL "OCLOSE" USING CURSOR-2. + IF C-RC IN CURSOR-2 NOT = 0 + PERFORM ORA-ERROR. + + EXIT-LOGOF. + + CALL "OLOGOF" USING LDA. + IF LDA-RC NOT = 0 + PERFORM ORA-ERROR. + + EXIT-STOP. + + DISPLAY "End of the OCIDEMO1 program." + STOP RUN. + + *---------------------------------------------------------- + * DISPLAY ORACLE ERROR NOTICE. + *---------------------------------------------------------- + + ORA-ERROR. + + IF LDA-RC NOT = 0 + DISPLAY "OLOGON error" + MOVE LDA-RC TO ERR-RC + MOVE "0" TO ERR-FNC + ELSE IF C-RC IN CURSOR-1 NOT = 0 + MOVE C-RC IN CURSOR-1 TO ERR-RC + MOVE C-FNC IN CURSOR-1 TO ERR-FNC + ELSE + MOVE C-RC IN CURSOR-2 TO ERR-RC + MOVE C-FNC IN CURSOR-2 TO ERR-FNC. + + DISPLAY "ORACLE error" WITH NO ADVANCING. + IF ERR-FNC NOT = 0 + MOVE ERR-FNC TO ERR-FNC-D + DISPLAY " processing OCI function" + ERR-FNC-D "." + ELSE + DISPLAY ".". + + MOVE " " TO MSGBUF. + CALL "OERHMS" USING LDA, ERR-RC, MSGBUF, MSGBUF-L. + DISPLAY MSGBUF. diff --git a/cbdem2.cob b/cbdem2.cob new file mode 100644 index 0000000..d99bed0 --- /dev/null +++ b/cbdem2.cob @@ -0,0 +1,446 @@ + * + * $Header: cbdem2.cob 14-jul-99.14:31:06 mjaeger Exp $ + * + * Copyright (c) 1991, 1999, Oracle Corporation. All rights reserved. + * + * NAME + * cbdem2.cob - Cobol demo program #2 + * MODIFIED (MM/DD/YY) + * mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + * plocke 11/14/95 - to update for v7.3 + * dchatter 07/20/95 - merge changes from branch 1.1.720.1 + * dchatter 04/14/95 - fix test to work on sun + * sjain 03/16/92 - Creation + * + * The program CBDEM2 accepts SQL statements from the + * user at run time and processes them. + + * If the statement was a Data Definition Language (DDL), + * Data Control Language (DCL), or Data Manipulation + * Language (DML) statement, it is parsed and executed, + * and the next statement is retrieved. (Note that + * performing the execute step for a DDL or DCL statement + * is not necessary, but it does no harm, and simplifies + * the program logic.) + + * If the statement was a query, the program describes + * the select list, and defines output variables of the + * appropriate type and size, depending on the internal + * datatype of the select-list item. + + * Then, each row of the query is fetched, and the results + * are displayed. + + * To keep the size of this example program to a + * reasonable limit for this book, the following + * restrictions are present: + + * (1) The SQL statement can contain only 25 elements (words + * and punctuation), and must be entered on a single line. + * There is no terminating ';'. + * (2) A maximum of 8 bind (input) variables is permitted. + * Additional input variables are not bound, which will + * cause an error at execute time. Input values must be + * enterable as character strings + * (numeric or alphanumeric). + * Placeholders for bind variables are :bv, + * as for OBNDRV. + * (3) A maximum of 8 select-list items per table are + * described and defined. Additional columns are + * not defined, which will cause unpredictable behavior + * at fetch time. + * (4) Not all internal datatypes are handled for queries. + * Selecting a RAW or LONG column could cause problems. + + + IDENTIFICATION DIVISION. + PROGRAM-ID. CBDEM2. + ENVIRONMENT DIVISION. + DATA DIVISION. + WORKING-STORAGE SECTION. + + * Logon, cursor, and host data areas. + 01 LDA. + 02 LDA-V2RC PIC S9(4) COMP. + 02 FILLER PIC X(10). + 02 LDA-RC PIC S9(4) COMP. + 02 FILLER PIC X(50). + 01 CDA. + 02 C-V2RC PIC S9(4) COMP. + 02 C-TYPE PIC S9(4) COMP. + 02 C-ROWS PIC S9(9) COMP. + 02 C-OFFS PIC S9(4) COMP. + 02 C-FNC PIC S9(4) COMP. + 02 C-RC PIC S9(4) COMP. + 02 FILLER PIC X(50). + 01 HDA PIC X(512). + + * Error message variables for the OERHMS routine. + 01 MSGBUF PIC X(256). + 01 MSGBUF-L PIC S9(9) VALUE 256 COMP. + 01 ERR-FNC-D PIC ZZZ. + + * Connect info. Link the program single-task, or + * modify to use a SQL*Net connect string appropriate + * to your site. + 01 USER-ID PIC X(5) VALUE "SCOTT". + 01 USER-ID-L PIC S9(9) VALUE 5 COMP. + 01 PSW PIC X(5) VALUE "TIGER". + 01 PSW-L PIC S9(9) VALUE 5 COMP. + 01 CONN PIC S9(9) VALUE 0 COMP. + 01 CONN-L PIC S9(9) VALUE 0 COMP. + 01 CONN-MODE PIC S9(9) VALUE 0 COMP. + + * Parameters for OPARSE. + 01 SQL-STMT PIC X(132). + 01 SQLL PIC S9(9) COMP. + 01 DEF-MODE PIC S9(9) VALUE 1 COMP. + 01 NO-DEF-MODE PIC S9(9) VALUE 0 COMP. + 01 V7-FLG PIC S9(9) VALUE 2 COMP. + + * Parameters for OBNDRV. + 01 BVNX. + 03 BV-NAME OCCURS 25 TIMES. + 05 BV-NAMEX OCCURS 10 TIMES PIC X. + 01 BVVX. + 03 BV-VAL OCCURS 10 TIMES PIC X(10). + 01 BV-VAL-L PIC S9(9) VALUE 10 COMP. + 01 N-BV PIC S9(9) COMP. + + * Parameters for ODESCR. Note: some are two bytes (S9(4)) + * some are four bytes (S9(9)). + 01 DBSIZEX. + 03 DBSIZE OCCURS 8 TIMES PIC S9(9) COMP. + 01 DBTYPEX. + 03 DBTYPE OCCURS 8 TIMES PIC S9(4) COMP. + 01 NAMEX. + 03 DBNAME OCCURS 8 TIMES PIC X(10). + 01 NAME-LX. + 03 NAME-L OCCURS 8 TIMES PIC S9(9) COMP. + 01 DSIZEX. + 03 DSIZE OCCURS 8 TIMES PIC S9(9) COMP. + 01 PRECX. + 03 PREC OCCURS 8 TIMES PIC S9(4) COMP. + 01 SCALEX. + 03 SCALE OCCURS 8 TIMES PIC S9(4) COMP. + 01 NULL-OKX. + 03 NULL-OK OCCURS 8 TIMES PIC S9(4) COMP. + + * Parameters for ODEFIN. + 01 OV-CHARX. + 03 OV-CHAR OCCURS 8 TIMES PIC X(10). + 01 OV-NUMX. + 03 OV-NUM OCCURS 8 TIMES + PIC S99999V99 COMP-3. + 01 INDPX. + 03 INDP OCCURS 8 TIMES PIC S9(4) COMP. + 01 N-OV PIC S9(9) COMP. + 01 N-ROWS PIC S9(9) COMP. + 01 N-ROWS-D PIC ZZZ9 DISPLAY. + 01 OV-CHAR-L PIC S9(9) VALUE 10 COMP. + 01 SEVEN PIC S9(9) VALUE 7 COMP. + 01 PACKED-DEC-L PIC S9(9) VALUE 4 COMP. + 01 PACKED-DEC-T PIC S9(9) VALUE 7 COMP. + 01 NUM-DISP PIC ZZZZZ.ZZ. + 01 FMT PIC X(6) VALUE "08.+02". + 01 FMT-L PIC S9(9) VALUE 6 COMP. + 01 FMT-NONE PIC X(6). + + * Miscellaneous parameters. + 01 ZERO-A PIC S9(9) VALUE 0 COMP. + 01 ZERO-B PIC S9(9) VALUE 0 COMP. + 01 ZERO-C PIC S9(4) VALUE 0 COMP. + 01 ONE PIC S9(9) VALUE 1 COMP. + 01 TWO PIC S9(9) VALUE 2 COMP. + 01 FOUR PIC S9(9) VALUE 4 COMP. + 01 INDX PIC S9(9) COMP. + 01 NAME-D8 PIC X(8). + 01 NAME-D10 PIC X(10). + 01 VARCHAR2-T PIC S9(9) VALUE 1 COMP. + 01 NUMBER-T PIC S9(9) VALUE 2 COMP. + 01 INTEGER-T PIC S9(9) VALUE 3 COMP. + 01 DATE-T PIC S9(9) VALUE 12 COMP. + 01 CHAR-T PIC S9(9) VALUE 96 COMP. + + + + PROCEDURE DIVISION. + BEGIN. + + * Connect to ORACLE in non-blocking mode. + * HDA must be initialized to all zeros before call to OLOG. + + MOVE LOW-VALUES TO HDA. + + CALL "OLOG" USING LDA, HDA, USER-ID, USER-ID-L, + PSW, PSW-L, CONN, CONN-L, CONN-MODE. + + * Check for error, perform error routine if required. + IF LDA-RC NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-STOP. + + DISPLAY "Logged on to ORACLE as user " USER-ID ".". + DISPLAY "Type EXIT at SQL prompt to quit." + + * Open a cursor. Only the first two parameters are + * used, the remainder (for V2 compatibility) are ignored. + CALL "OOPEN" USING CDA, LDA, USER-ID, ZERO-A, + ZERO-A, USER-ID, ZERO-A. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOFF. + + * Process each SQL statement. + STMT-LOOP. + PERFORM DO-SQL-STMT. + GO TO STMT-LOOP. + + EXIT-CLOSE. + CALL "OCLOSE" USING CDA. + EXIT-LOGOFF. + CALL "OLOGOF" USING LDA. + EXIT-STOP. + STOP RUN. + + * Perform paragraphs. + + DO-SQL-STMT. + MOVE " " TO SQL-STMT. + DISPLAY " ". + DISPLAY "SQL > " NO ADVANCING. + ACCEPT SQL-STMT. + * Get first word of statement. + UNSTRING SQL-STMT DELIMITED BY ALL " " + INTO BV-NAME(1). + IF (BV-NAME(1) = "exit" OR BV-NAME(1) = "EXIT") + GO TO EXIT-CLOSE. + MOVE 132 TO SQLL. + * Use non-deferred parse, to catch syntax errors + * right after the parse. + CALL "OPARSE" USING CDA, SQL-STMT, SQLL, + NO-DEF-MODE, V7-FLG. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO DO-SQL-STMT. + + PERFORM BIND-VARS. + DISPLAY " ". + MOVE N-BV TO ERR-FNC-D. + + DISPLAY "There were" ERR-FNC-D + " bind variables.". + + * Execute the statement. + CALL "OEXN" USING CDA, ONE, ZERO-B. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO DO-SQL-STMT. + + * Describe the SQL statement, and define output + * variables if it is a query. Limit output variables + * to eight. + PERFORM DESCRIBE-DEFINE THRU DESCRIBE-DEFINE-EXIT. + + SUBTRACT 1 FROM N-OV. + IF (N-OV > 0) + MOVE N-OV TO ERR-FNC-D + DISPLAY "There were" ERR-FNC-D + " define variables." + DISPLAY " " + PERFORM VARYING INDX FROM 1 BY 1 UNTIL INDX > N-OV + IF (DBTYPE(INDX) NOT = 2) + MOVE DBNAME(INDX) TO NAME-D10 + DISPLAY NAME-D10 NO ADVANCING + ELSE + MOVE DBNAME(INDX) TO NAME-D8 + DISPLAY NAME-D8 NO ADVANCING + END-IF + DISPLAY " " NO ADVANCING + END-PERFORM + DISPLAY " " + PERFORM VARYING INDX FROM 1 BY 1 UNTIL INDX > N-OV + DISPLAY "--------" NO ADVANCING + IF DBTYPE(INDX) NOT = 2 + DISPLAY "--" NO ADVANCING + END-IF + DISPLAY " " NO ADVANCING + END-PERFORM + DISPLAY " " + END-IF. + + * If the statement was a query, fetch the rows and + * display them. + IF (C-TYPE IN CDA = 4) + PERFORM FETCHN THRU FETCHN-EXIT + MOVE N-ROWS TO N-ROWS-D + DISPLAY " " + DISPLAY N-ROWS-D " rows returned.". + * End of DO-SQL-STMT. + + BIND-VARS. + MOVE 0 TO N-BV. + PERFORM VARYING INDX FROM 1 BY 1 UNTIL INDX > 25 + MOVE " " TO BV-NAME(INDX) + END-PERFORM. + UNSTRING SQL-STMT + DELIMITED BY "(" OR "," OR ";" OR "=" + OR ")" OR ALL " " + INTO BV-NAME(1) + BV-NAME(2) + BV-NAME(3) + BV-NAME(4) + BV-NAME(5) + BV-NAME(6) + BV-NAME(7) + BV-NAME(8) + BV-NAME(9) + BV-NAME(10) + BV-NAME(11) + BV-NAME(12) + BV-NAME(13) + BV-NAME(14) + BV-NAME(15) + BV-NAME(16) + BV-NAME(17) + BV-NAME(18) + BV-NAME(19) + BV-NAME(20) + BV-NAME(21) + BV-NAME(22) + BV-NAME(23) + BV-NAME(24) + BV-NAME(25). + + * Scan the words in the SQL statement. If the + * word begins with ':', it is a placeholder for + * a bind variable. Get a value for it (as a string) + * and bind using the OBNDRV routine, datatype 1. + MOVE 0 TO INDP(1). + + PERFORM VARYING INDX FROM 1 BY 1 UNTIL INDX > 25 + IF BV-NAMEX(INDX,1) = ':' + ADD 1 TO N-BV + MOVE 0 TO SQLL + INSPECT BV-NAME(INDX) TALLYING SQLL + FOR CHARACTERS BEFORE INITIAL ' ' + DISPLAY "Enter value for " BV-NAME(INDX) " --> " + NO ADVANCING + ACCEPT BV-VAL(N-BV) + CALL "OBNDRV" USING CDA, BV-NAME(INDX), SQLL, + BV-VAL(N-BV), BV-VAL-L, VARCHAR2-T, + ZERO-A, INDP(1), FMT-NONE, ZERO-A, ZERO-A + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-CLOSE + ELSE + DISPLAY "Bound " BV-VAL(N-BV) + END-IF + END-IF + END-PERFORM. + + DESCRIBE-DEFINE. + MOVE 0 TO N-OV. + PERFORM 9 TIMES + ADD 1 TO N-OV + IF (N-OV > 8) + GO TO DESCRIBE-DEFINE-EXIT + END-IF + MOVE 10 TO NAME-L(N-OV) + MOVE " " TO DBNAME(N-OV) + + CALL "ODESCR" USING CDA, N-OV, DBSIZE(N-OV), + DBTYPE(N-OV), + DBNAME(N-OV), NAME-L(N-OV), DSIZE(N-OV), + PREC(N-OV), SCALE(N-OV), NULL-OK(N-OV) + * Check for end of select list. + IF (C-RC IN CDA = 1007) + GO TO DESCRIBE-DEFINE-EXIT + END-IF + + * Check for error. + IF (C-RC IN CDA NOT = 0) + PERFORM ORA-ERROR + GO TO DESCRIBE-DEFINE-EXIT + END-IF + * Define an output variable for the select-list item. + * If it is a number, define a packed decimal variable, + * and create a format string for it. + + IF (DBTYPE(N-OV) = 2) + CALL "ODEFIN" USING CDA, N-OV, OV-NUM(N-OV), + PACKED-DEC-L, PACKED-DEC-T, TWO, + INDP(N-OV), FMT, FMT-L, PACKED-DEC-T, + ZERO-C, ZERO-C + ELSE + * For all other types, convert to a VARCHAR2 of length 10. + CALL "ODEFIN" USING CDA, N-OV, OV-CHAR(N-OV), + OV-CHAR-L, VARCHAR2-T, ZERO-A, INDP(N-OV), + FMT, ZERO-A, ZERO-A, ZERO-C, ZERO-C + END-IF + IF (C-RC IN CDA NOT = 0) + PERFORM ORA-ERROR + GO TO DESCRIBE-DEFINE-EXIT + END-IF + END-PERFORM. + DESCRIBE-DEFINE-EXIT. + + + FETCHN. + + MOVE 0 TO N-ROWS. + + PERFORM 10000 TIMES + + * Clear any existing values from storage buffers + MOVE SPACES TO OV-CHARX + MOVE LOW-VALUES TO OV-NUMX + + CALL "OFETCH" USING CDA + + * Check for end of fetch ("no data found") + IF C-RC IN CDA = 1403 + GO TO FETCHN-EXIT + END-IF + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO FETCHN-EXIT + END-IF + ADD 1 TO N-ROWS + PERFORM VARYING INDX FROM 1 + BY 1 UNTIL INDX > N-OV + IF (DBTYPE(INDX) = 2) + MOVE OV-NUM(INDX) TO NUM-DISP + INSPECT NUM-DISP REPLACING ALL ".00" BY " " + DISPLAY NUM-DISP NO ADVANCING + ELSE + DISPLAY OV-CHAR(INDX) NO ADVANCING + END-IF + DISPLAY " " NO ADVANCING + END-PERFORM + DISPLAY " " + END-PERFORM. + DISPLAY "LEAVING FETCHN...". + FETCHN-EXIT. + + + * Report an error. Obtain the error message + * text using the OERHMS routine. + ORA-ERROR. + IF LDA-RC IN LDA NOT = 0 + DISPLAY "OLOGON error" + MOVE 0 TO C-FNC IN CDA + MOVE LDA-RC IN LDA TO C-RC IN CDA. + DISPLAY "ORACLE error " NO ADVANCING. + IF C-FNC NOT = 0 + DISPLAY "processing OCI function" NO ADVANCING + MOVE C-FNC IN CDA TO ERR-FNC-D + DISPLAY ERR-FNC-D + ELSE + DISPLAY ":". + + MOVE " " TO MSGBUF. + CALL "OERHMS" USING LDA, C-RC IN CDA, MSGBUF,MSGBUF-L. + DISPLAY MSGBUF. + + diff --git a/cbdem3.cob b/cbdem3.cob new file mode 100644 index 0000000..4825ee9 --- /dev/null +++ b/cbdem3.cob @@ -0,0 +1,303 @@ + * + * $Header: cbdem3.cob 14-jul-99.14:31:45 mjaeger Exp $ + * + * Copyright (c) 1991, 1999, Oracle Corporation. All rights reserved. + * + * NAME + * cbdem3.cob - Cobol demo program # 3 + * MODIFIED (MM/DD/YY) + * mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + * plocke 11/14/95 - to update for v7.3 + * dchatter 07/20/95 - merge changes from branch 1.1.720.1 + * dchatter 04/14/95 - fix test to work on sun + * sjain 03/16/92 - Creation + * + * The program CBDEM3 creates a table called + * "VOICE_MAIL" that contains three fields: + * a message ID, and message length, and a LONG RAW + * column that contains a digitized voice + * message. The program fills one row of the table with a + * (simulated) message, then plays the message by + * extracting 64 kB chunks of it using the OFLNG routine, + * and sending them to a (simulated) digital-to-analog + * (DAC) converter routine. + + IDENTIFICATION DIVISION. + PROGRAM-ID. CBDEM3. + ENVIRONMENT DIVISION. + DATA DIVISION. + WORKING-STORAGE SECTION. + + 01 LDA. + 02 LDA-V2RC PIC S9(4) COMP. + 02 FILLER PIC X(10). + 02 LDA-RC PIC S9(4) COMP. + 02 FILLER PIC X(50). + 01 CDA. + 02 C-V2RC PIC S9(4) COMP. + 02 C-TYPE PIC S9(4) COMP. + 02 C-ROWS PIC S9(9) COMP. + 02 C-OFFS PIC S9(4) COMP. + 02 C-FNC PIC S9(4) COMP. + 02 C-RC PIC S9(4) COMP. + 02 FILLER PIC X(50). + 01 HDA PIC X(512). + + 01 ERRMSG PIC X(256). + 01 ERRMSG-L PIC S9(9) VALUE 256 COMP. + 01 ERR-RC PIC S9(9) COMP. + 01 ERR-FNC-D PIC ZZ9. + + 01 USER-ID PIC X(5) VALUE "SCOTT". + 01 USER-ID-L PIC S9(9) VALUE 5 COMP. + 01 PSW PIC X(5) VALUE "tiger". + 01 PSW-L PIC S9(9) VALUE 5 COMP. + 01 CONN PIC S9(9) VALUE 0 COMP. + 01 CONN-L PIC S9(9) VALUE 0 COMP. + 01 CONN-MODE PIC S9(9) VALUE 0 COMP. + + 01 SQL-STMT PIC X(132). + 01 SQLL PIC S9(9) COMP. + 01 ZERO-A PIC S9(9) VALUE 0 COMP. + 01 ZERO-B PIC S9(9) VALUE 0 COMP. + 01 FMT PIC X(6). + + * Establish a 200000 byte buffer. (On most systems, + * including the VAX, a PIC 99 reserves one byte.) + 01 MSGX. + 02 MSG OCCURS 200000 TIMES PIC 99. + 01 MSGX-L PIC S9(9) VALUE 200000 COMP. + 01 MSG-L PIC S9(9) COMP. + 01 MSG-L-D PIC ZZZZZZ. + 01 MSG-ID PIC S9(9) COMP. + 01 MSG-ID-L PIC S9(9) VALUE 4 COMP. + 01 MSG-ID-D PIC ZZZZ. + 01 LEN PIC 9(9) COMP. + 01 LEN-D PIC ZZZZ9. + 01 INDX PIC S9(9) COMP. + 01 INTEGER-T PIC S9(9) VALUE 3 COMP. + 01 DEF-MODE PIC S9(9) VALUE 1 COMP. + 01 LONG-RAW PIC S9(9) VALUE 24 COMP. + 01 ONE PIC S9(9) VALUE 1 COMP. + 01 TWO PIC S9(9) VALUE 2 COMP. + 01 THREE PIC S9(9) VALUE 3 COMP. + + 01 ANSX. + 02 ANSWER OCCURS 6 TIMES PIC X. + 01 VERSION-7 PIC S9(9) VALUE 2 COMP. + 01 INDP PIC S9(4) COMP. + 01 RCODE PIC S9(4) COMP. + 01 RLEN PIC S9(4) COMP. + 01 RETL PIC S9(9) COMP. + 01 OFF1 PIC S9(9) COMP. + + + PROCEDURE DIVISION. + BEGIN. + + * Connect to ORACLE in non-blocking mode. + * HDA must be initialized to all zeros before call to OLOG. + + MOVE LOW-VALUES TO HDA. + + CALL "OLOG" USING LDA, HDA, USER-ID, USER-ID-L, + PSW, PSW-L, CONN, CONN-L, CONN-MODE. + + IF LDA-RC NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-STOP. + + DISPLAY "Logged on to ORACLE as user ", USER-ID. + + * Open a cursor. + CALL "OOPEN" USING CDA, LDA, USER-ID, ZERO-A, + ZERO-A, USER-ID, ZERO-A. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOFF. + + * Drop the VOICE_MAIL table. + DISPLAY "OK to drop VOICE_MAIL table (Y or N)? : " + - WITH NO ADVANCING. + ACCEPT ANSX. + IF (ANSWER(1) NOT = 'y' AND ANSWER(1) NOT = 'Y') + DISPLAY "Exiting program now." + GO TO EXIT-CLOSE. + MOVE "DROP TABLE VOICE_MAIL" TO SQL-STMT. + MOVE 132 TO SQLL. + + * Call OPARSE with no deferred parse to execute the DDL + * statement immediately. + CALL "OPARSE" USING CDA, SQL-STMT, SQLL, + ZERO-A, VERSION-7. + IF C-RC IN CDA NOT = 0 + IF (C-RC IN CDA = 942) + DISPLAY "Table did not exist." + ELSE + PERFORM ORA-ERROR + GO TO EXIT-LOGOFF + END-IF + ELSE + DISPLAY "Table dropped." + END-IF + + * Create the VOICE_MAIL table anew. + MOVE "CREATE TABLE VOICE_MAIL (MSG_ID NUMBER(6), + - "MSG_LEN NUMBER(12), MSG LONG RAW)" TO SQL-STMT. + MOVE 132 TO SQLL. + + * Non-deferred parse to execute the DDL SQL statement. + DISPLAY "Table VOICE_MAIL " NO ADVANCING. + + CALL "OPARSE" USING CDA, SQL-STMT, SQLL, + ZERO-A, VERSION-7. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOFF. + DISPLAY "created.". + + * Insert some data into the table. + MOVE "INSERT INTO VOICE_MAIL VALUES (:1, :2, :3)" + TO SQL-STMT. + MOVE 132 TO SQLL. + CALL "OPARSE" USING CDA, SQL-STMT, SQLL, + ZERO-A, VERSION-7. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOFF. + + * Bind the inputs. + MOVE 0 TO INDP. + CALL "OBNDRN" USING CDA, ONE, MSG-ID, MSG-ID-L, + INTEGER-T, ZERO-A, INDP, FMT, ZERO-A, ZERO-A. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOFF. + + CALL "OBNDRN" USING CDA, TWO, MSG-L, MSG-ID-L, + INTEGER-T, ZERO-A, INDP, FMT, ZERO-A, ZERO-A. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOFF. + + CALL "OBNDRN" USING CDA, THREE, MSGX, MSGX-L, + LONG-RAW, ZERO-A, INDP, FMT, ZERO-A, ZERO-A. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOFF. + + * Set input variables, then execute the INSERT statement. + MOVE 100 TO MSG-ID. + MOVE 200000 TO MSG-L. + PERFORM VARYING INDX FROM 1 BY 1 UNTIL INDX > MSG-L + MOVE 42 TO MSG(INDX) + END-PERFORM. + CALL "OEXN" USING CDA, ONE, ZERO-B. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOFF. + + MOVE "SELECT MSG_ID, MSG_LEN, MSG FROM VOICE_MAIL + - " WHERE MSG_ID = 100" TO SQL-STMT. + + * Call OPARSE in deferred mode to select a message. + CALL "OPARSE" USING CDA, SQL-STMT, SQLL, + DEF-MODE, VERSION-7. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOFF. + * Define the output variables. + CALL "ODEFIN" USING CDA, ONE, MSG-ID, + MSG-ID-L, INTEGER-T, ZERO-A, ZERO-A, ZERO-A, + ZERO-A, ZERO-A, ZERO-A, ZERO-A. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOFF. + + CALL "ODEFIN" USING CDA, TWO, MSG-L, + MSG-ID-L, INTEGER-T, ZERO-A, ZERO-A, ZERO-A, + ZERO-A, ZERO-A, ZERO-A, ZERO-A. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOFF. + + MOVE 100 TO MSG-ID-L. + CALL "ODEFIN" USING CDA, THREE, MSGX, + MSG-ID-L, LONG-RAW, ZERO-A, INDP, ANSX, ZERO-A, ZERO-A, + RLEN, RCODE. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOFF. + + * Do the query, getting the message ID and just the first + * 100 bytes of the message. This query basically just sets + * the cursor to the right row. The message contents are + * fetched by the OFLNG routine. + + CALL "OEXFET" USING CDA, ONE, ZERO-A, ZERO-A. + IF C-RC IN CDA NOT = 0 + PERFORM ORA-ERROR + GO TO EXIT-LOGOFF. + + MOVE MSG-ID TO MSG-ID-D. + DISPLAY " ". + DISPLAY "Message " MSG-ID-D " is available.". + MOVE MSG-L TO MSG-L-D. + DISPLAY "The length is " MSG-L-D " bytes.". + + PERFORM VARYING OFF1 FROM 0 BY 65536 + UNTIL MSG-L <= 0 + IF (MSG-L < 65536) + MOVE MSG-L TO LEN + ELSE + MOVE 65536 TO LEN + END-IF + PERFORM PLAY-MSG THRU PLAY-MSG-EXIT + SUBTRACT LEN FROM MSG-L + * IF (MSG-L < 0 OR MSG-L = 0) + * GO TO END-LOOP + * END-IF + END-PERFORM. + + END-LOOP. + DISPLAY " ". + DISPLAY "End of message.". + + + EXIT-CLOSE. + CALL "OCLOSE" USING CDA. + EXIT-LOGOFF. + CALL "OLOGOF" USING LDA. + EXIT-STOP. + STOP RUN. + + + PLAY-MSG. + MOVE LEN TO LEN-D. + DISPLAY "Playing " LEN-D " bytes.". + PLAY-MSG-EXIT. + + + + * Report an error. Obtain the error message + * text using the OERHMS routine. + ORA-ERROR. + IF LDA-RC IN LDA NOT = 0 + DISPLAY "OLOGON error" + MOVE 0 TO C-FNC IN CDA + MOVE LDA-RC IN LDA TO C-RC IN CDA. + DISPLAY "ORACLE error" NO ADVANCING. + IF C-FNC NOT = 0 + DISPLAY " processing OCI function " NO ADVANCING + MOVE C-FNC IN CDA TO ERR-FNC-D + DISPLAY ERR-FNC-D + ELSE + DISPLAY ".". + + MOVE " " TO ERRMSG. + CALL "OERHMS" USING LDA, C-RC IN CDA, + ERRMSG, ERRMSG-L. + DISPLAY ERRMSG. + + + diff --git a/cdcdemo.sql b/cdcdemo.sql new file mode 100644 index 0000000..dda6c2a --- /dev/null +++ b/cdcdemo.sql @@ -0,0 +1,455 @@ +Rem +Rem $Header: cdcdemo.sql 22-may-2006.07:34:50 bpanchap Exp $ +Rem +Rem cdcdemo.sql +Rem +Rem Copyright (c) 2004, 2006, Oracle. All rights reserved. +Rem +Rem NAME +Rem cdcdemo.sql - Change Data Capture Demo +Rem +Rem DESCRIPTION +Rem This script is a demonstration of Change Data Capture (CDC) +Rem capabilities. It operates in asynchronous HotLog mode. +Rem +Rem This demo shows how CDC can be used to supplement information +Rem stored in the Human Resources (HR) sample schema without changing +Rem the tables already defined there. The HR schema tracks current +Rem salary for each employee but does not maintain a history of +Rem salary changes. This demo creates a new HR.SALARY_HISTORY table +Rem and uses CDC to populate it. HR.SALARY_HISTORY can be used to +Rem track information such as an employee's salary over time, or +Rem average amount and frequency of raises given by a particular +Rem department. +Rem +Rem This script creates a new user CDCPUB to be the CDC publisher. +Rem It uses the existing user HR as both the owner of the source +Rem table and as the CDC subscriber. +Rem +Rem NOTES +Rem This script must be run on a database that is set up for +Rem asynchronous HotLog Change Data Capture. The following should +Rem be verified before running this script: +Rem +Rem 1. Database initialization parameters are set according to the +Rem table "Initialization Parameters for Asynchronous HotLog +Rem Publishing" in the Change Data Capture chapter of the Oracle +Rem Data Warehousing Guide. +Rem +Rem 2. The database is running in archivelog mode, force logging mode +Rem and is performing at least minimal database-level supplemental +Rem logging. +Rem +Rem For more information about Change Data Capture, please refer to +Rem the Change Data Capture chapter in the Oracle Data Warehousing Guide. +Rem +Rem To run this script, do the following actions: +Rem sqlplus /nolog +Rem @cdcdemo +Rem +Rem MODIFIED (MM/DD/YY) +Rem bpanchap 05/22/06 - Adding ddl_markers to create_change_table +Rem pabingha 07/12/04 - increase subscrip window wait +Rem pabingha 03/26/04 - pabingha_cdc_demo +Rem pabingha 03/10/04 - Created +Rem + +set echo on +set pagesize 80 + +connect hr/hr + +-- +-- Create a copy of HR.EMPLOYEES so that this script can perform +-- employee DML operations without changing the original sample +-- schema data. This copy, HR.CDC_DEMO_EMPLOYEES, is the CDC source +-- table for this demo. +-- +create table cdc_demo_employees as select * from employees; + +-- +-- Create new HR.SALARY_HISTORY table. +-- +create table salary_history ( + employee_id number(6) not null, + job_id varchar2(10) not null, + department_id number(4), + old_salary number(8,2), + new_salary number(8,2), + percent_change number(4,2), + salary_action_date date +); + +-- +-- Instantiate the source table so that the underlying Oracle +-- Streams environment records the information it needs to capture +-- the source table's changes. +-- +connect / as sysdba +begin + dbms_capture_adm.prepare_table_instantiation( + table_name => 'HR.CDC_DEMO_EMPLOYEES'); +end; +/ + +-- +-- Create CDCPUB user to be the CDC publisher. +-- +connect / as sysdba +create user cdcpub identified BY cdcpub; +grant unlimited tablespace to cdcpub; +grant create session to cdcpub; +grant create table to cdcpub; +grant create sequence to cdcpub; +grant select_catalog_role to cdcpub; +grant execute_catalog_role to cdcpub; +grant connect, resource, dba to cdcpub; +execute dbms_streams_auth.grant_admin_privilege(grantee=>'CDCPUB'); + +-- +-- Connect as the CDC publisher and create the objects needed to publish +-- the changes to the HR.CDC_DEMO_EMPLOYEES source table. +-- +connect cdcpub/cdcpub + +-- +-- Create asynchronous HotLog change set CDC_DEMO_SET. +-- +begin + dbms_cdc_publish.create_change_set( + change_set_name => 'CDC_DEMO_SET', + description => 'change set for CDC demo', + change_source_name => 'HOTLOG_SOURCE', + stop_on_ddl => 'Y', + begin_date => NULL, + end_date => NULL); +end; +/ + +-- +-- Create change table CDCPUB.CDC_DEMO_EMP_CT and grant select access +-- on it to the subscriber. +-- +begin + dbms_cdc_publish.create_change_table( + owner => 'CDCPUB', + change_table_name => 'CDC_DEMO_EMP_CT', + change_set_name => 'CDC_DEMO_SET', + source_schema => 'HR', + source_table => 'CDC_DEMO_EMPLOYEES', + column_type_list => 'EMPLOYEE_ID NUMBER, FIRST_NAME VARCHAR2(20), + LAST_NAME VARCHAR2(25), EMAIL VARCHAR2(25), + PHONE_NUMBER VARCHAR2(20), HIRE_DATE DATE, + JOB_ID VARCHAR2(10), SALARY NUMBER, + COMMISSION_PCT NUMBER, MANAGER_ID NUMBER, + DEPARTMENT_ID NUMBER', + capture_values => 'BOTH', + rs_id => 'y', + row_id => 'n', + user_id => 'y', + timestamp => 'y', + object_id => 'n', + source_colmap => 'n', + target_colmap => 'y', + ddl_markers => 'n', + options_string => null); +end; +/ +grant select on cdc_demo_emp_ct to hr; + +-- +-- Enable capture for the CDC_DEMO_SET change set. +-- +begin + dbms_cdc_publish.alter_change_set( + change_set_name => 'CDC_DEMO_SET', + enable_capture => 'y'); +end; +/ + +-- +-- Connect as the CDC subscriber and create the CDC subscription that +-- will be used to populate the new HR.SALARY_HISTORY table. +-- +connect hr/hr + +-- +-- Create subscription CDC_DEMO_EMP_SUB. +-- +begin + dbms_cdc_subscribe.create_subscription( + change_set_name => 'CDC_DEMO_SET', + description => 'subscription to cdc_demo_employees', + subscription_name => 'CDC_DEMO_EMP_SUB'); +end; +/ + +-- +-- Create subscriber view HR.CDC_DEMO_EMP_SUB_VIEW to display +-- changes to the HR.CDC_DEMO_EMPLOYEES source table. +-- +begin + dbms_cdc_subscribe.subscribe( + subscription_name => 'CDC_DEMO_EMP_SUB', + source_schema => 'HR', + source_table => 'CDC_DEMO_EMPLOYEES', + column_list => 'EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, + PHONE_NUMBER, HIRE_DATE, JOB_ID, SALARY, + COMMISSION_PCT, MANAGER_ID, DEPARTMENT_ID', + subscriber_view => 'CDC_DEMO_EMP_SUB_VIEW'); +end; +/ + +-- +-- Activate subscription CDC_DEMO_EMP_SUB. +-- +begin + dbms_cdc_subscribe.activate_subscription( + subscription_name => 'CDC_DEMO_EMP_SUB'); +end; +/ + +-- +-- Create procedure HR.UPDATE_SALARY_HISTORY to populate the new +-- HR.SALARY_HISTORY table. This procedure extends the subscription +-- window of the CDC_DEMP_EMP_SUB subscription to get the most recent +-- set of source table changes. It uses the HR.CDC_DEMO_EMP_SUB_VIEW +-- subscriber view to scan the changes and insert them into the +-- HR.SALARY_HISTORY table. It then purges the subscription window to +-- indicate that it is finished with this set of changes. +-- +create or replace procedure update_salary_history is + cursor cur is + select * from ( + select 'I' opt, cscn$, rsid$, employee_id, job_id, department_id, + 0 old_salary, salary new_salary, commit_timestamp$ + from cdc_demo_emp_sub_view + where operation$ = 'I ' + union all + select 'D' opt, cscn$, rsid$, employee_id, job_id, department_id, + salary old_salary, 0 new_salary, commit_timestamp$ + from cdc_demo_emp_sub_view + where operation$ = 'D ' + union all + select 'U' opt , v1.cscn$, v1.rsid$, v1.employee_id, v1.job_id, + v1.department_id, v1.salary old_salary, v2.salary new_salaryi, + v1.commit_timestamp$ + from cdc_demo_emp_sub_view v1, cdc_demo_emp_sub_view v2 + where v1.operation$ = 'UO' and v2.operation$ = 'UN' and + v1.cscn$ = v2.cscn$ and v1.rsid$ = v2.rsid$ and + abs(v1.salary - v2.salary) > 0) + order by cscn$, rsid$; + percent number; + +begin + + -- Get the next set of changes to HR.CDC_DEMO_EMPLOYEES source table. + dbms_cdc_subscribe.extend_window( + subscription_name => 'CDC_DEMO_EMP_SUB'); + + -- Process each change. + for row in cur loop + if row.opt = 'I' then + insert into salary_history values ( + row.employee_id, row.job_id, row.department_id, 0, row.new_salary, + NULL, row.commit_timestamp$); + end if; + if row.opt = 'D' then + insert into salary_history values ( + row.employee_id, row.job_id, row.department_id, row.old_salary, 0, + NULL, row.commit_timestamp$); + end if; + if row.opt = 'U' then + percent := (row.new_salary - row.old_salary) / row.old_salary * 100; + insert into salary_history values ( + row.employee_id, row.job_id, row.department_id, row.old_salary, + row.new_salary, percent, row.commit_timestamp$); + end if; + end loop; + + -- Indicate subscriber is finished with this set of changes. + dbms_cdc_subscribe.purge_window( + subscription_name => 'CDC_DEMO_EMP_SUB'); + +end update_salary_history; +/ + +-- +-- Create procedure CDCPUB.WAIT_FOR_CHANGES to enable this demo to run +-- predictably. The asynchronous nature of CDC HotLog mode means that +-- there is a delay for source table changes to appear in the CDC +-- change table and the subscriber view. By default this procedure +-- waits up to 5 minutes for the change table and 1 additional minute +-- for the subscriber view. This can be adjusted if it is insufficient. +-- The caller must specify the name of the change table and the number +-- of rows expected to be in the change table. The caller may also +-- optionally specify a different number of seconds to wait for changes +-- to appear in the change table. +-- +connect cdcpub/cdcpub +create or replace function wait_for_changes( + change_table_name in varchar2, -- name of change table + rowcount in number, -- number of rows to wait for + maxwait_seconds in number := 300) -- maximum time to wait, in seconds +return varchar2 authid current_user as + + num_of_rows number := 0; -- number of rows in change table + slept number := 0; -- total time slept + sleep_time number := 3; -- number of seconds to sleep + return_msg varchar2(500); -- informational message + query_txt varchar2(200) := 'select count(*) from ' || change_table_name; + keep_waiting boolean := TRUE; -- whether to keep waiting + +begin + + while (keep_waiting) loop + dbms_lock.sleep(sleep_time); + slept := slept+sleep_time; + execute immediate query_txt into num_of_rows; + + -- Got expected number of rows. + if num_of_rows >= rowcount then + keep_waiting := FALSE; + return_msg := 'Change table ' || change_table_name || + ' contains at least ' || rowcount || ' rows.'; + goto DONE; + + -- Reached maximum number of seconds to wait. + elsif slept > maxwait_seconds then + return_msg := ' !!! - Timed out while waiting for ' || + change_table_name || + ' to reach ' || rowcount || ' rows !!! '; + goto DONE; + end if; + end loop; + + <> + -- additional wait time for changes to become available to subscriber view + dbms_lock.sleep(120); + + return return_msg; +end ; +/ + +-- +-- First set of DML operations on source table HR.CDC_DEMO_EMPLOYEES. +-- +connect hr/hr +update cdc_demo_employees set salary = salary + 500 where job_id = 'SH_CLERK'; +update cdc_demo_employees set salary = salary + 1000 where job_id = 'ST_CLERK'; +update cdc_demo_employees set salary = salary + 1500 where job_id = 'PU_CLERK'; +commit; + +insert into cdc_demo_employees values + (207, 'Mary', 'Lee', 'MLEE', '310.234.4590', + to_date('10-JAN-2003','DD-MON-YYYY'), 'SH_CLERK', 4000, NULL, 121, 50); +insert into cdc_demo_employees values + (208, 'Karen', 'Prince', 'KPRINCE', '345.444.6756', + to_date('10-NOV-2003','DD-MON-YYYY'), 'SH_CLERK', 3000, NULL, 111, 50); +insert into cdc_demo_employees values + (209, 'Frank', 'Gate', 'FGATE', '451.445.5678', + to_date('13-NOV-2003','DD-MON-YYYY'), 'IT_PROG', 8000, NULL, 101, 50); +insert into cdc_demo_employees values + (210, 'Paul', 'Jeep', 'PJEEP', '607.345.1112', + to_date('28-MAY-2003','DD-MON-YYYY'), 'IT_PROG', 8000, NULL, 101, 50); +commit; + +-- +-- Expecting 94 rows to appear in the change table CDCPUB.CDC_DEMO_EMP_CT. +-- This first capture may take a few minutes. Later captures should be +-- faster. +-- +connect cdcpub/cdcpub +select wait_for_changes('CDCPUB.CDC_DEMO_EMP_CT', 94, 1000) message from dual; + +-- +-- Execute subscriber routine to update HR.SALARY_HISTORY. +-- +connect hr/hr +execute update_salary_history; + +-- +-- Look at the contents of HR.SALARY_HISTORY. +-- +select employee_id, job_id, department_id, old_salary, new_salary, + percent_change +from salary_history +order by employee_id, old_salary, new_salary; + +-- +-- Second set of DML operations on source table HR.CDC_DEMO_EMPLOYEES. +-- +connect hr/hr +delete from cdc_demo_employees +where first_name = 'Mary' and last_name = 'Lee'; +delete from cdc_demo_employees +where first_name = 'Karen' and last_name = 'Prince'; +delete from cdc_demo_employees +where first_name = 'Frank' and last_name = 'Gate'; +delete from cdc_demo_employees +where first_name = 'Paul' and last_name = 'Jeep'; +commit; + +update cdc_demo_employees set salary = salary + 5000 +where job_id = 'AD_VP'; +update cdc_demo_employees set salary = salary - 1000 +where job_id = 'ST_MAN'; +update cdc_demo_employees set salary = salary - 500 +where job_id = 'FI_ACCOUNT'; +commit; + +-- +-- Expecting 122 rows to appear in the change table CDCPUB.CDC_DEMO_EMP_CT. +-- (94 rows from the first set of DMLs and 28 from the second set) +-- +connect cdcpub/cdcpub +select wait_for_changes('CDCPUB.CDC_DEMO_EMP_CT', 122, 1000) message from dual; + +-- +-- Execute subscriber routine to update HR.SALARY_HISTORY. +-- +connect hr/hr +execute update_salary_history; + +-- +-- Look at the contents of HR.SALARY_HISTORY. +-- +select employee_id, job_id, department_id, old_salary, new_salary, + percent_change +from salary_history +order by employee_id, old_salary, new_salary; + +-- +-- Clean up all objects created for this demo. +-- +connect hr/hr +begin + dbms_cdc_subscribe.drop_subscription( + subscription_name => 'CDC_DEMO_EMP_SUB'); +end; +/ + +connect cdcpub/cdcpub +begin + dbms_cdc_publish.drop_change_table( + owner => 'CDCPUB', + change_table_name => 'CDC_DEMO_EMP_CT', + force_flag => 'Y'); +end; +/ +begin + dbms_cdc_publish.drop_change_set( + change_set_name => 'CDC_DEMO_SET'); +end; +/ +drop function wait_for_changes; + +connect hr/hr +drop table salary_history purge; +drop table cdc_demo_employees; +drop procedure update_salary_history; + +connect / as sysdba +drop user cdcpub cascade; + +exit diff --git a/cdemdp9i.sql b/cdemdp9i.sql new file mode 100644 index 0000000..b3d22dd --- /dev/null +++ b/cdemdp9i.sql @@ -0,0 +1,112 @@ +Rem +Rem $Header: cdemdp9i.sql 15-aug-2006.11:46:52 jkaloger Exp $ +Rem +Rem cdemdp9i.sql +Rem +Rem+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +Rem Copyright (c) 2006, Oracle. All rights reserved. +Rem All Rights Reserved. +Rem+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +Rem +Rem +Rem NAME: +Rem +Rem Cdemdp9i.sql +Rem +Rem DESCRIPTION: +Rem +Rem Provides Oracle9i Objects for Direct Path API demo. +Rem +Rem NOTES: +Rem +Rem Objects and tables will be used by several DP API demo clients. +Rem +Rem Access the database with the oe/oe(Order Entry) user/password. +Rem +Rem The demo tables incorporate various "Sample Schema" types from the +Rem Order Entry schema scripts at $ORACLE_HOME/demo/schema. +Rem Refer to "Oracle9i Sample Schemas" documentation for schema layout and +Rem how to reinitialize the Sample Schema. +Rem +Rem This demo adds three tables to the Sample Schema. +Rem +Rem Sample Schemas can be built using the Database Configuration Assistant +Rem (DBCA). Refer to appropriate Oracle9i documentation for using DBCA. +Rem +Rem Refer to OCI Programmer Guide, Chapter 12, for complete DP API +Rem information and Appendix B for DP API demo information. +Rem +Rem Sample Schema types used for DP API demos: +Rem +Rem cust_address_type +Rem customer_typ +Rem corporate_cust_typ (derived from customer_typ) +Rem inventory_typ +Rem warehouse_typ (nested column object within inventory_typ) +Rem +Rem DP API Demo tables created for DP API demos: +Rem +Rem dp_api_demo1 +Rem dp_api_demo2 +Rem dp_api_demo3 +Rem +Rem +Rem Used by clients: +Rem +Rem Cdemdpco.c - Column object +Rem Cdemdpno.c - Nested Column object +Rem Cdemdpro.c - Reference column object +Rem Cdemdpss.c - Sql string +Rem Cdemdpin.c - Inheritance +Rem Cdemdpit.c - Table object with inheritance +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem jkaloger 08/15/06 - Lowercase passwords for secure verifiers project +Rem eegolf 04/04/01 - Merged eegolf_demo_update +Rem +Rem eegolf 04/27/01 - Creation +Rem +Rem------------------------------------------------------------------------ + +connect oe/oe + +set echo on + +drop table dp_api_demo1 force; +drop table dp_api_demo2 force; +drop table dp_api_demo3 force; + + +Rem -------------------------------------------- +Rem Create Column objects +Rem -------------------------------------------- + +Rem Place any DP API objects here + + +Rem -------------------------------------------- +Rem Create tables +Rem -------------------------------------------- + +create table dp_api_demo2 of warehouse_typ; +create table dp_api_demo3 of customer_typ +nested table cust_orders store as cust_orders2 +(nested table order_item_list store as invnt_oi_list); + +create table dp_api_demo1 +(cust_first_name varchar2(10), + cust_last_name varchar2(10), + cust_address cust_address_typ, + cust_more_info customer_typ, + current_inventory inventory_typ, + inventory_string varchar2(20), + inventory_string2 varchar2(20), + inventory_warehouse ref warehouse_typ, + inventory_stock_date varchar2(20)) +nested table cust_more_info.cust_orders store as cust_more_orders +(nested table order_item_list store as inventory_oi_list); + +exit; + + diff --git a/cdemdpco.c b/cdemdpco.c new file mode 100644 index 0000000..8c64734 --- /dev/null +++ b/cdemdpco.c @@ -0,0 +1,139 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemdpco.c 15-aug-2006.10:05:09 jkaloger Exp $ "; +#endif /* RCSID */ + +/* +** Copyright (c) 2001 Oracle Corporation. All rights reserved. +*/ + +/* +** Directions: +** 1. make -f demo_rdbms.mk build_dp EXE=cdemdpco OBJS=cdemdpco.o +** makes the cdemdpco executable +** 2. sqlplus oe/oe @cdemdp9i.sql +** creates the Oracle 9.0 types tbl +** 3. cdemdpco < cdemdpco.dat +** runs the executable +** 4. to retrieve data, select from "dp_api_demo1" as "oe/oe" +** +*/ + +/* + NAME + cdemdpco.c - An example C program that loads a column object + via Direct Path API. + + DESCRIPTION + A client module to be used with the cdemodp.c driver. + + NOTES + This module loads selected types as defined in the Sample Schema. + Refer to Cdemdp9i.sql for more information on the use of the + Sample Schema with the DP API demo modules. + + MODIFIED (MM/DD/YY) + jkaloger 08/15/06 - Lowercase passwords for secure verifiers project + cmlim 09/11/01 - fix lint + eegolf 04/04/01 - Merged eegolf_demo_update + eegolf 03/27/01 - Creation + */ + +#include +#include +#include + + +externdef struct col objx_01_col [] = +{ + { + (text *)"street_address", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + }, + { + (text *)"postal_code", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + }, + { + (text *)"city", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + }, + { + (text *)"state_province", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + }, + { + (text *)"country_id", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + } +}; + +externdef struct fld objx_01_fld [] = +{ + { 26, 65, 40, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* street_address */ + { 66, 75, 10, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* postal_code */ + { 76,105, 30, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* city */ + {106,115, 10, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* state_province */ + {116,117, 2, FLD_INLINE|FLD_STRIP_TRAIL_BLANK } /* country_id */ +}; + +externdef struct obj cust_address_typ = +{ + (text *) "CUST_ADDRESS_TYP", 5, objx_01_col, objx_01_fld, 0, 0, + (OCIDirPathFuncCtx *)0, (OCIDirPathColArray *)0, OBJ_OBJ}; + + +externdef struct col column[] = +{ + { + (text *)"cust_first_name", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"cust_last_name", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"cust_address", 0, SQLT_NTY, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, & cust_address_typ + } +}; + +/* Field descriptor which maps one-to-one with the column descriptor. + * For this simple example, fields are strictly positional within + * an input record. + */ +externdef struct fld field[] = +{ + { 1, 10, 10, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* cust_first_name */ + { 11,20, 10, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* cust_last_name */ + { 21,25, 5, FLD_INLINE|FLD_STRIP_TRAIL_BLANK } /* cust_address */ +}; + + +externdef struct tbl table = +{ + (text *)"OE", /* table owner */ + (text *)"dp_api_demo1", /* table name */ + (text *)"" , /* subname (partition, subpartition) */ + (ub2)(sizeof(column) / sizeof(struct col)), /* number of columns */ + (text *)"DD-MON-YY", /* default date format */ + (struct col *)(&column[0]), /* column descriptors */ + (struct fld *)(&field[0]), /* field descriptors */ + (ub1)0, /* parallel */ + (ub1)0, /* nolog */ + (ub4)(64 * 1024) /* transfer buffer size */ +}; + +externdef struct sess session = +{ + (text *)"oe", /* user */ + (text *)"oe", /* passwd */ + (text *)"", /* instance name */ + (text *)0, /* output file name; NULL implies stderr */ + (ub4)130 /* max input record length */ +}; + + +/* end of file cdemdpco.c */ + diff --git a/cdemdpco.dat b/cdemdpco.dat new file mode 100644 index 0000000..cfcee33 --- /dev/null +++ b/cdemdpco.dat @@ -0,0 +1,10 @@ +fredrich lawson 1 563 West Apple Orchard Road 1234567890Manchester New Hamp US +pamela smith 1 256 East Apple Orchard Road 1234567890Concord New Hamp US +james thyson 1 63 North Apple Orchard Road 1234567890Manchester New Hamp US +barbara sweeney 349 South Apple Orchard Road 1234567890Concord New Hamp US +richard jacobs 1 38 West Apple Orchard Road 1234567890Manchester New Hamp US +mary miller 1 20 East Apple Orchard Road 1234567890Concord New Hamp US +franklin ford 1 293 North Apple Orchard Road 1234567890Manchester New Hamp US +jessica patrick 1 843 South Apple Orchard Road 1234567890Concord New Hamp US +john wang 1 39 West Apple Orchard Road 1234567890Manchester New Hamp US +peter barnes 1 5 East Apple Orchard Road 1234567890Concord New Hamp US diff --git a/cdemdpin.c b/cdemdpin.c new file mode 100644 index 0000000..1f73140 --- /dev/null +++ b/cdemdpin.c @@ -0,0 +1,124 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemdpin.c 15-aug-2006.10:05:43 jkaloger Exp $ "; +#endif /* RCSID */ + +/* +** Copyright (c) 2001 Oracle Corporation. All rights reserved. +*/ + +/* +** Directions: +** 1. make -f demo_rdbms.mk build_dp EXE=cdemdpin OBJS=cdemdpin.o +** makes the cdemdpin executable +** 2. sqlplus OE/OE @cdemdp9i.sql +** creates the Oracle 9.0 types tbl +** 3. cdemdpin < cdemdpin.dat +** runs the executable +** 4. to retrieve data, select from "dp_api_demo1" as "OE/OE" +** +*/ + +/* + NAME + cdemdpin An example C program that loads a derived object type + via Direct Path API. + + DESCRIPTION + A client module to be used with the cdemodp.c driver. + + NOTES + This module loads selected types as defined in the Sample Schema. + Refer to Cdemdp9i.sql for more information on the use of the + Sample Schema with the DP API demo modules. + + MODIFIED (MM/DD/YY) + jkaloger 08/15/06 - Lowercase passwords for secure verifiers project + cmlim 09/11/01 - fix lint + eegolf 04/04/01 - Merged eegolf_demo_update + eegolf 03/29/01 - Creation + */ + +#include +#include +#include + + +externdef struct col objx_01_col [] = +{ + { + (text *)"customer_id", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + }, + { + (text *)"account_mgr_id", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + } +}; + +externdef struct fld objx_01_fld [] = +{ + { 26, 31, 6, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* customer_id */ + { 32, 37, 6, FLD_INLINE|FLD_STRIP_TRAIL_BLANK } /* account_mgr_id */ +}; + +externdef struct obj corporate_customer_typ = +{ + (text *) "CORPORATE_CUSTOMER_TYP", 2, objx_01_col, objx_01_fld, 0, 0, + (OCIDirPathFuncCtx *)0, (OCIDirPathColArray *)0, OBJ_OBJ}; + + +externdef struct col column[] = +{ + { + (text *)"cust_first_name", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"cust_last_name", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"cust_more_info", 0, SQLT_NTY, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, & corporate_customer_typ + } +}; + +/* Field descriptor which maps one-to-one with the column descriptor. + * For this simple example, fields are strictly positional within + * an input record. + */ +externdef struct fld field[] = +{ + { 1, 10, 10, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* cust_first_name */ + { 11,20, 10, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* cust_last_name */ + { 21,25, 5, FLD_INLINE|FLD_STRIP_TRAIL_BLANK } /* cust_more_info */ +}; + + +externdef struct tbl table = +{ + (text *)"OE", /* table owner */ + (text *)"dp_api_demo1", /* table name */ + (text *)"" , /* subname (partition, subpartition) */ + (ub2)(sizeof(column) / sizeof(struct col)), /* number of columns */ + (text *)"DD-MON-YY", /* default date format */ + (struct col *)(&column[0]), /* column descriptors */ + (struct fld *)(&field[0]), /* field descriptors */ + (ub1)0, /* parallel */ + (ub1)0, /* nolog */ + (ub4)(64 * 1024) /* transfer buffer size */ +}; + +externdef struct sess session = +{ + (text *)"oe", /* user */ + (text *)"oe", /* passwd */ + (text *)"", /* instance name */ + (text *)0, /* output file name; NULL implies stderr */ + (ub4)130 /* max input record length */ +}; + + +/* end of file cdemdpin .c */ + diff --git a/cdemdpin.dat b/cdemdpin.dat new file mode 100644 index 0000000..86524d5 --- /dev/null +++ b/cdemdpin.dat @@ -0,0 +1,10 @@ +fredrich lawson 1 123456123456 +pamela smith 1 121212909090 +james thyson 1 131313808080 +barbara sweeney 1 141414707070 +richard jacobs 1 151515606060 +mary miller 1 161616404040 +franklin ford 1 171717505050 +jessica patrick 181818303030 +john wang 1 191919202020 +peter barnes 1 101010101010 diff --git a/cdemdpit.c b/cdemdpit.c new file mode 100644 index 0000000..95347c2 --- /dev/null +++ b/cdemdpit.c @@ -0,0 +1,108 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemdpit.c 15-aug-2006.10:06:05 jkaloger Exp $ "; +#endif /* RCSID */ + +/* +** Copyright (c) 2001 Oracle Corporation. All rights reserved. +*/ + +/* +** Directions: +** 1. make -f demo_rdbms.mk build_dp EXE=cdemdpit OBJS=cdemdpit.o +** makes the cdemdpit executable +** 2. sqlplus OE/OE @cdemdp9i.sql +** creates the Oracle 9.0 types tbl +** 3. cdemdpit < cdemdpit.dat +** runs the executable +** 4. to retrieve data, select from "dp_api_demo3" as "OE/OE" +** +*/ + +/* + NAME + cdemdpit.c - An example C program that loads an object table, + of a non final type corporate_customer_typ, via direct path API. + In this example the OID is being loaded explicitly. + + DESCRIPTION + A client module to be used with the cdemodp.c driver. + + NOTES + This module loads selected types as defined in the Sample Schema. + Refer to Cdemdp9i.sql for more information on the use of the + Sample Schema with the DP API demo modules. + + MODIFIED (MM/DD/YY) + jkaloger 08/15/06 - Lowercase passwords for secure verifiers project + cmlim 09/11/01 - fix lint + cmlim 04/20/01 - remove TBL_SUBST_OBJ flg + eegolf 04/04/01 - Merged eegolf_demo_update + eegolf 03/29/01 - Creation + */ + +#include +#include +#include + + +externdef struct col column[] = +{ + { + (text *)"cust_oid", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0, (ub4)COL_OID + }, + { + (text *)"cust_first_name", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0, (ub4)0 + }, + { + (text *)"cust_last_name", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0, (ub4)0 + }, + { + (text *)"account_mgr_id", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0, (ub4)0 + } +}; + +/* Field descriptor which maps one-to-one with the column descriptor. + * For this simple example, fields are strictly positional within + * an input record. + */ +externdef struct fld field[] = +{ + { 1, 32, 32, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* cust_oid */ + { 33,52, 20, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* cust_first_name */ + { 53,72, 20, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* cust_last_name */ + { 73,78, 6, FLD_INLINE|FLD_STRIP_TRAIL_BLANK } /* account_mgr_id */ +}; + + +externdef struct tbl table = +{ + (text *)"OE", /* table owner */ + (text *)"dp_api_demo3", /* table name */ + (text *)"" , /* subname (partition, subpartition) */ + (ub2)(sizeof(column) / sizeof(struct col)), /* number of columns */ + (text *)"DD-MON-YY", /* default date format */ + (struct col *)(&column[0]), /* column descriptors */ + (struct fld *)(&field[0]), /* field descriptors */ + (ub1)0, /* parallel */ + (ub1)0, /* nolog */ + (ub4)(64 * 1024), /* transfer buffer size */ + (text *)"corporate_customer_typ" /* derived object type to be loaded */ +}; + +externdef struct sess session = +{ + (text *)"oe", /* user */ + (text *)"oe", /* passwd */ + (text *)"", /* instance name */ + (text *)0, /* output file name; NULL implies stderr */ + (ub4)130 /* max input record length */ +}; + + +/* end of file cdemdpit.c */ + diff --git a/cdemdpit.dat b/cdemdpit.dat new file mode 100644 index 0000000..7165693 --- /dev/null +++ b/cdemdpit.dat @@ -0,0 +1,10 @@ +78686CC3AEE95A4DE034080020A3EC15fredrick lawson 123456 +78686CC3AEE85A4DE034080020A3EC15pamela smith 101010 +78686CC3AEE75A4DE034080020A3EC15james thyson 202020 +78686CC3AEE65A4DE034080020A3EC15barbara sweeney 303030 +78686CC3AEE55A4DE034080020A3EC15richard jacobs 101010 +78686CC3AEE45A4DE034080020A3EC15mary miller 202020 +78686CC3AEE35A4DE034080020A3EC15franklin ford 303030 +78686CC3AEE25A4DE034080020A3EC15jessica patrick 101010 +78686CC3AEE15A4DE034080020A3EC15john wang 202020 +78686CC3AEE10A4DE034080020A3EC15peter barnes 303030 diff --git a/cdemdplp.c b/cdemdplp.c new file mode 100644 index 0000000..8d40027 --- /dev/null +++ b/cdemdplp.c @@ -0,0 +1,166 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemdplp.c 15-aug-2006.10:06:32 jkaloger Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 2001, 2006, Oracle. All rights reserved. */ + +/* + * -- cdemdplp.c -- + * An example program that loads data via direct path api. + * + * Directions: + * 1. make -f demo_rdbms.mk build_dp EXE=cdemdplp OBJS=cdemdplp.o + * makes the cdemdplp executable + * 2. sqlplus scott/tiger @cdemdplp.sql + * creates lineitem_dp tbl + * 3. cdemdplp < cdemdplp.dat + * runs executable + * 4. to retrieve data, select from "lineitem_dp" as "scott/tiger" + * + */ + +/* + NAME + cdemdplp.c - C Demo for Direct Path api for LineItem Partitioned + table. + + DESCRIPTION + - A client module describing lineitem partition table. + To be used with cdemodp.c driver prog. + + NOTES + Loads the lineitem1 partition of the lineitem table. + + MODIFIED (MM/DD/YY) + jkaloger 08/15/06 - Lowercase passwords for secure verifiers project + eegolf 12/01/03 - correct size 7 to 17 for l_shipinstruct + cmlim 09/11/01 - fix lint + eegolf 04/04/01 - Merged eegolf_demo_update + eegolf 03/04/01 - Updated for 9i + cmlim 09/16/98 - Creation + */ + +#include +#include +#include + +externdef struct col column[] = +{ + { + (text *)"l_orderkey", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_partkey", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_suppkey", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_linenumber", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_quantity", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_extendedprice", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_discount", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_tax", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_returnflag", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_linestatus", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_shipdate", 0, SQLT_CHR, (text *) "DD-MON-RR", + (sword)0, (sword)0, (ub2)0, (ub1)1 + }, + { + (text *)"l_commitdate", 0, SQLT_CHR, (text *) "DD-MON-RR", + (sword)0, (sword)0, (ub2)0, (ub1)1 + }, + { + (text *)"l_receiptdate", 0, SQLT_CHR, (text *) "DD-MON-RR", + (sword)0, (sword)0, (ub2)0, (ub1)1 + }, + { + (text *)"l_shipinstruct", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_shipmode", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_comment", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + } +}; + +/* Field descriptor which maps one-to-one with the column descriptor. + * For this simple example, fields are strictly positional within + * an input record. + */ +externdef struct fld field[] = +{ + { 1, 6, 6, FLD_INLINE }, /* l_orderkey */ + { 7, 11, 5, FLD_INLINE }, /* l_partkey */ + { 12, 15, 4, FLD_INLINE }, /* l_suppkey */ + { 16, 16, 1, FLD_INLINE }, /* l_linenumber */ + { 17, 18, 2, FLD_INLINE }, /* l_quantity */ + { 19, 26, 8, FLD_INLINE }, /* l_extendedprice */ + { 27, 29, 3, FLD_INLINE }, /* l_discount */ + { 30, 32, 3, FLD_INLINE }, /* l_tax */ + { 33, 33, 1, FLD_INLINE }, /* l_returnflag */ + { 34, 34, 1, FLD_INLINE }, /* l_linestatus */ + { 35, 43, 9, FLD_INLINE }, /* l_shipdate */ + { 44, 52, 9, FLD_INLINE }, /* l_commitdate */ + { 53, 61, 9, FLD_INLINE }, /* l_receiptdate */ + { 62, 78, 17, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* l_shipinstruct */ + { 79, 85, 7, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* l_shipmode */ + { 86,128, 43, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* l_comment */ +}; + +/* Note setting of subname field */ +externdef struct tbl table = +{ + (text *)"scott", /* table owner */ + (text *)"lineitem_dp", /* table name */ + (text *)"lineitem1", /* subname (partition, subpartition) */ + (ub2)(sizeof(column) / sizeof(struct col)), /* number of columns */ + (text *)"DD-MON-YY", /* default date format */ + (struct col *)(&column[0]), /* column descriptors */ + (struct fld *)(&field[0]), /* field descriptors */ + (ub1)0, /* parallel */ + (ub1)0, /* nolog */ + (ub4)(64 * 1024) /* transfer buffer size */ +}; + +externdef struct sess session = +{ + (text *)"scott", /* user */ + (text *)"tiger", /* passwd */ + (text *)"", /* instance name */ + (text *)0, /* output file name; NULL implies stderr */ + (ub4)130 /* max input record length */ +}; + + +/* end of file cdemdplp.c */ + diff --git a/cdemdplp.dat b/cdemdplp.dat new file mode 100644 index 0000000..4a65736 --- /dev/null +++ b/cdemdplp.dat @@ -0,0 +1,30 @@ + 115519 78511724386.67.04.02NO13-MAR-9612-FEB-9622-MAR-96DELIVER IN PERSONTRUCK iPBw4mMm7w7kQ zNPL i261OPP + 1 6731 73223658958.28.09.06NO12-APR-9628-FEB-9620-APR-96TAKE BACK RETURN MAIL 5wM04SNyl0AnghCP2nx lAi + 1 6370 3713 810210.96 .1.02NO29-JAN-9605-MAR-9631-JAN-96TAKE BACK RETURN REG AIRSQC2C 5PNCy4mM + 1 214 46542831197.88.09.06NO21-APR-9630-MAR-9616-MAY-96NONE AIR Om0L65CSAwSj5k6k + 1 1564 6763246897.92.07.02NO30-JAN-9607-FEB-9603-FEB-96DELIVER IN PERSONMAIL CB0SnyOL PQ32B70wB75k 6Aw10m0wh + 1 2403 160524 31329.6 .1.04NO30-MAR-9614-MAR-9601-APR-96NONE FOB C2gOQj OB6RLk1BS15 igN + 216819 82012441659.44 0.08NO05-MAR-9709-FEB-9711-MAR-97COLLECT COD AIR O52M70MRgRNnmm476mNm + 319451 721230 41113.5.05.01AF05-FEB-9429-DEC-9318-FEB-94TAKE BACK RETURN FOB 6wQnO0Llg6y + 310017 1834440788.44.07.03RF19-JAN-9423-DEC-9315-FEB-94TAKE BACK RETURN SHIP LhiA7wygz0k4g4zRhMLBAM + 3 444 1955 6 8066.64.04.01RF28-JAN-9415-DEC-9314-FEB-94TAKE BACK RETURN REG AIR6nmBmjQkgiCyzCQBkxPPOx5j4hB 0lRywgniP7 + 310617 13813858049.18 0.05AF11-DEC-9327-NOV-9316-DEC-93TAKE BACK RETURN RAIL 3AR yMS77lQ12kR + 3 4581 9043754966.46.09.05AF22-DEC-9328-DEC-9304-JAN-94DELIVER IN PERSONAIR jykM7l5S7xl6nin26jhn75C60kj2iQAgg + 319568 838635 52064.6.01.05RF23-DEC-9310-JAN-9413-JAN-94COLLECT COD RAIL nNMwmwnnji74jRnMPl0z41BgwCLjk7ANPQM + 416642 1751 4 6234.56 0.07NO10-JAN-9623-DEC-9523-JAN-96TAKE BACK RETURN SHIP jLS22n33Qw + 5 430 18114559869.35.06 0RF18-NOV-9420-OCT-9409-DEC-94NONE AIR MQR1NNRmlBx1ylCy3k7lBS0 + 5 1904 658249 88489.1 .1 0AF25-AUG-9405-OCT-9409-SEP-94TAKE BACK RETURN RAIL kAPQM67LOxSNlnimlM + 512845 37032747461.68.06.07RF01-NOV-9407-SEP-9408-NOV-94DELIVER IN PERSONSHIP CxQnkxC3xP zyiRBzj6wB30NnCi hx Q4y1OQ kg6P + 6 2938 1911 2 3681.86.01.06RF12-APR-9216-MAY-9210-MAY-92NONE TRUCK mzl027k3h7ANRiL2C + 718310 11512834392.68.04 0NO11-MAR-9607-APR-9629-MAR-96TAKE BACK RETURN FOB 7CjjL1PLCOnhgh + 7 3052 53338 36291.9.05.06NO05-FEB-9616-MAR-9629-FEB-96TAKE BACK RETURN MAIL kA2hOk7zy5PA0126AB2nwB22Amzh7kx1LSnCzikB67i + 719894 16451221766.68.05.05NO19-MAR-9628-FEB-9623-MAR-96TAKE BACK RETURN MAIL k5MQgQix5mRNgy5nk6Rk2zAQyB21AyLxw5hRBM5AO + 7 7581 582610 14885.8.01.03NO25-FEB-9625-FEB-9612-MAR-96TAKE BACK RETURN MAIL iL w 06ySPx + 717470 7387 7 9712.29.08.02NO27-MAR-9615-FEB-9608-APR-96TAKE BACK RETURN FOB Liz5AjP4g2kOP + 7 8804 579430 51384.03.08NO10-APR-9614-MAR-9618-APR-96DELIVER IN PERSONREG AIR2O0CNMzMNn5LM2A2SwnPn604 ghN641OBwCl6h5hyh6 + 7 6215 98422629151.46 .1.02NO25-JAN-9615-MAR-9631-JAN-96TAKE BACK RETURN RAIL AxnNxAyS50Sk + 32 6286 799115 17884.2.04.08NO04-SEP-9504-OCT-9510-SEP-95TAKE BACK RETURN SHIP 6nRBz7zn2gLgL3S2ligw51CQ4mn2 + 32 8280 53922327330.44.04.04NO01-OCT-9522-AUG-9504-OCT-95TAKE BACK RETURN FOB iOCwx0NQ1n44O2hg3PQ3ALQ ROy6y4N1g n6jLxh5 + 115510 78511724386.67.04.02NO13-MAR-9612-FEB-9622-MAR-96DELIVER IN PERSONTRUCK iPBw4mMm7w7kQ zNPL i261OPP + 1 6031 73223658958.28.09.06NO12-APR-9628-FEB-9620-APR-96TAKE BACK RETURN MAIL 5wM04SNyl0AnghCP2nx lAi + 11 6370 3713 810210.96 .1.02NO29-JAN-9605-MAR-9631-JAN-96TAKE BACK RETURN REG AIRSQC2C 5PNCy4mM diff --git a/cdemdplp.sql b/cdemdplp.sql new file mode 100644 index 0000000..7dbd20d --- /dev/null +++ b/cdemdplp.sql @@ -0,0 +1,83 @@ +rem +rem $Header: cdemdplp.sql 04-apr-2001.11:17:49 eegolf Exp $ +rem +rem cdemdplp.sql +rem +rem Copyright (c) 2001 Oracle Corporation. All rights reserved. +rem +rem NAME +rem cdemdplp.sql - C Demo Direct Path api for LineItem Partition table +rem +rem DESCRIPTION +rem - creates a lineitem partition tbl for loading data w/ direct path api +rem via direct path API. +rem - execute this script before running cdemodp driver +rem w/cdemdplp client. +rem NOTES +rem +rem MODIFIED (MM/DD/YY) +rem eegolf 04/04/01 - Merged eegolf_demo_update +rem eegolf 03/04/01 - updated for 9i +rem cmlim 09/16/98 - Created +rem + +set echo off; +connect scott/tiger; + +rem for direct path +drop table LINEITEM_DP; +create table LINEITEM_DP + (L_ORDERKEY NUMBER, + L_PARTKEY NUMBER, + L_SUPPKEY NUMBER, + L_LINENUMBER NUMBER, + L_QUANTITY NUMBER, + L_EXTENDEDPRICE NUMBER, + L_DISCOUNT NUMBER, + L_TAX NUMBER, + L_RETURNFLAG CHAR(1), + L_LINESTATUS CHAR(1), + L_SHIPDATE DATE, + L_COMMITDATE DATE, + L_RECEIPTDATE DATE, + L_SHIPINSTRUCT VARCHAR2(25), + L_SHIPMODE VARCHAR2(10), + L_COMMENT VARCHAR2(44)) + partition by range (L_ORDERKEY) + (partition LINEITEM1 values less than (12250) , + partition LINEITEM2 values less than (24500) , + partition LINEITEM3 values less than (36750) , + partition LINEITEM4 values less than (49000) , + partition LINEITEM5 values less than (61250) , + partition LINEITEM6 values less than (73500) , + partition LINEITEM7 values less than (maxvalue) ); + +rem for conventional path +drop table LINEITEM_CV; +create table LINEITEM_CV + (L_ORDERKEY NUMBER, + L_PARTKEY NUMBER, + L_SUPPKEY NUMBER, + L_LINENUMBER NUMBER, + L_QUANTITY NUMBER, + L_EXTENDEDPRICE NUMBER, + L_DISCOUNT NUMBER, + L_TAX NUMBER, + L_RETURNFLAG CHAR(1), + L_LINESTATUS CHAR(1), + L_SHIPDATE DATE, + L_COMMITDATE DATE, + L_RECEIPTDATE DATE, + L_SHIPINSTRUCT VARCHAR2(25), + L_SHIPMODE VARCHAR2(10), + L_COMMENT VARCHAR2(44)) + partition by range (L_ORDERKEY) + (partition LINEITEM1 values less than (12250) , + partition LINEITEM2 values less than (24500) , + partition LINEITEM3 values less than (36750) , + partition LINEITEM4 values less than (49000) , + partition LINEITEM5 values less than (61250) , + partition LINEITEM6 values less than (73500) , + partition LINEITEM7 values less than (maxvalue) ); + +exit; diff --git a/cdemdpno.c b/cdemdpno.c new file mode 100644 index 0000000..f4d2a2e --- /dev/null +++ b/cdemdpno.c @@ -0,0 +1,157 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemdpno.c 15-aug-2006.10:06:59 jkaloger Exp $ "; +#endif /* RCSID */ + +/* +** Copyright (c) 2001 Oracle Corporation. All rights reserved. +*/ + +/* +** Directions: +** 1. make -f demo_rdbms.mk build_dp EXE=cdemdpno OBJS=cdemdpno.o +** makes the cdemdpno executable +** 2. sqlplus OE/OE @cdemdp9i.sql +** creates the Oracle 9.0 types tbl +** 3. cdemdpno < cdemdpno.dat +** runs the executable +** 4. to retrieve data, select from "dp_api_demo1" as "OE/OE" +** +*/ + +/* + NAME + cdemdpno.c - An example C program that loads a nested column + object via Direct Path API. + + DESCRIPTION + A client module to be used with the cdemodp.c driver. + + NOTES + This module loads selected types as defined in the Sample Schema. + Refer to Cdemdp9i.sql for more information on the use of the + Sample Schema with the DP API demo modules. + + MODIFIED (MM/DD/YY) + jkaloger 08/15/06 - Lowercase passwords for secure verifiers project + cmlim 09/11/01 - fix lint + eegolf 04/04/01 - Merged eegolf_demo_update + eegolf 03/27/01 - Creation + */ + +#include +#include +#include + +externdef struct col objx_02_col [] = +{ + { + (text *)"warehouse_id", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + }, + { + (text *)"warehouse_name", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + }, + { + (text *)"location_id", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + } +}; + +externdef struct fld objx_02_fld [] = +{ + { 45, 47, 3, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* warehouse_id */ + { 48, 82, 35, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* warehouse_name */ + { 83, 86, 4, FLD_INLINE|FLD_STRIP_TRAIL_BLANK } /* location_id */ +}; + +externdef struct obj warehouse_typ = +{ + (text *) "WAREHOUSE_TYP", 3, objx_02_col, objx_02_fld, 0, 0, + (OCIDirPathFuncCtx *)0, (OCIDirPathColArray *)0, OBJ_OBJ}; + + +externdef struct col objx_01_col [] = +{ + { + (text *)"product_id", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + }, + { + (text *)"warehouse", 0, SQLT_NTY, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, &warehouse_typ + }, + { + (text *)"quantity_on_hand", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + } +}; + +externdef struct fld objx_01_fld [] = +{ + { 26, 31, 6, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* product_id */ + { 32, 36, 5, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* warehouse */ + { 37, 44, 8, FLD_INLINE|FLD_STRIP_TRAIL_BLANK } /* quantiti_on_hand */ +}; + +externdef struct obj inventory_typ = +{ + (text *) "INVENTORY_TYP", 3, objx_01_col, objx_01_fld, 0, 0, + (OCIDirPathFuncCtx *)0, (OCIDirPathColArray *)0, OBJ_OBJ}; + + +externdef struct col column[] = +{ + { + (text *)"cust_first_name", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"cust_last_name", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"current_inventory", 0, SQLT_NTY, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, & inventory_typ + } +}; + +/* Field descriptor which maps one-to-one with the column descriptor. + * For this simple example, fields are strictly positional within + * an input record. + */ +externdef struct fld field[] = +{ + { 1, 10, 10, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* cust_first_name */ + { 11,20, 10, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* cust_last_name */ + { 21,25, 5, FLD_INLINE|FLD_STRIP_TRAIL_BLANK } /* current_inventory */ +}; + + +externdef struct tbl table = +{ + (text *)"OE", /* table owner */ + (text *)"dp_api_demo1", /* table name */ + (text *)"" , /* subname (partition, subpartition) */ + (ub2)(sizeof(column) / sizeof(struct col)), /* number of columns */ + (text *)"DD-MON-YY", /* default date format */ + (struct col *)(&column[0]), /* column descriptors */ + (struct fld *)(&field[0]), /* field descriptors */ + (ub1)0, /* parallel */ + (ub1)0, /* nolog */ + (ub4)(64 * 1024) /* transfer buffer size */ +}; + +externdef struct sess session = +{ + (text *)"oe", /* user */ + (text *)"oe", /* passwd */ + (text *)"", /* instance name */ + (text *)0, /* output file name; NULL implies stderr */ + (ub4)130 /* max input record length */ +}; + + +/* end of file cdemdpno.c */ + diff --git a/cdemdpno.dat b/cdemdpno.dat new file mode 100644 index 0000000..ffc18e8 --- /dev/null +++ b/cdemdpno.dat @@ -0,0 +1,10 @@ +fredrich lawson 1 666666 188888888123Plainfield road parts and pieces 4444 +pamela smith 1 555555 177777777222Plainfield road parts and pieces 4444 +james thyson 1 777777 166666666333Plainfield road parts and pieces 4444 +barbara sweeney 1 888888 155555555444Plainfield road parts and pieces 4444 +richard jacobs 1 999999 144444444555Plainfield road parts and pieces 4444 +mary miller 1 222222 122222222666Plainfield road parts and pieces 4444 +franklin ford 333333 199999999777Plainfield road parts and pieces 4444 +jessica patrick 1 444444 188888888111Plainfield road parts and pieces 4444 +john wang 1 555555 77777777333Plainfield road parts and pieces 4444 +peter barnes 1 666666 122222222333Plainfield road parts and pieces 4444 diff --git a/cdemdpro.c b/cdemdpro.c new file mode 100644 index 0000000..88b2385 --- /dev/null +++ b/cdemdpro.c @@ -0,0 +1,132 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemdpro.c 15-aug-2006.10:07:25 jkaloger Exp $ "; +#endif /* RCSID */ + +/* +** Copyright (c) 2001 Oracle Corporation. All rights reserved. +*/ + +/* +** Directions: +** 1. make -f demo_rdbms.mk build_dp EXE=cdemdpro OBJS=cdemdpro +** makes the cdemdpro executable +** 2. sqlplus OE/OE @cdemdp9i.sql +** creates the Oracle 9.0 types tbl +** 2a. sqlldr OE/OE cdemdpro.ctl +** loads the dp_api_demo2 table. +** 3. cdemdpro < cdemdpro.dat +** runs the executable +** 4. to retrieve data, select from "dp_api_demo1" as "OE/OE" +** +*/ + +/* + NAME + cdemdpro.c - An example C program that loads a reference object + via Direct Path API. Table name is in .dat file. + The refs point to objects in the dp_api_demo2 table. + + DESCRIPTION + A client module to be used with the cdemodp.c driver. + + NOTES + This module loads selected types as defined in the Sample Schema. + Refer to Cdemdp9i.sql for more information on the use of the + Sample Schema with the DP API demo modules. + + IMPORTANT + This module requires running cdemdpro.ctl in sql*loader to load + warehouse_typ table. + + MODIFIED (MM/DD/YY) + jkaloger 08/15/06 - Lowercase passwords for secure verifiers project + cmlim 09/11/01 - fix lint + eegolf 04/04/01 - Merged eegolf_demo_update + eegolf 04/03/01 - + eegolf 03/28/01 - Creation + */ + +#include +#include +#include + + +externdef struct col objx_01_col [] = +{ + { + (text *)"ref_tbl", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + }, + { + (text *)"sys_oid", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + } +}; + +externdef struct fld objx_01_fld [] = +{ + { 26, 40, 15, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* ref_tbl */ + { 41, 72, 32, FLD_INLINE|FLD_STRIP_TRAIL_BLANK } /* sys_oid */ +}; + +externdef struct obj warehouse_typ = +{ + (text *)0, 2, objx_01_col, objx_01_fld, 0, 0, + (OCIDirPathFuncCtx *)0, (OCIDirPathColArray *)0, OBJ_REF}; + + +externdef struct col column[] = +{ + { + (text *)"cust_first_name", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"cust_last_name", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"inventory_warehouse", 0, SQLT_REF, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, & warehouse_typ + } +}; + +/* Field descriptor which maps one-to-one with the column descriptor. + * For this simple example, fields are strictly positional within + * an input record. + */ +externdef struct fld field[] = +{ + { 1, 10, 10, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* cust_first_name */ + { 11,20, 10, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* cust_last_name */ + { 21,25, 5, FLD_INLINE|FLD_STRIP_TRAIL_BLANK } /* inventory_warehouse */ +}; + + +externdef struct tbl table = +{ + (text *)"OE", /* table owner */ + (text *)"dp_api_demo1", /* table name */ + (text *)"" , /* subname (partition, subpartition) */ + (ub2)(sizeof(column) / sizeof(struct col)), /* number of columns */ + (text *)"DD-MON-YY", /* default date format */ + (struct col *)(&column[0]), /* column descriptors */ + (struct fld *)(&field[0]), /* field descriptors */ + (ub1)0, /* parallel */ + (ub1)0, /* nolog */ + (ub4)(64 * 1024) /* transfer buffer size */ +}; + +externdef struct sess session = +{ + (text *)"oe", /* user */ + (text *)"oe", /* passwd */ + (text *)"", /* instance name */ + (text *)0, /* output file name; NULL implies stderr */ + (ub4)130 /* max input record length */ +}; + + +/* end of file cdemdpro.c */ + diff --git a/cdemdpro.ctl b/cdemdpro.ctl new file mode 100644 index 0000000..5cb7f64 --- /dev/null +++ b/cdemdpro.ctl @@ -0,0 +1,21 @@ +-- Load the dp_api_demo2 table specifying OIDs. + + +load data +infile * + +into table dp_api_demo2 +replace +oid (name_oid) +( +name_oid FILLER position(1:32), +warehouse_id position(33:35), +warehouse_name position(36:70), +location_id position(71:74) +) + + +BEGINDATA +78686CC3AEE15A4DE034080020A3EC15123plainville warehouse parts_one 1234 +78686CC3AEE25A4DE034080020A3EC15222plainville warehouse parts_two 1212 +78686CC3AEE35A4DE034080020A3EC15333plainville warehouse pieces_one 2323 diff --git a/cdemdpro.dat b/cdemdpro.dat new file mode 100644 index 0000000..30fa74b --- /dev/null +++ b/cdemdpro.dat @@ -0,0 +1,10 @@ +fredrich lawson 1 dp_api_demo2 78686CC3AEE15A4DE034080020A3EC15 +pamela smith 1 dp_api_demo2 78686CC3AEE25A4DE034080020A3EC15 +james thyson 1 dp_api_demo2 78686CC3AEE35A4DE034080020A3EC15 +barbara sweeney 1 dp_api_demo2 78686CC3AEE15A4DE034080020A3EC15 +richard jacobs dp_api_demo2 78686CC3AEE25A4DE034080020A3EC15 +mary miller 1 dp_api_demo2 78686CC3AEE35A4DE034080020A3EC15 +franklin ford 1 dp_api_demo2 78686CC3AEE15A4DE034080020A3EC15 +jessica patrick 1 dp_api_demo2 78686CC3AEE25A4DE034080020A3EC15 +john wang 1 dp_api_demo2 78686CC3AEE35A4DE034080020A3EC15 +peter barnes 1 dp_api_demo2 78686CC3AEE35A4DE034080020A3EC15 diff --git a/cdemdpss.c b/cdemdpss.c new file mode 100644 index 0000000..b8ecad1 --- /dev/null +++ b/cdemdpss.c @@ -0,0 +1,172 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemdpss.c 15-aug-2006.10:07:47 jkaloger Exp $ "; +#endif /* RCSID */ + +/* +** Copyright (c) 2001 Oracle Corporation. All rights reserved. +*/ + +/* +** Directions: +** 1. make -f demo_rdbms.mk build_dp EXE=cdemdpss OBJS=cdemdpss.o +** makes the cdemdpss executable +** 2. sqlplus OE/OE @cdemdp9i.sql +** creates the Oracle 9.0 types tbl +** 3. cdemdpss < cdemdpss.dat +** runs the executable +** 4. to retrieve data, select from "dp_api_demo1" as "OE/OE" +** +*/ + +/* + NAME + cdemdpss.c - An example C program that loads a sql string + via Direct Path API. + + DESCRIPTION + A client module to be used with the cdemodp.c driver. + + NOTES + This module loads selected types as defined in the Sample Schema. + Refer to Cdemdp9i.sql for more information on the use of the + Sample Schema with the DP API demo modules. + + IMPORTANT + Argument names to opaques and sql strings must be unique. + + + MODIFIED (MM/DD/YY) + jkaloger 08/15/06 - Lowercase passwords for secure verifiers project + cmlim 09/11/01 - fix lint + eegolf 04/04/01 - Merged eegolf_demo_update + eegolf 03/28/01 - Creation + */ + +#include +#include +#include + + +externdef struct obj inventory_stock_date = +{ + (text *) "sysdate", 0, 0, 0, 0, 0, + (OCIDirPathFuncCtx *)0, (OCIDirPathColArray *)0, OBJ_OPQ}; + + + +externdef struct col objx_02_col [] = +{ + { + (text *)"name_str2_arg1", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + } +}; + +externdef struct fld objx_02_fld [] = +{ + { 66, 67, 2, FLD_INLINE|FLD_STRIP_TRAIL_BLANK } /* name_str2, arg1 */ +}; + + + +externdef struct obj name_str2 = +{ + (text *) "lower(add_months(sysdate, :name_str2_arg1))", 1, objx_02_col, + objx_02_fld, 0, 0, (OCIDirPathFuncCtx *)0, (OCIDirPathColArray *)0, OBJ_OPQ}; + + +externdef struct col objx_01_col [] = +{ + { + (text *)"name_str_arg1", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + }, + { + (text *)"name_str_arg2", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + }, + { + (text *)"name_str_arg3", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, (struct obj *) 0 + } +}; + +externdef struct fld objx_01_fld [] = +{ + { 36, 55,20, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* name_str, arg1 */ + { 56, 60, 5, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* name_str, arg2 */ + { 61, 65, 5, FLD_INLINE|FLD_STRIP_TRAIL_BLANK } /* name_str, arg3 */ +}; + +externdef struct obj name_str = +{ + (text *) "substr(:name_str_arg1, :name_str_arg2, :name_str_arg3)", 3, + objx_01_col, objx_01_fld, 0, 0, + (OCIDirPathFuncCtx *)0, (OCIDirPathColArray *)0, OBJ_OPQ}; + + +externdef struct col column[] = +{ + { + (text *)"cust_first_name", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"cust_last_name", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"inventory_string", 0, SQLT_NTY, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, & name_str + }, + { + (text *)"inventory_string2", 0, SQLT_NTY, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, & name_str2 + }, + { + (text *)"inventory_stock_date", 0, SQLT_NTY, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0, & inventory_stock_date + } +}; + +/* Field descriptor which maps one-to-one with the column descriptor. + * For this simple example, fields are strictly positional within + * an input record. + */ +externdef struct fld field[] = +{ + { 1, 10, 10, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* cust_first_name */ + { 11,20, 10, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* cust_last_name */ + { 21,25, 5, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* inventory_string */ + { 26,30, 5, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* inventory_string2 */ + { 31,35, 5, FLD_INLINE|FLD_STRIP_TRAIL_BLANK } /* inventory_stock_date */ +}; + + +externdef struct tbl table = +{ + (text *)"OE", /* table owner */ + (text *)"dp_api_demo1", /* table name */ + (text *)"" , /* subname (partition, subpartition) */ + (ub2)(sizeof(column) / sizeof(struct col)), /* number of columns */ + (text *)"DD-MON-YY", /* default date format */ + (struct col *)(&column[0]), /* column descriptors */ + (struct fld *)(&field[0]), /* field descriptors */ + (ub1)0, /* parallel */ + (ub1)0, /* nolog */ + (ub4)(64 * 1024) /* transfer buffer size */ +}; + +externdef struct sess session = +{ + (text *)"oe", /* user */ + (text *)"oe", /* passwd */ + (text *)"", /* instance name */ + (text *)0, /* output file name; NULL implies stderr */ + (ub4)130 /* max input record length */ +}; + + +/* end of file cdemdpss.c */ + diff --git a/cdemdpss.dat b/cdemdpss.dat new file mode 100644 index 0000000..706be5b --- /dev/null +++ b/cdemdpss.dat @@ -0,0 +1,10 @@ +fredrich lawson 1 1 1 this is a demo 1 4 1 +pamela smith 1 1 1 this is a demo 1 7 2 +james thyson 1 1 this is a demo 1 9 3 +barbara sweeney 1 1 this is a demo 1 14 1 +richard jacobs 1 1 this is a demo 1 14 2 +mary miller 1 1 1 this is a demo 1 9 3 +franklin ford 1 1 1 this is a demo 1 7 1 +jessica patrick 1 1 1 this is a demo 1 4 2 +john wang 1 1 1 this is a demo 1 4 3 +peter barnes 1 1 1 this is a demo 1 7 1 diff --git a/cdemo1.c b/cdemo1.c new file mode 100644 index 0000000..ddd7959 --- /dev/null +++ b/cdemo1.c @@ -0,0 +1,415 @@ +/* Copyright (c) 1991, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + cdemo1.c - C Demo Program + MODIFIED (MM/DD/YY) + azhao 10/11/06 - case-senstive password change + kmohan 03/28/06 - change hda to size_t + emendez 09/13/00 - fix top 5 olint errors + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/22/97 - Fix VMS porting exceptions + dchatter 01/05/96 - Creation of the Solaris version with hda as + ub4 array of HDA_SIZE/sizeof(ub4) for alignment + reasons. +*/ +/* + * -- cdemo1.c -- + * An example program which adds new employee + * records to the personnel data base. Checking + * is done to insure the integrity of the data base. + * The employee numbers are automatically selected using + * the current maximum employee number as the start. + * + * The program queries the user for data as follows: + * + * Enter employee name: + * Enter employee job: + * Enter employee salary: + * Enter employee dept: + * + * The program terminates if return key (CR) is entered + * when the employee name is requested. + * + * If the record is successfully inserted, the following + * is printed: + * + * "ename" added to department "dname" as employee # "empno" + * + * The size of the HDA is defined by the HDA_SIZE constant, + * which is declared in ocidem.h to be 256 bytes for 32- + * bit architectures and 512 bytes for 64-bit architectures. + */ + +#include +#include +#include +#include + + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + + +text *username = (text *) "SCOTT"; +text *password = (text *) "tiger"; + +/* Define SQL statements to be used in program. */ +text *insert = (text *) "INSERT INTO emp(empno, ename, job, sal, deptno)\ + VALUES (:empno, :ename, :job, :sal, :deptno)"; +text *seldept = (text *) "SELECT dname FROM dept WHERE deptno = :1"; +text *maxemp = (text *) "SELECT NVL(MAX(empno), 0) FROM emp"; +text *selemp = (text *) "SELECT ename, job FROM emp"; + +/* Define an LDA, a HDA, and two cursors. */ +Lda_Def lda; +size_t hda[HDA_SIZE/sizeof(size_t)]; +Cda_Def cda1; +Cda_Def cda2; + + +void err_report(); +void do_exit(); +void myfflush(); + + + +main() +{ + sb4 empno, sal, deptno; + sb4 len, len2, rv, dsize, dsize2; + sb4 enamelen, joblen, deptlen; + sb2 sal_ind, job_ind; + sb2 db_type, db2_type; + sb1 name_buf[20], name2_buf[20]; + text *cp, *ename, *job, *dept; + +/* + * Connect to ORACLE and open two cursors. + * Exit on any error. + */ + if (olog(&lda, (ub1 *)hda, username, -1, password, -1, + (text *) 0, -1, (ub4)OCI_LM_DEF)) + { + err_report(&lda); + exit(EXIT_FAILURE); + } + printf("Connected to ORACLE as %s\n", username); + + if (oopen(&cda1, &lda, (text *) 0, -1, -1, (text *) 0, -1)) + { + err_report(&cda1); + do_exit(EXIT_FAILURE); + } + if (oopen(&cda2, &lda, (text *) 0, -1, -1, (text *) 0, -1)) + { + err_report(&cda2); + do_exit(EXIT_FAILURE); + } + + /* Turn off auto-commit. Default is off, however. */ + if (ocof(&lda)) + { + err_report(&lda); + do_exit(EXIT_FAILURE); + } + + /* Retrieve the current maximum employee number. */ + if (oparse(&cda1, maxemp, (sb4) -1, DEFER_PARSE, + (ub4) VERSION_7)) + { + err_report(&cda1); + do_exit(EXIT_FAILURE); + } + if (odefin(&cda1, 1, (ub1 *) &empno, (sword) sizeof(sword), + (sword) INT_TYPE, + (sword) -1, (sb2 *) 0, (text *) 0, -1, -1, + (ub2 *) 0, (ub2 *) 0)) + { + err_report(&cda1); + do_exit(EXIT_FAILURE); + } + if (oexfet(&cda1, (ub4) 1, FALSE, FALSE)) + { + if (cda1.rc == NO_DATA_FOUND) + empno = 10; + else + { + err_report(&cda1); + do_exit(EXIT_FAILURE); + } + } + + /* Describe the columns in the select-list + of "selemp" to determine the max length of + the employee name and job title. + */ + if (oparse(&cda1, selemp, (sb4) -1, FALSE, (ub4)VERSION_7)) + { + err_report(&cda1); + do_exit(EXIT_FAILURE); + } + + len = sizeof(name_buf); len2 = sizeof (name2_buf); + if (odescr(&cda1, 1, &enamelen, + (sb2 *) &db_type, name_buf, (sb4 *) &len, + (sb4 *) &dsize, (sb2 *) 0, (sb2 *) 0, (sb2 *) 0) || + odescr(&cda1, 2, &joblen, + (sb2 *) &db_type, name2_buf, (sb4 *) &len2, + (sb4 *) &dsize2, (sb2 *) 0, (sb2 *) 0, (sb2 *) 0)) + { + err_report(&cda1); + do_exit(EXIT_FAILURE); + } + + /* Parse the INSERT statement. */ + if (oparse(&cda1, insert, (sb4) -1, FALSE, (ub4) VERSION_7)) + { + err_report(&cda1); + do_exit(EXIT_FAILURE); + } + + /* Parse the SELDEPT statement. */ + if (oparse(&cda2, seldept, (sb4) -1, FALSE, (ub4) VERSION_7)) + { + err_report(&cda2); + do_exit(EXIT_FAILURE); + } + + /* Allocate output buffers. Allow for \n and '\0'. */ + ename = (text *) malloc((int) enamelen + 2); + job = (text *) malloc((int) joblen + 2); + + /* Bind the placeholders in the INSERT statement. */ + if (obndrv(&cda1, (text *) ":ENAME", -1, (ub1 *) ename, + enamelen+1, STRING_TYPE, -1, (sb2 *) 0, + (text *) 0, -1, -1) || + obndrv(&cda1, (text *) ":JOB", -1, (ub1 *) job, joblen+1, + STRING_TYPE, -1, &job_ind, (text *) 0, -1, -1) || + obndrv(&cda1, (text *) ":SAL", -1, (ub1 *) &sal, (sword) sizeof (sal), + INT_TYPE, -1, &sal_ind, (text *) 0, -1, -1) || + obndrv(&cda1, (text *) ":DEPTNO",-1, (ub1 *) &deptno, + (sword) sizeof (deptno), INT_TYPE, -1, + (sb2 *) 0, (text *) 0, -1, -1) || + obndrv(&cda1, (text *) ":EMPNO", -1, (ub1 *) &empno, + (sword) sizeof (empno), INT_TYPE, -1, + (sb2 *) 0, (text *) 0, -1, -1)) + { + err_report(&cda1); + do_exit(EXIT_FAILURE); + } + + /* Bind the placeholder in the "seldept" statement. */ + if (obndrn(&cda2, + 1, + (ub1 *) &deptno, + (sword) sizeof(deptno), + INT_TYPE, + -1, + (sb2 *) 0, + (text *) 0, + -1, + -1)) + { + err_report(&cda2); + do_exit(EXIT_FAILURE); + } + + /* Describe the select-list field "dname". */ + len = sizeof (name_buf); + if (odescr(&cda2, 1, (sb4 *) &deptlen, &db_type, + name_buf, (sb4 *) &len, (sb4 *) &dsize, (sb2 *) 0, + (sb2 *) 0, (sb2 *) 0)) + { + err_report(&cda2); + do_exit(EXIT_FAILURE); + } + +/* Allocate the dept buffer now that you have length. */ + dept = (text *) malloc((int) deptlen + 1); + + /* Define the output variable for the select-list. */ + if (odefin(&cda2, + 1, + (ub1 *) dept, + deptlen+1, + STRING_TYPE, + -1, + (sb2 *) 0, + (text *) 0, + -1, + -1, + (ub2 *) 0, + (ub2 *) 0)) + { + err_report(&cda2); + do_exit(EXIT_FAILURE); + } + + for (;;) + { + /* Prompt for employee name. Break on no name. */ + printf("\nEnter employee name (or CR to EXIT): "); + fgets((char *) ename, (int) enamelen+1, stdin); + cp = (text *) strchr((char *) ename, '\n'); + if (cp == ename) + { + printf("Exiting... "); + do_exit(EXIT_SUCCESS); + } + if (cp) + *cp = '\0'; + else + { + printf("Employee name may be truncated.\n"); + myfflush(); + } + /* Prompt for the employee's job and salary. */ + printf("Enter employee job: "); + job_ind = 0; + fgets((char *) job, (int) joblen + 1, stdin); + cp = (text *) strchr((char *) job, '\n'); + if (cp == job) + { + job_ind = -1; /* make it NULL in table */ + printf("Job is NULL.\n");/* using indicator variable */ + } + else if (cp == 0) + { + printf("Job description may be truncated.\n"); + myfflush(); + } + else + *cp = '\0'; + + printf("Enter employee salary: "); + scanf("%d", &sal); + myfflush(); + sal_ind = (sal <= 0) ? -2 : 0; /* set indicator variable */ + + /* + * Prompt for the employee's department number, and verify + * that the entered department number is valid + * by executing and fetching. + */ + do + { + printf("Enter employee dept: "); + scanf("%d", &deptno); + myfflush(); + if (oexec(&cda2) || + (ofetch(&cda2) && (cda2.rc != NO_DATA_FOUND))) + { + err_report(&cda2); + do_exit(EXIT_FAILURE); + } + if (cda2.rc == NO_DATA_FOUND) + printf("The dept you entered doesn't exist.\n"); + } while (cda2.rc == NO_DATA_FOUND); + + /* + * Increment empno by 10, and execute the INSERT + * statement. If the return code is 1 (duplicate + * value in index), then generate the next + * employee number. + */ + empno += 10; + if (oexec(&cda1) && cda1.rc != 1) + { + err_report(&cda1); + do_exit(EXIT_FAILURE); + } + while (cda1.rc == 1) + { + empno += 10; + if (oexec(&cda1) && cda1.rc != 1) + { + err_report(&cda1); + do_exit(EXIT_FAILURE); + } + } /* end for (;;) */ + +/* Commit the change. */ + if (ocom(&lda)) + { + err_report(&lda); + do_exit(EXIT_FAILURE); + } + printf( + "\n\n%s added to the %s department as employee number %d\n", + ename, dept, empno); + } + do_exit(EXIT_SUCCESS); + +} + + +void +err_report(cursor) + Cda_Def *cursor; +{ + sword n; + text msg[512]; + + printf("\n-- ORACLE error--\n"); + printf("\n"); + n = oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + if (cursor->fc > 0) + fprintf(stderr, "Processing OCI function %s", + oci_func_tab[cursor->fc]); +} + + +/* + * Exit program with an exit code. + */ +void do_exit(exit_code) + sword exit_code; +{ + sword error = 0; + + if (oclose(&cda1)) + { + fprintf(stderr, "Error closing cursor 1.\n"); + error++; + } + if (oclose(&cda2)) + { + fprintf(stderr, "Error closing cursor 2.\n"); + error++; + } + if (ologof(&lda)) + { + fprintf(stderr, "Error on disconnect.\n"); + error++; + } + if (error == 0 && exit_code == EXIT_SUCCESS) + printf ("\nG'day\n"); + + exit(exit_code); +} + + +void myfflush() +{ + eb1 buf[50]; + + fgets((char *) buf, 50, stdin); +} + + diff --git a/cdemo2.c b/cdemo2.c new file mode 100644 index 0000000..fdf13b9 --- /dev/null +++ b/cdemo2.c @@ -0,0 +1,509 @@ +/* Copyright (c) 1991, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + cdemo2.c - C demo Program # 2 + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/29/97 - Fix olint errors + echen 03/11/97 - fix a test bug + dchatter 01/05/96 - Creation of the Solaris version with hda as + ub4 array of HDA_SIZE/sizeof(ub4) for alignment + reasons. +*/ + +/* This program accepts arbitrary SQL statements from the user, + and processes the statement. Statements may be entered on + multiple lines, and must be terminated by a semi-colon. + If a query, the results are printed. + + Statements are entered at the OCISQL prompt. + + To quit the program, type EXIT at the OCISQL prompt. + + The size of the HDA is defined by the HDA_SIZE constant, + which is declared in ocidem.h to be 256 bytes for 32- + bit architectures and 512 bytes for 64-bit architectures. +*/ + +#include +#include +#include + + +/* Include OCI-specific headers. */ +#include +#include +#ifdef __STDC__ +#include +#else +#include +#endif +#include + + +/* Constants used in this program. */ +#define MAX_BINDS 12 +#define MAX_ITEM_BUFFER_SIZE 33 +#define MAX_SELECT_LIST_SIZE 12 +#define MAX_SQL_IDENTIFIER 31 + +#define PARSE_NO_DEFER 0 +#define PARSE_V7_LNG 2 + + +/* Define one logon data area and one cursor data area + Also define a host data area for olog. + (See ocidfn.h for declarations). */ +Lda_Def lda; +Cda_Def cda; +size_t hda[HDA_SIZE/sizeof(size_t)]; + +/* Declare an array of bind values. */ +text bind_values[MAX_BINDS][MAX_ITEM_BUFFER_SIZE]; + +/* Declare structures for query information. */ +struct describe +{ + sb4 dbsize; + sb2 dbtype; + sb1 buf[MAX_ITEM_BUFFER_SIZE]; + sb4 buflen; + sb4 dsize; + sb2 precision; + sb2 scale; + sb2 nullok; +}; + +struct define +{ + ub1 buf[MAX_ITEM_BUFFER_SIZE]; + float flt_buf; + sword int_buf; + sb2 indp; + ub2 col_retlen, col_retcode; +}; + + +/* Define arrays of describe and define structs. */ +struct describe desc[MAX_SELECT_LIST_SIZE]; +struct define def[MAX_SELECT_LIST_SIZE]; + +/* Declare this programs functions. */ +sword connect_user(); +sword describe_define(); +sword do_binds(); +void do_exit(); +void oci_error(); +sword get_sql_statement(); +void print_header(); +void print_rows(); + +/* Globals */ +static text sql_statement[2048]; +static sword sql_function; +static sword numwidth = 8; + + +main() +{ + sword col, errno, n, ncols; + text *cp; + + /* Connect to ORACLE. */ + if (connect_user()) + exit(-1); + + /* Open a cursor, exit on error (unrecoverable). */ + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) + { + printf("Error opening cursor. Exiting...\n"); + ologof(&lda); + exit(-1); + } + + /* Process user's SQL statements. */ + + for (;;) + { + /* Get the statement, exit on "exit". */ + if (get_sql_statement()) { + printf("\n"); + do_exit(0); + } + + /* Parse the statement; do not defer the parse, + so that errors come back right away. */ + if (oparse(&cda, (text *) sql_statement, (sb4) -1, + (sword) PARSE_NO_DEFER, (ub4) PARSE_V7_LNG)) + { + oci_error(&cda); + continue; + } + + /* Save the SQL function code right after parse. */ + sql_function = cda.ft; + + /* Bind any input variables. */ + if ((ncols = do_binds(&cda, sql_statement)) == -1) + continue; + + /* If the statement is a query, describe and define + all select-list items before doing the oexec. */ + if (sql_function == FT_SELECT) + if ((ncols = describe_define(&cda)) == -1) + continue; + + /* Execute the statement. */ + if (oexec(&cda)) + { + oci_error(&cda); + continue; + } + + /* Fetch and display the rows for the query. */ + if (sql_function == FT_SELECT) + { + print_header(ncols); + print_rows(&cda, ncols); + } + + /* Print the rows-processed count. */ + if (sql_function == FT_SELECT || + sql_function == FT_UPDATE || + sql_function == FT_DELETE || + sql_function == FT_INSERT) + printf("\n%d row%c processed.\n", cda.rpc, + cda.rpc == 1 ? ' ' : 's'); + else + printf("\nStatement processed.\n"); + + } /* end for (;;) */ + + +} /* end main() */ + + +sword +connect_user() +{ + text username[132]; + text password[132]; + sword n; + + /* Three tries to connect. */ + for (n = 3; --n >= 0; ) + { + printf("Username: "); + gets((char *) username); + printf("Password: "); + gets((char *) password); + + if (olog(&lda, (ub1 *)hda, username, -1, password, -1, + (text *) 0, -1, (ub4)OCI_LM_DEF)) + { + printf("Cannot connect as %s.\n", username); + printf("Try again.\n\n"); + } + else + { + return 0; + } + } + printf("Connection failed. Exiting...\n"); + return -1; +} + + +/* Describe select-list items. */ + +sword +describe_define(cda) +Cda_Def *cda; +{ + sword col, deflen, deftyp; + static ub1 *defptr; + + /* Describe the select-list items. */ + for (col = 0; col < MAX_SELECT_LIST_SIZE; col++) + { + desc[col].buflen = MAX_ITEM_BUFFER_SIZE; + if (odescr(cda, col + 1, &desc[col].dbsize, + &desc[col].dbtype, &desc[col].buf[0], + &desc[col].buflen, &desc[col].dsize, + &desc[col].precision, &desc[col].scale, + &desc[col].nullok)) + { + /* Break on end of select list. */ + if (cda->rc == VAR_NOT_IN_LIST) + break; + else + { + oci_error(cda); + return -1; + } + } + /* adjust sizes and types for display */ + switch (desc[col].dbtype) + { + case NUMBER_TYPE: + desc[col].dbsize = numwidth; + /* Handle NUMBER with scale as float. */ + if (desc[col].scale != 0) + { + defptr = (ub1 *) &def[col].flt_buf; + deflen = (sword) sizeof(float); + deftyp = FLOAT_TYPE; + desc[col].dbtype = FLOAT_TYPE; + } + else + { + defptr = (ub1 *) &def[col].int_buf; + deflen = (sword) sizeof(sword); + deftyp = INT_TYPE; + desc[col].dbtype = INT_TYPE; + } + break; + default: + if (desc[col].dbtype == DATE_TYPE) + desc[col].dbsize = 9; + if (desc[col].dbtype == ROWID_TYPE) + desc[col].dbsize = 18; + defptr = def[col].buf; + deflen = desc[col].dbsize > MAX_ITEM_BUFFER_SIZE ? + MAX_ITEM_BUFFER_SIZE : desc[col].dbsize + 1; + deftyp = STRING_TYPE; + break; + } + if (odefin(cda, col + 1, + defptr, deflen, deftyp, + -1, &def[col].indp, (text *) 0, -1, -1, + &def[col].col_retlen, + &def[col].col_retcode)) + { + oci_error(cda); + return -1; + } + } + return col; +} + + +/* Bind input variables. */ + +sword +do_binds(cda, stmt_buf) +Cda_Def *cda; +text *stmt_buf; +{ + sword i, in_literal, n; + text *cp, *ph; + + /* Find and bind input variables for placeholders. */ + for (i = 0, in_literal = FALSE, cp = stmt_buf; + *cp && i < MAX_BINDS; cp++) + { + if (*cp == '\'') + in_literal = ~in_literal; + if (*cp == ':' && !in_literal) + { + for (ph = ++cp, n = 0; + *cp && (isalnum(*cp) || *cp == '_') + && n < MAX_SQL_IDENTIFIER; + cp++, n++ + ) + ; + *cp = '\0'; + printf("Enter value for %s: ", ph); + gets((char *) &bind_values[i][0]); + + /* Do the bind, using obndrv(). + NOTE: the bind variable address must be static. + This would not work if bind_values were an + auto on the do_binds stack. */ + if (obndrv(cda, ph, -1, (ub1 *)&bind_values[i][0], -1, + VARCHAR2_TYPE, + -1, (sb2 *) 0, (text *) 0, -1, -1)) + { + oci_error(cda); + return -1; + } + i++; + } /* end if (*cp == ...) */ + } /* end for () */ + return i; +} + + + +/* Clean up and exit. LDA and CDA are + global. */ +void +do_exit(rv) +sword rv; +{ + if (oclose(&cda)) + fputs("Error closing cursor!\n", stdout); + if (ologof(&lda)) + fputs("Error logging off!\n", stdout); + exit(rv); +} + + +void +oci_error(cda) +Cda_Def *cda; +{ + text msg[512]; + sword n; + + fputs("\n-- ORACLE ERROR --\n", stderr); + n = oerhms(&lda, cda->rc, msg, (sword) sizeof (msg)); + fprintf(stderr, "%.*s", n, msg); + fprintf(stderr, "Processing OCI function %s\n", + oci_func_tab[cda->fc]); + fprintf(stderr, "Do you want to continue? [yn]: "); + fgets((char *) msg, (int) sizeof (msg), stdin); + if (*msg != '\n' && *msg != 'y' && *msg != 'Y') + do_exit(1); + fputc('\n', stdout); +} + + +sword +get_sql_statement() +{ + text cbuf[1024]; + text *cp; + sword stmt_level; + + + for (stmt_level = 1; ;) + { + if (stmt_level == 1) + { + /* Init statement buffer and print prompt. */ + *sql_statement = '\0'; + fputs("\nOCISQL> ", stdout); + } + else + { + printf("%3d ", stmt_level); + } + + /* Get (part of) a SQL statement. */ + gets((char *) cbuf); + if (*cbuf == '\0') + continue; + if (strncmp((char *) cbuf, "exit", 4) == 0) + return -1; + + /* Concatenate to statement buffer. */ + if (stmt_level > 1) + strcat((char *) sql_statement, " "); + strcat((char *) sql_statement, (char *) cbuf); + + /* Check for possible terminator. */ + cp = &sql_statement[strlen((char *) sql_statement) - 1]; + + while (isspace(*cp)) + cp--; + if (*cp == ';') + { + *cp = '\0'; + break; + } + stmt_level++; + } + return 0; +} + + +void +print_header(ncols) +sword ncols; +{ + sword col, n; + + fputc('\n', stdout); + + for (col = 0; col < ncols; col++) + { + n = desc[col].dbsize - desc[col].buflen; + if (desc[col].dbtype == FLOAT_TYPE || + desc[col].dbtype == INT_TYPE) + { + printf("%*c", n, ' '); + printf("%*.*s", desc[col].buflen, + desc[col].buflen, desc[col].buf); + } + else + { + printf("%*.*s", desc[col].buflen, + desc[col].buflen, desc[col].buf); + printf("%*c", n, ' '); + } + fputc(' ', stdout); + } + fputc('\n', stdout); + + for (col = 0; col < ncols; col++) + { + for (n = desc[col].dbsize; --n >= 0; ) + fputc('-', stdout); + fputc(' ', stdout); + } + fputc('\n', stdout); +} + + +void +print_rows(cda, ncols) +Cda_Def *cda; +sword ncols; +{ + sword col, n; + + for (;;) + { + fputc('\n', stdout); + /* Fetch a row. Break on end of fetch, + disregard null fetch "error". */ + if (ofetch(cda)) + { + if (cda->rc == NO_DATA_FOUND) + break; + if (cda->rc != NULL_VALUE_RETURNED) + oci_error(cda); + } + for (col = 0; col < ncols ; col++) + { + /* Check col. return code for null. If + null, print n spaces, else print value. */ + if (def[col].indp < 0) + printf("%*c", desc[col].dbsize, ' '); + else + { + switch (desc[col].dbtype) + { + case FLOAT_TYPE: + printf("%*.*f", numwidth, 2, def[col].flt_buf); + break; + case INT_TYPE: + printf("%*d", numwidth, def[col].int_buf); + break; + default: + printf("%s", def[col].buf); + n = desc[col].dbsize - strlen((char *) def[col].buf); + if (n > 0) + printf("%*c", n, ' '); + break; + } + } + fputc(' ', stdout); + } + } /* end for (;;) */ +} + diff --git a/cdemo3.c b/cdemo3.c new file mode 100644 index 0000000..142c7a5 --- /dev/null +++ b/cdemo3.c @@ -0,0 +1,292 @@ +/* Copyright (c) 1991, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + cdemo3.c - C demo program # 3 + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/29/97 - Fix olint errors + dchatter 01/05/96 - Creation of the Solaris version with hda as + ub4 array of HDA_SIZE/sizeof(ub4) for alignment + reasons. +*/ +/* + * cdemo3.c + * + * Demonstrates using the oflng function to retrieve + * a portion of a LONG column. + * + * This example "plays" a digitized voice message + * by repeatedly extracting 64 Kbyte chunks of the message + * from the table and sending them to a converter buffer + * (for example, a digital-to-analog converter's FIFO buffer). + * + * To better understand this example, the table is created by + * the program, and some dummy data is inserted into it. + * + * The converter subroutine is only simulated in this example + * program. + * + * The size of the HDA is defined by the HDA_SIZE constant, + * which is declared in ocidem.h to be 256 bytes for 32- + * bit architectures and 512 bytes for 64-bit architectures. + * + */ + +#include +#include +#include + +#define MSG_SIZE 200000 + +#include +#include +#ifdef __STDC__ +#include +#else +#include +#endif +#include + +Cda_Def cda; +Lda_Def lda; +size_t hda[HDA_SIZE/sizeof(size_t)]; + + +dvoid do_exit(); +dvoid oci_error(); +dvoid play_msg(); + + +main() +{ + text sql_statement[256]; + register sword i; + sb2 indp; + ub2 retl, rcode; + sword msg_id; + sb4 msg_len, len, offset; + ub1 *ucp; + register ub1 *ucp1; + ub4 ret_len; + + + /* Connect to ORACLE. */ + if (olog(&lda, (ub1 *)hda, (text *) "scott/tiger", -1, + (text *) 0, -1, (text *) 0, -1, (ub4)OCI_LM_DEF)) + { + fputs("Cannot connect with username SCOTT. Exiting...\n", stderr); + exit(EXIT_FAILURE); + } + fputs("Connected to ORACLE as user SCOTT.\n", stdout); + + + /* Open a cursor. */ + if (oopen(&cda, &lda, (text *) 0, -1, + -1, (text *) 0, -1)) + { + fputs("Cannot open cursor. Exiting...\n", stderr); + exit(EXIT_FAILURE); + } + + fputs("Program is about to drop the VOICE_MAIL table.\n", stdout); + fputs("Is this OK (Y or N)? : ", stdout); + fflush(stdout); + + gets((char *) sql_statement); + if (*sql_statement != 'y' && *sql_statement != 'Y') + do_exit(EXIT_SUCCESS); + + /* Parse, set defflg parameter for non-deferred parse + (to execute the DDL statement immediately). */ + if (oparse(&cda, (text *) "DROP TABLE voice_mail", + (sb4)-1, FALSE, (ub4)2)) + { + if (cda.rc == 942) + fputs("Table did not exist.\n", stdout); + else + oci_error(&cda); + } + else + fputs("Dropped table \"voice_mail\".\n", stdout); + + strcpy((char *) sql_statement, "CREATE TABLE voice_mail\ + (msg_id NUMBER(6), msg_len NUMBER(12), msg LONG RAW)"); + if (oparse(&cda, sql_statement, (sb4)-1, FALSE, (ub4)2)) + oci_error(&cda); + fputs("Created table \"voice_mail\".\n", stdout); + + + /* Create a dummy message. */ + strcpy((char *) sql_statement, + "INSERT INTO voice_mail (msg_id, msg_len, msg) \ + VALUES (:1, :2, :3)"); + if (oparse(&cda, sql_statement, (sb4)-1, FALSE, (ub4)2)) + oci_error(&cda); + + if (obndrn(&cda, 1, (ub1 *) &msg_id, 4, 3, -1, + (sb2 *) 0, (text *) 0, 0, -1)) + oci_error(&cda); + + /* Set buffer address before binding. */ + ucp = (ub1 *) malloc(MSG_SIZE); + if (ucp == 0) + { + fputs("malloc error\n", stderr); + do_exit(EXIT_FAILURE); + } + + if (obndrn(&cda, 2, (ub1 *) &msg_len, 4, 3, -1, + (sb2 *) 0, (text *) 0, 0, -1)) + oci_error(&cda); + + if (obndrn(&cda, 3, ucp, MSG_SIZE, 24, -1, + (sb2 *) 0, (text *) 0, 0, -1)) + oci_error(&cda); + + /* Set bind vars before oexn. */ + msg_id = 100; + msg_len = MSG_SIZE; + for (i = 0, ucp1 = ucp; i < MSG_SIZE; i++) + *ucp1++ = (ub1) i % 128; + + if (oexn(&cda, 1, 0)) + oci_error(&cda); + fputs("Data inserted in table \"voice_mail\".\n", stdout); + +/* + * After setting up the test data, do the + * select and fetch the message chunks + */ + strcpy((char *) sql_statement, "select msg_id, msg_len, msg\ + from voice_mail where msg_id = 100"); + if (oparse(&cda, sql_statement, (sb4)-1, 0, (ub4)2)) + oci_error(&cda); + if (odefin(&cda, + 1, /* index */ + (ub1 *) &msg_id, /* output variable */ + 4, /* length */ + 3, /* datatype */ + -1, /* scale */ + (sb2 *) 0, /* indp */ + (text *) 0, /* fmt */ + 0, /* fmtl */ + -1, /* fmtt */ + (ub2 *) 0, /* retl */ + (ub2 *) 0)) /* rcode */ + oci_error(&cda); + if (odefin(&cda, + 2, /* index */ + (ub1 *) &msg_len,/* output variable */ + 4, /* length */ + 3, /* datatype */ + -1, /* scale */ + (sb2 *) 0, /* indp */ + (text *) 0, /* fmt */ + 0, /* fmtl */ + -1, /* fmtt */ + (ub2 *) 0, /* retl */ + (ub2 *) 0)) /* rcode */ + oci_error(&cda); + if (odefin(&cda, + 3, /* index */ + ucp, /* output variable */ + 100, /* length */ + 24, /* LONG RAW datatype code */ + -1, /* scale */ + &indp, /* indp */ + (text *) 0, /* fmt */ + 0, /* fmtl */ + -1, /* fmtt */ + &retl, /* retl */ + &rcode)) /* rcode */ + oci_error(&cda); + + + /* Do the query, getting the msg_id and the first + 100 bytes of the message. */ + if (oexfet(&cda, + (ub4) 1, /* nrows */ + 0, /* cancel (FALSE) */ + 0)) /* exact (FALSE) */ + { + oci_error(&cda); + } + fprintf(stdout, + "Message %d is available, length is %d.\n", msg_id, msg_len); + fprintf(stdout, + "indp = %d, rcode = %d, retl = %d\n", indp, rcode, retl); + + /* Play the message, looping until there are + no more data points to output. */ + + for (offset = (ub4) 0; ; offset += (ub4) 0x10000) + { + len = msg_len < 0x10000 ? msg_len : 0x10000; + + if (oflng(&cda, + 3, /* position */ + ucp, /* buf */ + len, /* bufl */ + 24, /* datatype */ + &ret_len, /* retl */ + offset)) /* offset */ + oci_error(&cda); + + /* Output the message chunk. */ + play_msg(ucp, len); + msg_len -= len; + if (msg_len <= 0) + break; + } + do_exit(EXIT_SUCCESS); +} + + +dvoid +play_msg(buf, len) +ub1 *buf; +sword len; +{ + fprintf(stdout, "\"playing\" %d bytes.\n", len); +} + + +dvoid +oci_error(cda) +Cda_Def *cda; +{ + text msg[200]; + sword n; + + fputs("\n-- ORACLE ERROR --\n", stderr); + n = oerhms(&lda, (sb2) cda->rc, msg, 200); + fprintf(stderr, "%.*s", n, msg); + fprintf(stderr, "Processing OCI function %s\n", + oci_func_tab[(int) cda->fc]); + do_exit(EXIT_FAILURE); +} + + +dvoid +do_exit(rv) +sword rv; +{ + fputs("Exiting...\n", stdout); + if (oclose(&cda)) + { + fputs("Error closing cursor.\n", stderr); + rv = EXIT_FAILURE; + } + if (ologof(&lda)) + { + fputs("Error logging off.\n", stderr); + rv = EXIT_FAILURE; + } + exit(rv); +} + + + diff --git a/cdemo4.c b/cdemo4.c new file mode 100644 index 0000000..d43c22b --- /dev/null +++ b/cdemo4.c @@ -0,0 +1,413 @@ +/* Copyright (c) 1991, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + cdemo4.c - + DESCRIPTION + + PUBLIC FUNCTION(S) + + PRIVATE FUNCTION(S) + + RETURNS + + NOTES + + MODIFIED (MM/DD/YY) + azhao 10/11/06 - case-senstive password change + kmohan 03/28/06 - change hda to size_t + jchai 07/27/04 - add order by in select stmt + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/29/97 - Fix olint errors + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + plocke 11/18/95 - to update for v7.3 + slari 04/25/95 - merge changes from branch 1.6.720.1 + slari 04/19/95 - replace orlon with olog + emendez 04/07/94 - merge changes from branch 1.4.710.3 + gdoherty 04/06/94 - merge changes from branch 1.4.710.1 + emendez 02/07/94 - fix for bug 196094 + emendez 02/02/94 - Fix for bug 157576 + gdoherty 02/02/94 - make oci header inclusion for ansi or k+r adaptive + lfeng 01/13/93 - fix non-portable fflush + rkooi2 11/27/92 - Changing e... datatypes to s... + kaghevli 11/06/92 - test + rkooi2 10/29/92 - Creation +*/ +/* cdemo4.c + * + * Demonstrates doing a FETCH from a cursor + * into PL/SQL tables. The tables are bound to C + * arrays using the obndra routine. + * The fully-commented script to create the stored procedure + * is in the demo program file calldemo.sql. + * + * Execute this script using SQL*DBA or SQL*Plus + * to store the package before executing this program. + * + * The script is: + * create or replace package calldemo as + * + * type char_array is table of varchar2(20) index by binary_integer; + * type num_array is table of float index by binary_integer; + * + * procedure get_employees( + * dept_number in integer, -- which department to query + * batch_size in integer, -- how many rows at a time + * found in out integer, -- n of rows actually returned + * done_fetch out integer, -- all done flag + * emp_name out char_array,-- arrays of employee names, + * job out char_array,-- jobs, + * sal out num_array);-- salaries + * + * end; + * / + * + * create or replace package body calldemo as + * + * cursor get_emp( + * dept_number in integer) is + * select ename, job, sal from emp + * where deptno = dept_number order by ename; + * + * -- Procedure get_employees fetches a batch of employee + * -- rows (batch size is determined by the client/caller + * -- of this procedure). Procedure may be called from + * -- other stored procedures or client application + * -- programs. The procedure opens the cursor if it is + * -- not already open, fetches a batch of rows, and + * -- returns the number of rows actually retrieved. At + * -- end of fetch, the procedure closes the cursor. + * + * procedure get_employees( + * dept_number in integer, + * batch_size in integer, + * found in out integer, + * done_fetch out integer, + * emp_name out char_array, + * job out char_array, + * sal out num_array) is + * + * begin + * if NOT get_emp%ISOPEN then -- open the cursor if it is + * open get_emp(dept_number); -- not already open + * end if; + * + * -- Fetch up to "batch_size" rows into PL/SQL table, + * -- tallying rows found as they are retrieved. When end + * -- of fetch is encountered, close the cursor and exit + * -- the loop, returning only the last set of rows found. + * + * done_fetch := FALSE; + * found := 0; + * + * for i in 1..batch_size loop + * fetch get_emp -- get one emp table row + * into emp_name(i), job(i), sal(i); + * + * if get_emp%notfound then -- if no row was found, then + * close get_emp; -- close the cursor + * done_fetch := TRUE; -- indicate all done + * exit; -- exit the loop + * else + * found := found + 1; -- else count the row and continue + * end if; + * end loop; + * end; + * end; + * / + */ + +#include +#include + +#include +#include +#ifdef __STDC__ +#include +#else +#include +#endif +#include + +#define MAX_ARRAY_SIZE 5 +#define NO_PARSE_DEFER 0 +#define V7_LNGFLG 2 +#define VC_LENGTH 20 + +/* Declare the data areas. */ +Cda_Def cda; +Lda_Def lda; +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ + +/* Declare routines in this program */ +dvoid do_fetch(/*_ void _*/); +dvoid oci_error(/*_ void _*/); + +main(argc, argv) +sword argc; +text **argv; +{ + text username[128]; + + if (argc > 1) + strncpy((char *) username, (char *) argv[1], + sizeof (username) - 1); + else + strcpy((char *) username, "SCOTT/tiger"); + + if (olog(&lda, (ub1 *)hda, username, -1, (text *) 0, -1, + (text *) 0, -1, (ub4)OCI_LM_DEF)) + { + printf("Cannot connect as %s. Exiting...\n", username); + exit(-1); + } + else + printf("Connected.\n"); + + /* Open the OCI cursor. */ + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) + { + printf("Cannot open cursor data area, exiting...\n"); + exit(-1); + } + + /* Fetch and print the data. */ + do_fetch(); + + /* Close the OCI cursor. */ + if (oclose(&cda)) + { + printf("Error closing cursor!\n"); + exit(-1); + } + + /* Disconnect from ORACLE. */ + if (ologof(&lda)) + { + printf("Error logging off!\n"); + exit(-1); + } + exit(0); +} + + +/* Set up an anonymous PL/SQL call to the stored + procedure that fetches the data. */ +dvoid +do_fetch(/*_ void _*/) +{ + text *call_fetch = (text *) "\ + begin\ + calldemo.get_employees(:deptno, :t_size, :num_ret, :all_done,\ + :e_name, :job, :sal);\ + end;"; + sword table_size = MAX_ARRAY_SIZE; + sword i, n_ret, done_flag; + sword dept_num; + sb2 n_ret_indp; + ub2 n_ret_len, n_ret_rcode; + ub4 n_ret_cursiz = 0; + + text emp_name[MAX_ARRAY_SIZE][VC_LENGTH]; + sb2 emp_indp_name[MAX_ARRAY_SIZE]; + ub2 emp_len_name[MAX_ARRAY_SIZE]; + ub2 emp_rcode_name[MAX_ARRAY_SIZE]; + ub4 emp_cursiz_name = (ub4) MAX_ARRAY_SIZE; + + text job[MAX_ARRAY_SIZE][VC_LENGTH]; + sb2 job_indp[MAX_ARRAY_SIZE]; + ub2 job_len[MAX_ARRAY_SIZE]; + ub2 job_rcode[MAX_ARRAY_SIZE]; + ub4 job_cursiz = (ub4) MAX_ARRAY_SIZE; + + float salary[MAX_ARRAY_SIZE]; + sb2 salary_indp[MAX_ARRAY_SIZE]; + ub2 salary_len[MAX_ARRAY_SIZE]; + ub2 salary_rcode[MAX_ARRAY_SIZE]; + ub4 salary_cursiz = (ub4) MAX_ARRAY_SIZE; + + /* parse the anonymous SQL block */ + if (oparse(&cda, call_fetch, (sb4)-1, + NO_PARSE_DEFER, (ub4)V7_LNGFLG)) + { + oci_error(); + return; + } + + /* initialize the bind arrays */ + for (i = 0; i < MAX_ARRAY_SIZE; i++) + { + emp_len_name[i] = VC_LENGTH; + job_len[i] = VC_LENGTH; + salary_len[i] = sizeof (float); + } + + n_ret_len = sizeof (sword); + + /* bind the department number IN parameter */ + if (obndrv(&cda, (text *) ":deptno", -1, (ub1 *) &dept_num, + (sword) sizeof (sword), INT_TYPE, -1, + (sb2 *) 0, (text *) 0, -1, -1)) + { + oci_error(); + return; + } + /* bind the table size IN parameter */ + if (obndrv(&cda, (text *) ":t_size", -1, (ub1 *) &table_size, + (sword) sizeof (sword), + INT_TYPE, -1, (sb2 *) 0, (text *) 0, -1, -1)) + { + oci_error(); + return; + } + /* bind the fetch done OUT parameter */ + if (obndrv(&cda, (text *) ":all_done", -1, (ub1 *) &done_flag, + (sword) sizeof (sword), + INT_TYPE, -1, (sb2 *) 0, (text *) 0, -1, -1)) + { + oci_error(); + return; + } + + /* Bind the OUT n_ret using obndra. obndrv could + have been used just as well, since no arrays + are involved, but it is possible to use obndra + for scalars as well. */ + if (obndra(&cda, + (text *) ":num_ret", + -1, + (ub1 *) &n_ret, + (sword) sizeof (sword), + INT_TYPE, + -1, + &n_ret_indp, + &n_ret_len, + &n_ret_rcode, + (ub4) 0, /* pass as 0, not 1, when binding a scalar */ + (ub4 *) 0, /* pass as the null pointer when scalar */ + (text *) 0, + -1, + -1)) + { + oci_error(); + return; + } + + /* bind the employee name array */ + if (obndra(&cda, + (text *) ":e_name", + -1, + (ub1 *) emp_name, + VC_LENGTH, + VARCHAR2_TYPE, + -1, + emp_indp_name, + emp_len_name, + emp_rcode_name, + (ub4) MAX_ARRAY_SIZE, + &emp_cursiz_name, + (text *) 0, + -1, + -1)) + { + oci_error(); + return; + } + + /* bind the job array */ + if (obndra(&cda, + (text *) ":job", + -1, + (ub1 *) job, + VC_LENGTH, + VARCHAR2_TYPE, + -1, + job_indp, + job_len, + job_rcode, + (ub4) MAX_ARRAY_SIZE, + &job_cursiz, + (text *) 0, + -1, + -1)) + { + oci_error(); + return; + } + + /* bind the salary array */ + if (obndra(&cda, + (text *) ":sal", + -1, + (ub1 *) salary, + (sword) sizeof (float), + FLOAT_TYPE, + -1, + salary_indp, + salary_len, + salary_rcode, + (ub4) MAX_ARRAY_SIZE, + &salary_cursiz, + (text *) 0, + -1, + -1)) + { + oci_error(); + return; + } + + printf("\nenter deptno: "); + scanf("%d", &dept_num); + + for (;;) + { + /* execute the fetch */ + if (oexec(&cda)) + { + oci_error(); + return; + } + + printf("\n%d row%c returned\n", + n_ret, n_ret == 1 ? '\0' : 's'); + + if (n_ret > 0) + { + printf("\n%-*.*s%-*.*s%s\n", + VC_LENGTH, VC_LENGTH, "Employee Name", + VC_LENGTH, VC_LENGTH, "Job", " Salary"); + for (i = 0; i < n_ret; i++) + { + printf("%.*s", emp_len_name[i], emp_name[i]); + printf("%*c", VC_LENGTH - emp_len_name[i], ' '); + printf("%.*s", job_len[i], job[i]); + printf("%*c", VC_LENGTH - job_len[i], ' '); + printf("%8.2f\n", salary[i]); + } + } + if (done_flag != 0) + { + printf("\n"); + break; + } + } + return; +} + + +dvoid +oci_error(/*_ void _*/) +{ + text msg[900]; + sword rv; + + rv = oerhms(&lda, cda.rc, msg, (sword) sizeof (msg)); + + printf("\n\n%.*s", rv, msg); + printf("Processing OCI function %s\n", + oci_func_tab[(int) cda.fc]); + return; +} + + diff --git a/cdemo5.c b/cdemo5.c new file mode 100644 index 0000000..6a7aab1 --- /dev/null +++ b/cdemo5.c @@ -0,0 +1,313 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemo5.c 11-oct-2006.17:36:36 azhao Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + cdemo5.c - a small example of use of variable cursors + MODIFIED (MM/DD/YY) + azhao 10/11/06 - case-senstive password change + lzhao 04/04/05 - bug4184176 + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/29/97 - Fix olint errors + azhao 05/16/97 - change ub1 to ub4 for hstb + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + plocke 11/18/95 - to update for v7.3 + slari 04/25/95 - merge changes from branch 1.1.720.1 + slari 04/20/95 - Branch_for_patch + slari 04/19/95 - replace orlon with olog + pvasterd 10/20/94 - Changes to bring into line with other cdemos + dchatter 10/17/94 - Creation + */ +/* + * -- cdemo5.c -- + * + * An example program which demonstrates the use of + * Variable Cursors in an OCI program. + * + */ + +#include +#include +#include +#include +#include +#include +#include + + /* oparse flags */ +#define DEFER_PARSE 1 +#define VERSION_7 2 + +#define NPOS 16 +#define DSCLEN 240 + +text *username = (text *) "SCOTT"; +text *password = (text *) "tiger"; + +static sword retval; +static ub4 hstb[512]; +static text errorb[4095]; +static text cbuf[NPOS][DSCLEN]; +static sb4 cbufl[NPOS]; +static sb4 dbsize[NPOS]; +static sb4 dsize[NPOS]; +static sb2 dbtype[NPOS]; +static sb2 prec[NPOS]; +static sb2 scale[NPOS]; +static sb2 nullok[NPOS]; + +static Lda_Def lda1; + +static text plsql_block[] = + "begin \ + OPEN :cursor1 FOR select empno, ename, job, mgr, hiredate,sal,deptno\ + from emp where job=:job order by empno;\ + end;"; + +/* CLIENT CURSORS */ +static Cda_Def cursor, cursor_emp; + +/* Prototype */ +void oracle_error(); + +int main () +{ + Lda_Def *ldap = &lda1; + + ub4 empno; + text ename[11]; + text job[10]; + ub4 mgr; + text hidate[10]; + ub4 sal; + ub4 deptno; + int i; + text job_kind[50]; + ub4 pos; + + strcpy((char *) job_kind, (char *)"ANALYST"); + fprintf(stdout,"\n\nFETCHING for job=%s\n\n",job_kind); + + /* + * Connect to Oracle as SCOTT/TIGER. + * Exit on any error. + */ + + if (olog(ldap, (ub1 *)hstb, username, -1, password, -1, + (text *) 0, -1, (ub4)OCI_LM_DEF)) + { + printf("Unable to connect as %s\n", username); + exit(EXIT_FAILURE); + } + printf("Connected to Oracle as %s\n\n", username); + + /* + * Open a cursor for executing the PL/SQL block. + */ + + if (oopen(&cursor, ldap, (text *) 0, -1, 0, (text *) 0, -1)) + { + oracle_error(&cursor); + exit(EXIT_FAILURE); + } + + /* + * Parse the PL/SQL block. + */ + + if (oparse(&cursor, plsql_block, (sb4) -1, (sword) TRUE, (ub4) 2)) + { + oracle_error(&cursor); + exit(EXIT_FAILURE); + } + + /* + * Bind a variable of cursor datatype, the cursor will be opened + * inside the PL/SQL block. + */ + + if (obndra(&cursor, (text *) ":cursor1", -1, (ub1 *) &cursor_emp, + -1, SQLT_CUR, -1, (sb2 *) 0, (ub2 *) 0, (ub2 *) 0, + (ub4) 0, (ub4 *) 0, (text *) 0, 0, 0)) + { + oracle_error(&cursor); + exit(EXIT_FAILURE); + } + + /* + * Bind a variable of string datatype. + */ + + if (obndra(&cursor, (text *) ":job", -1, (ub1 *) job_kind, + -1, SQLT_STR, -1, (sb2 *) 0, (ub2 *) 0, (ub2 *) 0, + (ub4) 0, (ub4 *) 0, (text *) 0, 0, 0)) + { + oracle_error(&cursor); + exit(EXIT_FAILURE); + } + + /* + * Execute the PL/SQL block. + */ + + if (oexec(&cursor)) + { + oracle_error(&cursor); + exit(EXIT_FAILURE); + } + + /* + * Close the cursor on which the PL/SQL block executed. + */ + + if (oclose(&cursor)) + { + oracle_error(&cursor); + exit(EXIT_FAILURE); + } + + /* + * Do describe on cursor initialized and returned from the PL/SQL block. + */ + + for (pos = 0; pos < NPOS; pos++) + { + cbufl[pos] = DSCLEN; + if (odescr(&cursor_emp, (sword) (pos+1), &dbsize[pos], &dbtype[pos], + (sb1 *) cbuf[pos], &cbufl[pos], &dsize[pos], + &prec[pos], &scale[pos], &nullok[pos])) + { + if (cursor_emp.rc == 1007) + break; + oracle_error(&cursor_emp); + exit(EXIT_FAILURE); + } + } + + printf("Describe select-list returns:\n\n"); + printf("----------------------------------------\n"); + printf("Item\t\tMaxSize\t\tType\n"); + printf("----------------------------------------\n"); + for (i = 0; i < pos; i++) + { + cbuf[i][cbufl[i]] = '\0'; + printf("%s\t\t%d\t\t%d\n", cbuf[i], dbsize[i], dbtype[i]); + } + + /* + * Do client defines. + */ + + if (odefin(&cursor_emp, 1, (ub1 *) &empno, (sword) sizeof(ub4), SQLT_INT, + -1, (sb2 *) -1, (text *) 0, (sword) 0, (sword) 0, (ub2 *) 0, + (ub2 *) 0)) + { + oracle_error(&cursor_emp); + exit(EXIT_FAILURE); + } + + if (odefin(&cursor_emp, 2, (ub1 *) ename, (sword) sizeof(ename), + SQLT_STR, -1, (sb2 *) -1, (text *)0, (sword) 0, (sword) 0, + (ub2 *) 0, (ub2 *) 0)) + { + oracle_error(&cursor_emp); + exit(EXIT_FAILURE); + } + + if (odefin(&cursor_emp, 3, (ub1 *) job, (sword) sizeof(job), + SQLT_STR, -1, (sb2 *) -1, (text *) 0, (sword) 0, (sword) 0, + (ub2 *) 0, (ub2 *) 0)) + { + oracle_error(&cursor_emp); + exit(EXIT_FAILURE); + } + + if (odefin(&cursor_emp, 4, (ub1 *)&mgr, (sword) sizeof(ub4), SQLT_INT, + -1, (sb2 *) -1, (text *)0, (sword) 0, (sword) 0, (ub2 *) 0, + (ub2 *) 0)) + { + oracle_error(&cursor_emp); + exit(EXIT_FAILURE); + } + + if (odefin(&cursor_emp, 5, (ub1 *)hidate, (sword) sizeof(hidate), + SQLT_STR, -1, (sb2 *) -1, (text *) 0, (sword) 0, (sword) 0, + (ub2 *) 0, (ub2 *) 0)) + { + oracle_error(&cursor_emp); + exit(EXIT_FAILURE); + } + + if (odefin(&cursor_emp, 6, (ub1 *) &sal, (sword) sizeof(ub4), SQLT_INT, + -1, (sb2 *) -1, (text *) 0, (sword) 0, (sword) 0, (ub2 *) 0, + (ub2 *) 0)) + { + oracle_error(&cursor_emp); + exit(EXIT_FAILURE); + } + + if (odefin(&cursor_emp, 7, (ub1 *) &deptno, (sword) sizeof(deptno), + SQLT_INT, -1, (sb2 *) -1, (text *) 0, (sword) 0, (sword) 0, + (ub2 *) 0, (ub2 *) 0)) + { + oracle_error(&cursor_emp); + exit(EXIT_FAILURE); + } + + printf("\nFETCH from variable cursor:\n\n"); + printf("------------------------------------------------------------\n"); + printf("empno\tename\tjob\tmgr\thiredate\tsalary\tdept\n"); + printf("------------------------------------------------------------\n"); + + /* + * Now fetch the result set and display. + */ + + while (1) + { + sb4 err = 0; + + if (err = ofetch(&cursor_emp)) + { + if (cursor_emp.rc == 1403) + break; + else + { + oracle_error(&cursor_emp); + exit(EXIT_FAILURE); + } + } + else + { + /* A row was returned; have to do the fetch. */ + fprintf(stdout, "%d\t%s\t%s\t%d\t%s\t%d\t%d\n\n", + empno, ename, job, mgr, hidate, sal, deptno); + } + } + + /* + * Log off. + */ + + if (ologof(ldap)) + { + oracle_error(&cursor_emp); + exit(EXIT_FAILURE); + } +} /* end of main */ + +void oracle_error(lda) +Lda_Def * lda; +{ + char msgbuf[512]; + int n=oerhms(lda, lda->rc, (text *)msgbuf, (int) sizeof(msgbuf) ); + + printf("\n\n%.*s\n",n,msgbuf); +} + + diff --git a/cdemo6.cc b/cdemo6.cc new file mode 100644 index 0000000..11a828c --- /dev/null +++ b/cdemo6.cc @@ -0,0 +1,315 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemo6.cc 18-feb-2005.06:13:14 sudsrini Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1991, 2005, Oracle. All rights reserved. +*/ + +/* + NAME + cdemo1.cc - C++ Demo Program + MODIFIED (MM/DD/YY) + sudsrini 02/18/05 - include stdlib + slari 08/08/01 - b1737025: move extern declaration + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + akatti 05/19/98 - [493012]:bug fix to prevent core dump + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + slari 04/19/95 - replace orlon with olog + skrishna 10/20/94 - Creation +*/ +/* + * -- cdemo6.cc -- + * An example program which illustrates how a C++ program + * can use the OCI interface to access ORACLE database. + * + * This program retrieves department name, given the + * department number. + * + * The program queries the user for data as follows: + * + * Enter department number: + * + * The program terminates if -1 is entered + * when the department number is requested. + */ +#include +#include +#include + +extern "C" +{ +#include +/* demo constants and structs */ +} + +#include +#include + +const text *username = (text *) "SCOTT"; +const text *password = (text *) "TIGER"; + +/* define SQL statements to be used in the program */ +const text *seldept = (text *) "SELECT dname FROM dept WHERE deptno = :1"; + +void err_report(FILE *file, text *errmsg, sword func_code); +void myfflush(); + +/* connection destructor */ +connection::~connection() +{ + // disconnect if connection exists + if (state == connected) + { + if (disconnect()) + { + display_error(stderr); + } + } +} + +/* connect to ORACLE */ +sword connection::connect(const text *username, const text *password) +{ + sword status; + + if (state == connected) + { + // this object is already connected + return (CONERR_ALRCON); + } + + if ((status = olog(&lda, hda, (text *) username, -1, + (text *)password, -1, (text *) 0, -1, + OCI_LM_DEF)) == 0) + { + // successful login + state = connected; + printf("Connected to ORACLE as %s\n", username); + } + + return (status); +} + +/* disconnect from ORACLE */ +sword connection::disconnect() +{ + sword status; + + if (state == not_connected) + { + // this object has not been connected + return (CONERR_NOTCON); + } + + if ((status = ologof(&lda)) == 0) + { + // successful logout + state = not_connected; + } + + return (status); +} + +/* write error message to the given file */ +void connection::display_error(FILE *file) const +{ + if (lda.rc != 0) + { + sword n; + text msg[512]; + + n = oerhms((cda_def *)&lda, lda.rc, msg, (sword) sizeof(msg)); + err_report(file, msg, lda.fc); + } +} + +/* cursor destructor */ +cursor::~cursor() +{ + if (state == opened) + { + if (close()) + display_error(stderr); + } +} + +/* open the cursor */ +sword cursor::open(connection *conn_param) +{ + sword status; + + if (state == opened) + { + // this cursor has already been opened + return (CURERR_ALROPN); + } + + if ((status = oopen(&cda, &conn_param->lda, (text *)0, -1, -1, + (text *)0, -1)) == 0) + { + // successfull open + state = opened; + conn = conn_param; + } + + return (status); +} + +/* close the cursor */ +sword cursor::close() +{ + sword status; + + if (state == not_opened) + { + // this cursor has not been opened + return (CURERR_NOTOPN); + } + + if ((status = oclose(&cda)) == 0) + { + // successful cursor close + state = not_opened; + conn = (connection *)0; + } + + return (status); +} + +/* write error message to the given file */ +void cursor::display_error(FILE *file) const +{ + if (cda.rc != 0) + { + sword n; + text msg[512]; + + n = oerhms(&conn->lda, cda.rc, msg, (sword) sizeof(msg)); + err_report(file, msg, cda.fc); + } +} + +int main() +{ + sword deptno; + sword len, dsize; + sb4 deptlen; + sb2 db_type; + sb1 name_buf[20]; + text *dept; + +/* + * Connect to ORACLE and open a cursor. + * Exit on any error. + */ + connection conn; + if (conn.connect(username, password)) + { + conn.display_error(stderr); + return(EXIT_FAILURE); + } + + cursor crsr; + if (crsr.open(&conn)) + { + crsr.display_error(stderr); + return(EXIT_FAILURE); + } + + /* parse the SELDEPT statement */ + if (crsr.parse(seldept)) + { + crsr.display_error(stderr); + return(EXIT_FAILURE); + } + + /* bind the placeholder in the SELDEPT statement */ + if (crsr.bind_by_position(1, (ub1 *) &deptno, (sword) sizeof(deptno), + INT_TYPE, -1, (sb2 *) 0)) + { + crsr.display_error(stderr); + return(EXIT_FAILURE); + } + + /* describe the select-list field "dname" */ + len = sizeof (name_buf); + if (crsr.describe(1, (sb4 *) &deptlen, &db_type, + name_buf, (sb4 *) &len, (sb4 *) &dsize, (sb2 *) 0, + (sb2 *) 0, (sb2 *) 0)) + { + crsr.display_error(stderr); + return(EXIT_FAILURE); + } + + /* allocate space for dept name now that you have length */ + dept = new text[(int) deptlen + 1]; + + /* define the output variable for the select-list */ + if (crsr.define_by_position(1, (ub1 *) dept, (sword)deptlen+1, + STRING_TYPE, -1, (sb2 *) 0, (ub2 *) 0, + (ub2 *) 0)) + { + crsr.display_error(stderr); + delete dept; + return(EXIT_FAILURE); + } + + for (;;) + { + /* prompt for department number, break if given number == -1 */ + printf("\nEnter department number (or -1 to EXIT): "); + while (scanf("%d", &deptno) != 1) + { + myfflush(); + printf("Invalid input, please enter a number (-1 to EXIT): "); + } + if (deptno == -1) + { + printf("Exiting... "); + break; + } + + /* display the name of the corresponding department */ + if (crsr.execute() || crsr.fetch()) + { + if (crsr.get_error_code() != NO_DATA_FOUND) + { + crsr.display_error(stderr); + delete dept; + return(EXIT_FAILURE); + } + else + printf( + "\n The department number that you entered doesn't exist.\n"); + } + else + { + printf("\n Department name = %s Department number = %d\n", + dept, deptno); + } + } + + delete dept; + printf ("\nG'day\n"); + + return 0; +} + + +void err_report(FILE *file, text *errmsg, sword func_code) +{ + fprintf(file, "\n-- ORACLE error--\n\n%s\n", errmsg); + if (func_code > 0) + fprintf(file, "Processing OCI function %s\n", + oci_func_tab[func_code]); +} + +void myfflush() +{ + eb1 buf[50]; + + fgets((char *) buf, 50, stdin); +} + + diff --git a/cdemo6.h b/cdemo6.h new file mode 100644 index 0000000..dd9392d --- /dev/null +++ b/cdemo6.h @@ -0,0 +1,117 @@ +/* + * $Header: cdemo6.h 08-aug-2001.16:30:28 slari Exp $ + */ + +/* Copyright (c) 1995, 2001, Oracle Corporation. All rights reserved. +*/ + +/* + NAME + cdemo6.h - header file for C++ Demo Program + MODIFIED (MM/DD/YY) + slari 08/08/01 - b1737025: move extern declaration + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + slari 04/25/95 - merge changes from branch 1.1.720.1 + slari 04/24/95 - Branch_for_patch + slari 04/21/95 - Creation +*/ + + +#include +#include +#include +#include + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* Class forward declarations */ +class connection; +class cursor; + +/* + * This class represents a connection to ORACLE database. + * + * NOTE: This connection class is just given as an example and all possible + * operations on a connection have not been defined. + */ +class connection +{ + friend class cursor; + public: + connection() + { state = not_connected; memset(hda,'\0', HDA_SIZE); } + ~connection(); + sword connect(const text *username, const text *password); + sword disconnect(); + void display_error(FILE* file) const; + private: + Lda_Def lda; + ub1 hda[HDA_SIZE]; + enum conn_state + { + not_connected, + connected + }; + conn_state state; +}; + +/* + * This class represents an ORACLE cursor. + * + * NOTE: This cursor class is just given as an example and all possible + * operations on a cursor have not been defined. + */ +class cursor +{ + public: + cursor() + {state = not_opened; conn = (connection *)0; } + ~cursor(); + sword open(connection *conn_param); + sword close(); + sword parse(const text *stmt) + { return (oparse(&cda, (text *)stmt, (sb4)-1, + DEFER_PARSE, (ub4) VERSION_7)); } + /* bind an input variable */ + sword bind_by_position(sword sqlvnum, ub1 *progvar, sword progvarlen, + sword datatype, sword scale, sb2 *indicator) + { return (obndrn(&cda, sqlvnum, progvar, progvarlen, datatype, scale, + indicator, (text *)0, -1, -1)); } + /* define an output variable */ + sword define_by_position(sword position, ub1 *buf, sword bufl, + sword datatype, sword scale, sb2 *indicator, + ub2 *rlen, ub2 *rcode) + { return (odefin(&cda, position, buf, bufl, datatype, scale, indicator, + (text *)0, -1, -1, rlen, rcode)); } + sword describe(sword position, sb4 *dbsize, sb2 *dbtype, sb1 *cbuf, + sb4 *cbufl, sb4 *dsize, sb2 *prec, sb2 *scale, sb2 *nullok) + { return (odescr(&cda, position, dbsize, dbtype, cbuf, cbufl, dsize, + prec, scale, nullok)); } + sword execute() + { return (oexec(&cda)); } + sword fetch() + { return (ofetch(&cda)); } + sword get_error_code() const + { return (cda.rc); } + void display_error( FILE* file) const; + private: + Cda_Def cda; + connection *conn; + enum cursor_state + { + not_opened, + opened + }; + cursor_state state; +}; + +/* + * Error number macros + */ +#define CONERR_ALRCON -1 /* already connected */ +#define CONERR_NOTCON -2 /* not connected */ +#define CURERR_ALROPN -3 /* cursor is already open */ +#define CURERR_NOTOPN -4 /* cursor is not opened */ diff --git a/cdemo81.c b/cdemo81.c new file mode 100644 index 0000000..f9db754 --- /dev/null +++ b/cdemo81.c @@ -0,0 +1,445 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemo81.c 14-apr-2006.10:55:52 lburgess Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1996, 2006, Oracle. All rights reserved. +*/ + +/* + + NAME + cdemo81.c - Basic OCI V8 functionality + + DESCRIPTION + + * An example program which adds new employee + * records to the personnel data base. Checking + * is done to insure the integrity of the data base. + * The employee numbers are automatically selected using + * the current maximum employee number as the start. + * + * The program queries the user for data as follows: + * + * Enter employee name: + * Enter employee job: + * Enter employee salary: + * Enter employee dept: + * + * The program terminates if return key (CR) is entered + * when the employee name is requested. + * + * If the record is successfully inserted, the following + * is printed: + * + * "ename" added to department "dname" as employee # "empno" + + Demonstrates creating a connection, a session and executing some SQL. + Also shows the usage of allocating memory for application use which has the + life time of the handle. + + MODIFIED (MM/DD/YY) + lburgess 04/14/06 - lowercase passwords + aliu 04/21/06 - use OCIEnvCreate and exit if it fails + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + dchatter 10/14/98 - add the usage of xtrmemsz and usrmempp + azhao 06/23/97 - Use OCIBindByPos, OCIBindByName; clean up + echen 12/17/96 - OCI beautification + dchatter 07/18/96 - delete spurious header files + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + mgianata 06/17/96 - change ociisc() to OCISessionBegin() + aroy 04/26/96 - change OCITransCommitt -> OCITransCommit + slari 04/24/96 - use OCITransCommitt + aroy 02/21/96 - fix bug in get descriptor handle call + lchidamb 02/20/96 - cdemo81.c converted for v8 OCI + lchidamb 02/20/96 - Creation + +*/ + + +#include +#include +#include +#include + +static text *username = (text *) "SCOTT"; +static text *password = (text *) "tiger"; + +/* Define SQL statements to be used in program. */ +static text *insert = (text *)"INSERT INTO emp(empno, ename, job, sal, deptno)\ + VALUES (:empno, :ename, :job, :sal, :deptno)"; +static text *seldept = (text *)"SELECT dname FROM dept WHERE deptno = :1"; +static text *maxemp = (text *)"SELECT NVL(MAX(empno), 0) FROM emp"; +static text *selemp = (text *)"SELECT ename, job FROM emp"; + +static OCIEnv *envhp; +static OCIError *errhp; + +static void checkerr(/*_ OCIError *errhp, sword status _*/); +static void cleanup(/*_ void _*/); +static void myfflush(/*_ void _*/); +int main(/*_ int argc, char *argv[] _*/); + +static sword status; + +int main(argc, argv) +int argc; +char *argv[]; +{ + + sword empno, sal, deptno; + sword len, len2, rv, dsize, dsize2; + sb4 enamelen = 10; + sb4 joblen = 9; + sb4 deptlen = 14; + sb2 sal_ind, job_ind; + sb2 db_type, db2_type; + sb1 name_buf[20], name2_buf[20]; + text *cp, *ename, *job, *dept; + + sb2 ind[2]; /* indicator */ + ub2 alen[2]; /* actual length */ + ub2 rlen[2]; /* return length */ + + OCIDescribe *dschndl1 = (OCIDescribe *) 0, + *dschndl2 = (OCIDescribe *) 0, + *dschndl3 = (OCIDescribe *) 0; + + OCISession *authp = (OCISession *) 0; + OCIServer *srvhp; + OCISvcCtx *svchp; + OCIStmt *inserthp, + *stmthp, + *stmthp1; + OCIDefine *defnp = (OCIDefine *) 0; + + OCIBind *bnd1p = (OCIBind *) 0; /* the first bind handle */ + OCIBind *bnd2p = (OCIBind *) 0; /* the second bind handle */ + OCIBind *bnd3p = (OCIBind *) 0; /* the third bind handle */ + OCIBind *bnd4p = (OCIBind *) 0; /* the fourth bind handle */ + OCIBind *bnd5p = (OCIBind *) 0; /* the fifth bind handle */ + OCIBind *bnd6p = (OCIBind *) 0; /* the sixth bind handle */ + + sword errcode = 0; + + errcode = OCIEnvCreate((OCIEnv **) &envhp, (ub4) OCI_DEFAULT, + (dvoid *) 0, (dvoid * (*)(dvoid *,size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t)) 0, + (void (*)(dvoid *, dvoid *)) 0, (size_t) 0, (dvoid **) 0); + + if (errcode != 0) { + (void) printf("OCIEnvCreate failed with errcode = %d.\n", errcode); + exit(1); + } + + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + + /* server contexts */ + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, OCI_HTYPE_SERVER, + (size_t) 0, (dvoid **) 0); + + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, OCI_HTYPE_SVCCTX, + (size_t) 0, (dvoid **) 0); + + (void) OCIServerAttach( srvhp, errhp, (text *)"", strlen(""), 0); + + /* set attribute server context in the service context */ + (void) OCIAttrSet( (dvoid *) svchp, OCI_HTYPE_SVCCTX, (dvoid *)srvhp, + (ub4) 0, OCI_ATTR_SERVER, (OCIError *) errhp); + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **)&authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0); + + (void) OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) username, (ub4) strlen((char *)username), + (ub4) OCI_ATTR_USERNAME, errhp); + + (void) OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) password, (ub4) strlen((char *)password), + (ub4) OCI_ATTR_PASSWORD, errhp); + + checkerr(errhp, OCISessionBegin ( svchp, errhp, authp, OCI_CRED_RDBMS, + (ub4) OCI_DEFAULT)); + + (void) OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) authp, (ub4) 0, + (ub4) OCI_ATTR_SESSION, errhp); + + checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp, + OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0)); + + checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp1, + OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0)); + + /* Retrieve the current maximum employee number. */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, maxemp, + (ub4) strlen((char *) maxemp), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + /* bind the input variable */ + checkerr(errhp, OCIDefineByPos(stmthp, &defnp, errhp, 1, (dvoid *) &empno, + (sword) sizeof(sword), SQLT_INT, (dvoid *) 0, (ub2 *)0, + (ub2 *)0, OCI_DEFAULT)); + + /* execute and fetch */ + if (status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL, OCI_DEFAULT)) + { + if (status == OCI_NO_DATA) + empno = 10; + else + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + } + + + /* + * When we bind the insert statement we also need to allocate the storage + * of the employee name and the job description. + * Since the lifetime of these buffers are the same as the statement, we + * will allocate it at the time when the statement handle is allocated; this + * will get freed when the statement disappears and there is less + * fragmentation. + * + * sizes required are enamelen+2 and joblen+2 to allow for \n and \0 + * + */ + + + checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &inserthp, + OCI_HTYPE_STMT, (size_t) enamelen + 2 + joblen + 2, + (dvoid **) &ename)); + job = (text *) (ename+enamelen+2); + + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, insert, + (ub4) strlen((char *) insert), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp1, errhp, seldept, + (ub4) strlen((char *) seldept), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + + /* Bind the placeholders in the INSERT statement. */ + if ((status = OCIBindByName(stmthp, &bnd1p, errhp, (text *) ":ENAME", + -1, (dvoid *) ename, + enamelen+1, SQLT_STR, (dvoid *) 0, + (ub2 *) 0, (ub2 *) 0, (ub4) 0, (ub4 *) 0, OCI_DEFAULT)) || + (status = OCIBindByName(stmthp, &bnd2p, errhp, (text *) ":JOB", + -1, (dvoid *) job, + joblen+1, SQLT_STR, (dvoid *) &job_ind, + (ub2 *) 0, (ub2 *) 0, (ub4) 0, (ub4 *) 0, OCI_DEFAULT)) || + (status = OCIBindByName(stmthp, &bnd3p, errhp, (text *) ":SAL", + -1, (dvoid *) &sal, + (sword) sizeof(sal), SQLT_INT, (dvoid *) &sal_ind, + (ub2 *) 0, (ub2 *) 0, (ub4) 0, (ub4 *) 0, OCI_DEFAULT)) || + (status = OCIBindByName(stmthp, &bnd4p, errhp, (text *) ":DEPTNO", + -1, (dvoid *) &deptno, + (sword) sizeof(deptno), SQLT_INT, (dvoid *) 0, + (ub2 *) 0, (ub2 *) 0, (ub4) 0, (ub4 *) 0, OCI_DEFAULT)) || + (status = OCIBindByName(stmthp, &bnd5p, errhp, (text *) ":EMPNO", + -1, (dvoid *) &empno, + (sword) sizeof(empno), SQLT_INT, (dvoid *) 0, + (ub2 *) 0, (ub2 *) 0, (ub4) 0, (ub4 *) 0, OCI_DEFAULT))) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + /* Bind the placeholder in the "seldept" statement. */ + if (status = OCIBindByPos(stmthp1, &bnd6p, errhp, 1, + (dvoid *) &deptno, (sword) sizeof(deptno),SQLT_INT, + (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) 0, (ub4 *) 0, OCI_DEFAULT)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + /* Allocate the dept buffer now that you have length. */ + /* the deptlen should eventually get from dschndl3. */ + deptlen = 14; + dept = (text *) malloc((size_t) deptlen + 1); + + /* Define the output variable for the select-list. */ + if (status = OCIDefineByPos(stmthp1, &defnp, errhp, 1, + (dvoid *) dept, deptlen+1, SQLT_STR, + (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, OCI_DEFAULT)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + for (;;) + { + /* Prompt for employee name. Break on no name. */ + printf("\nEnter employee name (or CR to EXIT): "); + fgets((char *) ename, (int) enamelen+1, stdin); + cp = (text *) strchr((char *) ename, '\n'); + if (cp == ename) + { + printf("Exiting... "); + cleanup(); + return OCI_SUCCESS; + } + if (cp) + *cp = '\0'; + else + { + printf("Employee name may be truncated.\n"); + myfflush(); + } + /* Prompt for the employee's job and salary. */ + printf("Enter employee job: "); + job_ind = 0; + fgets((char *) job, (int) joblen + 1, stdin); + cp = (text *) strchr((char *) job, '\n'); + if (cp == job) + { + job_ind = -1; /* make it NULL in table */ + printf("Job is NULL.\n");/* using indicator variable */ + } + else if (cp == 0) + { + printf("Job description may be truncated.\n"); + myfflush(); + } + else + *cp = '\0'; + + printf("Enter employee salary: "); + scanf("%d", &sal); + myfflush(); + sal_ind = (sal <= 0) ? -2 : 0; /* set indicator variable */ + + /* + * Prompt for the employee's department number, and verify + * that the entered department number is valid + * by executing and fetching. + */ + do + { + printf("Enter employee dept: "); + scanf("%d", &deptno); + myfflush(); + if ((status = OCIStmtExecute(svchp, stmthp1, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL, OCI_DEFAULT)) + && (status != OCI_NO_DATA)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + if (status == OCI_NO_DATA) + printf("The dept you entered doesn't exist.\n"); + } while (status == OCI_NO_DATA); + + /* + * Increment empno by 10, and execute the INSERT + * statement. If the return code is 1 (duplicate + * value in index), then generate the next + * employee number. + */ + empno += 10; + if ((status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL, OCI_DEFAULT)) + && status != 1) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + while (status == 1) + { + empno += 10; + if ((status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL, OCI_DEFAULT)) + && status != 1) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + } /* end for (;;) */ + + /* Commit the change. */ + if (status = OCITransCommit(svchp, errhp, 0)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + printf("\n\n%s added to the %s department as employee number %d\n", + ename, dept, empno); + } +} + + +void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", 512, errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} + + +/* + * Exit program with an exit code. + */ +void cleanup() +{ + if (envhp) + (void) OCIHandleFree((dvoid *) envhp, OCI_HTYPE_ENV); + return; +} + + +void myfflush() +{ + eb1 buf[50]; + + fgets((char *) buf, 50, stdin); +} + + +/* end of file cdemo81.c */ + diff --git a/cdemo82.c b/cdemo82.c new file mode 100644 index 0000000..75ae307 --- /dev/null +++ b/cdemo82.c @@ -0,0 +1,514 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemo82.c 04-apr-2005.17:08:37 lzhao Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1996, 2005, Oracle. All rights reserved. +*/ + +/* + + NAME + cdemo82.c - oci adt sample program ; run cdemo82.sql + + MODIFIED (MM/DD/YY) + lzhao 04/04/05 - bug4184289 + akatti 11/05/99 - [987191]:consider ret value of OCIDescribeAny + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 09/09/98 - lines longer than 79 chars reformatted - bug 722491 + svedala 02/17/98 - OCI obsoletion changes + echen 06/03/97 - fix name resolution problem + cchau 05/19/97 - change OCITypeByName to OCIDescribeAny + azhao 01/30/97 - fix lint error + azhao 01/11/97 - also check OCI_SUCCESS_WITH_INFO in fetch + echen 01/03/97 - remove obsoleve type + azhao 07/18/96 - use OCI_PIN_ANY,OCI_PIN_LATEST for ogiopin + dchatter 07/18/96 - change ifdef for including cdemo82.h + slari 07/15/96 - Creation + +*/ + +#ifndef CDEMO82_ORACLE +#include +#endif + +#include + +#define SCHEMA "CDEMO82" + + +/*****************************************************************************/ +static void pin_display_addr(envhp, errhp, addrref) +OCIEnv *envhp; +OCIError *errhp; +OCIRef *addrref; +{ + sword status; + address *addr = (address *)0; + + checkerr(errhp, OCIObjectPin(envhp, errhp, addrref, (OCIComplexObject *)0, + OCI_PIN_ANY, OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&addr)); + + if (addr) + { + printf("address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), OCIStringPtr(envhp, addr->zip)); + } + else + { + printf("Pinned address pointer is null\n"); + } + + checkerr(errhp, OCIObjectUnpin(envhp, errhp, (dvoid *) addr)); +} + +/*****************************************************************************/ +static void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + ub4 buflen; + ub4 errcode; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + printf("Error - OCI_NO_DATA\n"); + break; + case OCI_ERROR: + OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, (sb4 *)&errcode, + errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); + printf("Error - %s\n", errbuf); + break; + case OCI_INVALID_HANDLE: + printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} + +/*****************************************************************************/ +/* +** Execute "selvalstmt" statement which selects records +** from a table with an ADT. +*/ +static void selectval(envhp, svchp, stmthp, errhp) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIError *errhp; +{ + OCIType *addr_tdo = (OCIType *) 0; + OCIDefine *defn1p = (OCIDefine *) 0, *defn2p = (OCIDefine *) 0; + address *addr = (address *)NULL; + sword custno =0; + int i = 0; + OCIRef *addrref = (OCIRef *) 0; + OCIRef *type_ref = (OCIRef *) 0; + sb4 status; + OCIDescribe *dschp = (OCIDescribe *) 0; + OCIParam *parmp; + sword retval; + + /* allocate describe handle for OCIDescribeAny */ + checkerr(errhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **) &dschp, + (ub4) OCI_HTYPE_DESCRIBE, + (size_t) 0, (dvoid **) 0)); + + /* define the application request */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) selvalstmt, + (ub4) strlen((char *)selvalstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + /* bind the input variable */ + checkerr(errhp, OCIDefineByPos(stmthp, &defn1p, errhp, + (ub4) 1, (dvoid *) &custno, + (sb4) sizeof(sword), SQLT_INT, (dvoid *) 0, (ub2 *)0, + (ub2 *)0, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIDefineByPos(stmthp, &defn2p, errhp, (ub4) 2, (dvoid *) 0, + (sb4) 0, SQLT_NTY, (dvoid *) 0, (ub2 *)0, + (ub2 *)0, (ub4) OCI_DEFAULT)); + + /* checkerr(errhp, OCITypeByName(envhp, errhp, svchp, (const text *) 0, + (ub4) 0, (const text *) "ADDRESS_VALUE", + (ub4) strlen((const char *) "ADDRESS_VALUE"), + (CONST text *) 0, (ub4) 0, + OCI_DURATION_SESSION, OCI_TYPEGET_HEADER, + &addr_tdo)); */ + + /* Bug 987191 - if describe call fails, no OCIAttrGet on desc handle */ + if ((retval = OCIDescribeAny(svchp, errhp, (text *)"ADDRESS_VALUE", + (ub4) strlen((char *)"ADDRESS_VALUE"), OCI_OTYPE_NAME, + (ub1)1, (ub1) OCI_PTYPE_TYPE, dschp)) != OCI_SUCCESS) + { + if (retval == OCI_NO_DATA) + { + printf("NO DATA: OCIDescribeAny on ADDRESS_VALUE\n"); + } + else + { + printf( "ERROR: OCIDescribeAny on ADDRESS_VALUE\n"); + checkerr(errhp, retval); + return; + } + } + else + { + checkerr(errhp, OCIAttrGet((dvoid *) dschp, (ub4) OCI_HTYPE_DESCRIBE, + (dvoid *)&parmp, (ub4 *)0, (ub4)OCI_ATTR_PARAM, errhp)); + + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &type_ref, (ub4 *) 0, + (ub4) OCI_ATTR_REF_TDO, (OCIError *) errhp)); + } + + checkerr(errhp, OCIObjectPin(envhp, errhp, type_ref, (OCIComplexObject *) 0, + OCI_PIN_ANY, OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&addr_tdo)); + + if(!addr_tdo) + { + printf("NULL tdo returned\n"); + goto done_selectval; + } + + + checkerr(errhp, OCIDefineObject(defn2p, errhp, addr_tdo, (dvoid **) &addr, + (ub4 *) 0, (dvoid **) 0, (ub4 *) 0)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + + /* execute and fetch */ + do + { + if (addr) + printf("custno = %d address.state = %.2s address.zip = %.10s\n", custno, + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + else + printf("custno = %d fetched address is NULL\n", custno); + + addr = (address *)NULL; + } + while ((status = OCIStmtFetch(stmthp, errhp, (ub4) 1, (ub4) OCI_FETCH_NEXT, + (ub4) OCI_DEFAULT)) == OCI_SUCCESS || + status == OCI_SUCCESS_WITH_INFO); + + + if ( status!= OCI_NO_DATA ) + checkerr(errhp, status); + + printf("\n\n"); + + done_selectval: + + i = 0; /* dummy statement, need something after label */ +/* + checkerr(errhp, OCIHandleFree((dvoid *) defn1p, (ub4) OCI_HTYPE_DEFINE)); + checkerr(errhp, OCIHandleFree((dvoid *) defn2p, (ub4) OCI_HTYPE_DEFINE)); +*/ + +} + +/*****************************************************************************/ +/* +** Execute "selobjstmt" statement which selects records +** from a table with a ref. +*/ +static void selectobj(envhp, svchp, stmthp, errhp) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIError *errhp; +{ + OCIType *addr_tdo = (OCIType *) 0; + OCIDefine *defn1p = (OCIDefine *) 0, *defn2p = (OCIDefine *) 0; + sword status; + OCIRef *addrref = (OCIRef *) 0, *addrref1 = (OCIRef *) 0; + sword custno =0; + int i = 0; + address *addr; + ub4 ref_len; + + + /* define the application request */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) selobjstmt, + (ub4) strlen((char *)selobjstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIDefineByPos(stmthp, &defn1p, errhp, (ub4) 1, + (dvoid *) &custno, + (sb4) sizeof(sword), SQLT_INT, (dvoid *) 0, (ub2 *)0, + (ub2 *)0, (ub4) OCI_DEFAULT)); + + addrref = (OCIRef *)NULL; + checkerr(errhp, OCIDefineByPos(stmthp, &defn2p, errhp, (ub4) 2, + (dvoid *) NULL, + (sb4) 0, SQLT_REF, (dvoid *) 0, (ub2 *)0, + (ub2 *)0, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIDefineObject(defn2p, errhp, (OCIType *)NULL, + (dvoid **)&addrref, + &ref_len, (dvoid **)0, (ub4 *)0)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)); + + do + { + printf("custno = %d fetched address\n", custno); + + if ( addrref ) + { + pin_display_addr(envhp, errhp, addrref); + } + else + printf("Address ref is NULL\n"); + + } + while ((status = OCIStmtFetch(stmthp, errhp, (ub4) 1, (ub4) OCI_FETCH_NEXT, + (ub4) OCI_DEFAULT)) == OCI_SUCCESS || + status == OCI_SUCCESS_WITH_INFO); + + + if ( status != OCI_NO_DATA ) + checkerr(errhp, status); + + printf("\n\n"); +/* + checkerr(errhp, OCIHandleFree((dvoid *) defn1p, (ub4) OCI_HTYPE_DEFINE)); + checkerr(errhp, OCIHandleFree((dvoid *) defn2p, (ub4) OCI_HTYPE_DEFINE)); +*/ + +} + + +/*****************************************************************************/ +/* + ** execute "insstmt" + ** + */ +static void insert(envhp, svchp, stmthp, errhp, insstmt, nrows) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIError *errhp; +text *insstmt; +ub2 nrows; +{ + OCIType *addr_tdo = (OCIType *) 0; + address addrs; + null_address naddrs; + address *addr = &addrs; + null_address *naddr = &naddrs; + sword custno =300; + OCIBind *bnd1p = (OCIBind *) 0, *bnd2p = (OCIBind *) 0; + char buf[20]; + ub2 i; + OCIRef *type_ref = (OCIRef *) 0; + OCIDescribe *dschp = (OCIDescribe *) 0; + OCIParam *parmp; + sword retval; + + /* allocate describe handle for OCIDescribeAny */ + checkerr(errhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **) &dschp, + (ub4) OCI_HTYPE_DESCRIBE, + (size_t) 0, (dvoid **) 0)); + + /* define the application request */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) insstmt, + (ub4) strlen((char *)insstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + /* bind the input variable */ + checkerr(errhp, OCIBindByName(stmthp, &bnd1p, errhp, (text *) ":custno", + (sb4) -1, (dvoid *) &custno, + (sb4) sizeof(sword), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, (ub4) 0, (ub4 *) 0, + (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIBindByName(stmthp, &bnd2p, errhp, (text *) ":addr", + (sb4) -1, (dvoid *) 0, + (sb4) 0, SQLT_NTY, (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)); + + /* checkerr(errhp, OCITypeByName(envhp, errhp, svchp, (const text *) 0, + (ub4) 0, (const text *) "ADDRESS_VALUE", + (ub4) strlen((const char *) "ADDRESS_VALUE"), + (CONST text *) 0, (ub4) 0, + OCI_DURATION_SESSION, OCI_TYPEGET_HEADER, + &addr_tdo)); */ + + /* Bug 987191-if describe call fails, don't call OCIAttrGet on dsc handle */ + if ((retval = OCIDescribeAny(svchp, errhp, (text *)"ADDRESS_VALUE", + (ub4) strlen((char *)"ADDRESS_VALUE"), OCI_OTYPE_NAME, + (ub1)1, (ub1) OCI_PTYPE_TYPE, dschp)) != OCI_SUCCESS) + { + if (retval == OCI_NO_DATA) + { + printf("NO DATA: OCIDescribeAny on ADDRESS_VALUE\n"); + } + else + { + printf( "ERROR: OCIDescribeAny on ADDRESS_VALUE\n"); + checkerr(errhp, retval); + return; + } + } + else + { + checkerr(errhp, OCIAttrGet((dvoid *) dschp, (ub4) OCI_HTYPE_DESCRIBE, + (dvoid *)&parmp, (ub4 *)0, (ub4)OCI_ATTR_PARAM, errhp)); + + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &type_ref, (ub4 *) 0, + (ub4) OCI_ATTR_REF_TDO, (OCIError *) errhp)); + } + + checkerr(errhp, OCIObjectPin(envhp, errhp, type_ref, (OCIComplexObject *) 0, + OCI_PIN_ANY, OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&addr_tdo)); + + if(!addr_tdo) + { + printf("Null tdo returned\n"); + goto done_insert; + } + + checkerr(errhp, OCIBindObject(bnd2p, errhp, addr_tdo, (dvoid **) &addr, + (ub4 *) 0, (dvoid **) &naddr, (ub4 *) 0)); + + for(i = 0; i <= nrows; i++) + { + addr->state = (OCIString *) 0; + sprintf(buf, "%cA", 65+i%27); + checkerr(errhp, OCIStringAssignText(envhp, errhp, + (CONST text*) buf, 2, &addr->state)); + addr->zip = (OCIString *) 0; + sprintf(buf, "94%d ", i+455); + checkerr(errhp, OCIStringAssignText(envhp, errhp, (CONST text*) buf, 10, + &addr->zip)); + + naddr->null_adt = 0; + naddr->null_state = 0; + naddr->null_zip = 0; + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)); + } + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + done_insert: + + i = 0; /* dummy statement, need something after label */ + +/* + checkerr(errhp, OCIHandleFree((dvoid *) bnd1p, (ub4) OCI_HTYPE_BIND)); + checkerr(errhp, OCIHandleFree((dvoid *) bnd2p, (ub4) OCI_HTYPE_BIND)); +*/ + +} + +/*****************************************************************************/ +int main() +{ + OCIEnv *envhp; + OCIServer *srvhp; + OCIError *errhp; + OCISvcCtx *svchp; + OCIStmt *stmthp; + OCISession *usrhp; + + OCIInitialize((ub4) OCI_THREADED | OCI_OBJECT, (dvoid *)0, + (dvoid * (*)()) 0, (dvoid * (*)()) 0, (void (*)()) 0 ); + + OCIHandleAlloc( (dvoid *) NULL, (dvoid **) &envhp, (ub4) OCI_HTYPE_ENV, + 52, (dvoid **) &tmp); + + OCIEnvInit( &envhp, (ub4) OCI_DEFAULT, 21, (dvoid **) &tmp ); + + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, (ub4) OCI_HTYPE_ERROR, + 52, (dvoid **) &tmp); + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, (ub4) OCI_HTYPE_SERVER, + 52, (dvoid **) &tmp); + + OCIServerAttach( srvhp, errhp, (text *) 0, (sb4) 0, (ub4) OCI_DEFAULT); + + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, (ub4) OCI_HTYPE_SVCCTX, + 52, (dvoid **) &tmp); + + /* set attribute server context in the service context */ + OCIAttrSet( (dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, + (ub4) OCI_ATTR_SERVER, (OCIError *) errhp); + + /* allocate a user context handle */ + OCIHandleAlloc((dvoid *)envhp, (dvoid **)&usrhp, (ub4) OCI_HTYPE_SESSION, + (size_t) 0, (dvoid **) 0); + + OCIAttrSet((dvoid *)usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"cdemo82", (ub4)strlen((char *)"cdemo82"), + OCI_ATTR_USERNAME, errhp); + + OCIAttrSet((dvoid *)usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"cdemo82", (ub4)strlen((char *)"cdemo82"), + OCI_ATTR_PASSWORD, errhp); + + checkerr(errhp, OCISessionBegin (svchp, errhp, usrhp, + OCI_CRED_RDBMS, OCI_DEFAULT)); + + OCIAttrSet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)usrhp, (ub4)0, + OCI_ATTR_SESSION, errhp); + + checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp, + (ub4) OCI_HTYPE_STMT, 50, (dvoid **) &tmp)); + + /* execute "insstmt" */ + printf("--- Test insertion into extent table.\n"); + insert(envhp, svchp, stmthp, errhp, insstmt, 26); + + /* execute "selstmt" */ + printf("--- Test selection of a table with one ADT column.\n"); + selectval(envhp, svchp, stmthp, errhp); + + + /* execute "selobjstmt" */ + printf("--- Test selection of a table with one ADT REF.\n"); + selectobj(envhp, svchp, stmthp, errhp); + + + checkerr(errhp, OCIHandleFree((dvoid *) stmthp, (ub4) OCI_HTYPE_STMT)); + + OCISessionEnd(svchp, errhp, usrhp, (ub4)OCI_DEFAULT); + OCIServerDetach( srvhp, errhp, (ub4) OCI_DEFAULT ); + checkerr(errhp, OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER)); + checkerr(errhp, OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX)); + checkerr(errhp, OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR)); + +} + +/* end of file cdemo82.c */ + diff --git a/cdemo82.h b/cdemo82.h new file mode 100644 index 0000000..6b34eac --- /dev/null +++ b/cdemo82.h @@ -0,0 +1,155 @@ +/* + * $Header: cdemo82.h 07-jun-2005.11:41:35 aliu Exp $ + */ + +/* Copyright (c) 1996, 2005, Oracle. All rights reserved. +*/ + +/* + NAME + cdemo82.h - header file for oci adt sample program + + MODIFIED (MM/DD/YY) + aliu 06/06/05 - fix lrg 1844051 + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + echen 06/03/97 - fix name resolution problem + azhao 01/30/97 - fix lint error + echen 01/03/97 - remove obsoleve type + azhao 07/18/96 - not to include s.h + dchatter 07/18/96 - delete spurious .h files + slari 07/15/96 - Creation + +*/ + + +#ifndef CDEMO82_ORACLE +# define CDEMO82_ORACLE + +#ifndef OCI_ORACLE +#include +#endif + +/*--------------------------------------------------------------------------- + PUBLIC TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ +#define SERVER "ORACLE" +#define ADDRESS_TYPE_NAME "ADDRESS_OBJECT" +#define EMB_ADDRESS_TYPE_NAME "EMBEDDED_ADDRESS" +#define ADDREXT "ADDREXT" +#define EMBADDREXT "EMBADDREXT" +#define RETURN_ON_ERROR(error) if (error) return (error) +#define BIG_RECORD_SIZE 1000 + + + +struct address +{ + OCIString *state; + OCIString *zip; +}; +typedef struct address address; + +struct null_address +{ + sb4 null_adt; + sb4 null_state; + sb4 null_zip; +}; +typedef struct null_address null_address; + +struct embaddress +{ + OCIString *state; + OCIString *zip; + OCIRef *preaddrref; +}; +typedef struct embaddress embaddress; + + +struct null_embaddress +{ + sb4 null_state; + sb4 null_zip; + sb4 null_preaddrref; +}; +typedef struct null_embaddress null_embaddress; + +struct person +{ + OCIString *name; + OCINumber age; + address addr; +}; +typedef struct person person; + +struct null_person +{ + sb4 null_name; + sb4 null_age; + null_address null_addr; +}; + +typedef struct null_person null_person; + +static const text *const names[] = +{(text *) "CUSTOMERVAL", (text *) "ADDRESS", (text *) "STATE"}; + +static const text *const selvalstmt = (text *) + "SELECT custno, addr FROM customerval order by custno, addr.zip"; + +static const text *const selobjstmt = (text *) + "SELECT custno, addr FROM customerobj order by custno, addr.zip"; + +static const text *const selref = (text *) + "SELECT REF(e) from extaddr e"; + +static const text *const deleteref = (text *) + "DELETE extaddr"; + +static const text *const insertref = (text *) +"insert into extaddr values(address_object('CA', '98765'))"; + +static const text *const modifyref = (text *) +"update extaddr set object_column = address_object('TX', '61111')"; + +static const text *const selembref = (text *) + "SELECT REF(emb) from embextaddr emb"; + +static const text *const bndref = (text *) +"update extaddr set object_column.state = 'GA' where object_column = :addrref"; + +static const text *const insstmt = +(text *)"INSERT INTO customerval (custno, addr) values (:custno, :addr)"; + +dvoid *tmp; + + +/*--------------------------------------------------------------------------- + PUBLIC FUNCTIONS + ---------------------------------------------------------------------------*/ +OCIRef *cbfunc(/*_ dvoid *context _*/); + +/*--------------------------------------------------------------------------- + PRIVATE FUNCTIONS + ---------------------------------------------------------------------------*/ +static void checkerr(/*_ OCIError *errhp, sword status _*/); +static void selectval(/*_ OCIEnv *envhp, OCISvcCtx *svchp, + OCIStmt *stmthp, OCIError *errhp _*/); +static void selectobj(/*_ OCIEnv *envhp, OCISvcCtx *svchp, + OCIStmt *stmthp, OCIError *errhp _*/); +static void insert(/*_ OCIEnv *envhp, OCISvcCtx *svchp, + OCIStmt *stmthp, OCIError *errhp, + text *insstmt, ub2 nrows _*/); + +static void pin_display_addr(/*_ OCIEnv *envhp, OCIError *errhp, + OCIRef *addrref _*/); + +int main(/*_ void _*/); + + + +#endif /* cdemo82 */ diff --git a/cdemo82.sql b/cdemo82.sql new file mode 100644 index 0000000..1d1e582 --- /dev/null +++ b/cdemo82.sql @@ -0,0 +1,132 @@ +rem +rem $Header: cdemo82.sql 18-jun-2004.14:31:26 stsun Exp $ +rem +rem cdemo82.sql +rem +rem Copyright (c) 1996, 2004, Oracle. All rights reserved. +rem +rem NAME +rem cdemo82.sql - sql to be executed before cdemo82 +rem +rem DESCRIPTION +rem +rem +rem NOTES +rem +rem +rem MODIFIED (MM/DD/YY) +rem stsun 06/18/04 - system/manager instead of sysdba +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem svedala 09/11/98 - a "/" required after create type - bug 717842 +rem cchau 08/18/97 - enable dictionary protection +rem echen 06/03/97 - fix name resolution problem +rem azhao 04/02/97 - add as object for create type +rem dchatter 07/19/96 - scott/tiger to cdemo82/cdemo82 +rem slari 07/15/96 - Created +rem + +REMARK >>>> Set System Variables For Current SQLPlus Session <<<< +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET PAGESIZE 100 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET DEFINE '^' + +set echo on; + +connect system/manager; + +drop user cdemo82 cascade; + +create user cdemo82 identified by cdemo82; + +grant connect, resource to cdemo82; + +connect cdemo82/cdemo82; + +drop table customerval; + +drop table customerobj; + +drop table extaddr; + +drop table embextaddr; + +drop type embedded_address; + +drop type address_object; + +drop type person; + +drop table emp; + +create type address_object as object (state char(2), zip char(10)); +/ + +create type embedded_address as object (state char(2), zip char(10), + preaddr REF address_object); +/ + +drop type address_value; + +create type address_value as object (state char(2), zip char(10)); +/ + +create table customerval (custno number, addr address_value); + +insert into customerval values(100, address_value('CA', '94065')); + +create table extaddr of address_object; + +create table customerobj (custno number, addr REF address_object); + +insert into extaddr values (address_object('CA', '94065')); + +insert into customerobj values(1000, null); + +update customerobj + set addr = (select ref(e) from extaddr e where e.zip='94065'); + +insert into extaddr values (address_object('CA', '98765')); + +insert into extaddr values (address_object('CA', '95117')); + +select REFTOHEX(ref(e)) from extaddr e; + +create table embextaddr of embedded_address; + +insert into embextaddr values (embedded_address('CA', '95117', NULL)); + +drop table extper; + +drop table empref; + +drop table emp; + +drop type person; + +create type person as object ( name char(20), age number, + address address_object ); +/ + +create table emp (emp_id number, emp_info person); + +create table empref (emp_id number, emp_info REF person); + +create table extper of person; + +create or replace procedure upd_addr(addr IN OUT address_object) is +begin + addr.state := 'CA'; + addr.zip := '95117'; +end; +/ + +commit; + +set echo off; + + + diff --git a/cdemoanydata1.c b/cdemoanydata1.c new file mode 100644 index 0000000..689e6e5 --- /dev/null +++ b/cdemoanydata1.c @@ -0,0 +1,775 @@ +/* Copyright (c) 2001, 2002, Oracle Corporation. All rights reserved. */ + +/* + + NAME + cdemoAnyData1.c - OCI demo program for ANYDATA. + + DESCRIPTION + An example program which inserts and selects rows of data to + and from anydatatab. + Rows are inserted into anydatatab by converting to ANYDATA + from the following types: NUMBER, VARCHAR2, DATE, + ADDRESS_OBJECT, CHAR, RAW, and COLLECTION in the above oder. + Then rows are fetched and COL2 accessed from ANYDATA + in the same order. + SQL> describe anydatatab; + Name Null? Type + ------------------------- -------- --------------- + COL1 NUMBER + COL2 SYS.ANYDATA + SQL> describe address_object; + Name Null? Type + ------------------------- -------- --------------- + STATE VARCHAR2(3) + ZIP VARCHAR2(13) + + EXPORT FUNCTION(S) + + + INTERNAL FUNCTION(S) + + + STATIC FUNCTION(S) + + + NOTES + Dependent Files: + cdemoAnyData1.sql - SQL script to be run before execution. + + MODIFIED (MM/DD/YY) + jchai 06/13/02 - fix bug 2360431 + ani 09/17/01 - OCIAnyDataAccess changes for Number,Date + ani 04/30/01 - Merged ani_ocidemo + ani 04/24/01 - Creation + +*/ + +#include +#include +#include + +#ifndef OCI_ORACLE +#include +#endif + +#define BUFLEN 20 +#define ADDR_SETNOTNULL(nind) (memset(nind, (char)0, 3*sizeof(OCIInd))); + +typedef struct cdemoanctx +{ + OCIEnv *envhp; + OCIServer *srvhp; + OCISvcCtx *svchp; + OCIError *errhp; + OCISession *authp; + OCIStmt *stmthp; +} cdemoanctx; + +struct address +{ + OCIString *state; /* text state[3]; */ + OCIString *zip; /* text zip[11]; */ +}; +typedef struct address address; + +struct null_address +{ + sb2 null_address; + sb2 null_state; + sb2 null_zip; +}; +typedef struct null_address null_address; + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ +static text *username = (text *) "scott"; +static text *password = (text *) "tiger"; + +/* Define SQL statements to be used in program. */ +static text *inst1 = (text *)"INSERT INTO anydatatab VALUES (:first_col, :oan_buffer)"; +static text *sel1 = (text *)"SELECT * FROM anydatatab WHERE col1 = "; + +/*--------------------------------------------------------------------------- + STATIC FUNCTION DECLARATIONS + ---------------------------------------------------------------------------*/ +static void initialize(cdemoanctx *ctxptr); +static void create_table(cdemoanctx *ctxptx); +static void drop_table(cdemoanctx *ctxptx); +static void sql_exec_insert(/*_ cdemoanctx *ctxptr, ub2 typecode, ub4 index _*/); +static void sql_exec_select(/*_ cdemoanctx *ctxptr, OCITypeCode typecode, ub4 recnum _*/); +static void cleanup(cdemoanctx *ctxptr); +static void checkerr(OCIError *errhp, sword status); +int main(); + + +int main() +{ + cdemoanctx ctx; + + printf("\n ######## start executing test ############ \n"); + + initialize(&ctx); + + /* execute sql statement */ + sql_exec_insert(&ctx, OCI_TYPECODE_NUMBER, 1); + sql_exec_insert(&ctx, OCI_TYPECODE_VARCHAR2, 2); + sql_exec_insert(&ctx, OCI_TYPECODE_DATE, 3); + sql_exec_insert(&ctx, OCI_TYPECODE_OBJECT, 4); + sql_exec_insert(&ctx, OCI_TYPECODE_CHAR, 5); + sql_exec_insert(&ctx, OCI_TYPECODE_RAW, 6); + sql_exec_insert(&ctx, OCI_TYPECODE_NAMEDCOLLECTION, 7); + + sql_exec_select(&ctx, OCI_TYPECODE_NUMBER, 1); + sql_exec_select(&ctx, OCI_TYPECODE_VARCHAR2, 2); + sql_exec_select(&ctx, OCI_TYPECODE_DATE, 3); + sql_exec_select(&ctx, OCI_TYPECODE_OBJECT, 4); + sql_exec_select(&ctx, OCI_TYPECODE_CHAR, 5); + sql_exec_select(&ctx, OCI_TYPECODE_RAW, 6); + sql_exec_select(&ctx, OCI_TYPECODE_NAMEDCOLLECTION, 7); + + /* clean things up before exhit */ + cleanup(&ctx); + return 1; + +} /*end main*/ + + +/********************************************************************* + * execute insert statement * + * This function converts data of given type specified by parameter * + * "typecode" to OCIANYDATA, then insert OCIANYDATA into datatabase * + * table named anydatatab. * + *********************************************************************/ +void sql_exec_insert(ctxptr, typecode, index) +cdemoanctx *ctxptr; +ub2 typecode; +ub4 index; +{ + OCIBind *bndp1 = (OCIBind *) NULL; + OCIBind *bndp2 = (OCIBind *) NULL; + + OCIType *any_tdo = (OCIType *)0; + OCIInd indp = OCI_IND_NOTNULL; + OCIInd *any_indp = (OCIInd *)0; + OCIAnyData *oan_buffer = (OCIAnyData *)0; + OCIType *addr_tdo = (OCIType *)0; + dvoid *addr = (dvoid *)0; + address *addr_obj = (address *)0; + + ub4 first_col = index; + ub4 any_number, i; + OCINumber num; + OCIString *str = (OCIString *) 0; + OCIDate date; + + OCIDuration dur; + OCIParam *type_info = (OCIParam *)0; + OCIRaw *raw_col = (OCIRaw *)0; + ub1* raw_ptr; + ub1 lbuf1[BUFLEN]; + dvoid *nind = (dvoid *)0; + /*text zip[6] = "00000";*/ + char zip[6] = "00000"; + + OCITable *addr_tab = (OCITable *) 0; + OCIType *addr_tab_tdo = (OCIType *)0; + sb4 collsiz; + /*address *addr = (address *)0, *addr2 = (address *)0;*/ + boolean exist; + /*sb4 index;*/ + dvoid *elem = (dvoid *)0; + dvoid *elemind = (dvoid *)0; + OCIInd *addr_tab_null=(OCIInd *)0; + address *addr_coll[3]; + + + printf("Testing INSERT ... \n"); + + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, + ctxptr->errhp, inst1, (ub4) strlen((char *)inst1), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCITypeByName(ctxptr->envhp, + ctxptr->errhp, ctxptr->svchp, + (CONST text *)"SYS", (ub4) strlen("SYS"), + (CONST text *) "ANYDATA", (ub4) strlen("ANYDATA"), + (CONST text *) 0, (ub4) 0, OCI_DURATION_SESSION, + OCI_TYPEGET_ALL, &any_tdo)); + checkerr(ctxptr->errhp, OCITypeByName(ctxptr->envhp, + ctxptr->errhp, ctxptr->svchp, + (CONST text *)"", (ub4) strlen(""), + (CONST text *) "ADDRESS_OBJECT", + (ub4) strlen("ADDRESS_OBJECT"), + (CONST text *) 0, (ub4) 0, OCI_DURATION_SESSION, + OCI_TYPEGET_ALL, &addr_tdo)); + + /* prepare data for insertion */ + switch (typecode) + { + case OCI_TYPECODE_NUMBER: + any_number = 10; + checkerr(ctxptr->errhp, OCINumberFromInt(ctxptr->errhp, + &any_number, sizeof(any_number), + OCI_NUMBER_UNSIGNED, &num)); + + checkerr(ctxptr->errhp, OCIAnyDataConvert(ctxptr->svchp, + ctxptr->errhp, (OCITypeCode)OCI_TYPECODE_NUMBER, + (OCIType *)0, OCI_DURATION_SESSION, (dvoid *)&indp, + (dvoid *)&num, 0, &oan_buffer)); + break; + + case OCI_TYPECODE_VARCHAR2: + OCIStringAssignText(ctxptr->envhp, ctxptr->errhp, + (text *)"TestString", 10, &str); + checkerr(ctxptr->errhp, OCIAnyDataConvert(ctxptr->svchp, + ctxptr->errhp,(OCITypeCode)OCI_TYPECODE_VARCHAR2, + (OCIType *)0, OCI_DURATION_SESSION, (dvoid *)&indp, + (dvoid *) str, 0, &oan_buffer)); + break; + + case OCI_TYPECODE_DATE: + OCIDateSetDate((OCIDate *) &date, (sb2)2000, (ub1) 7, (ub1)31); + checkerr(ctxptr->errhp, OCIAnyDataConvert(ctxptr->svchp, + ctxptr->errhp, (OCITypeCode)OCI_TYPECODE_DATE, + (OCIType *)0, OCI_DURATION_SESSION, (dvoid *)&indp, + (dvoid *)&date, 0, &oan_buffer)); + break; + + case OCI_TYPECODE_CHAR: + OCIStringAssignText(ctxptr->envhp, ctxptr->errhp, + (text *)"CHARString", 10, &str); + checkerr(ctxptr->errhp, OCIAnyDataConvert(ctxptr->svchp, + ctxptr->errhp,(OCITypeCode)OCI_TYPECODE_CHAR, + (OCIType *)0, OCI_DURATION_SESSION, (dvoid *)&indp, + (dvoid *) str, 0, &oan_buffer)); + break; + + case OCI_TYPECODE_OBJECT: + if ( OCIObjectNew(ctxptr->envhp, ctxptr->errhp, + ctxptr->svchp, OCI_TYPECODE_OBJECT, + addr_tdo, (dvoid *) 0, + OCI_DURATION_DEFAULT, TRUE, + (dvoid **) &addr_obj) != OCI_SUCCESS) + { + printf("object new error \n"); + exit(0); /*no point of proceeding */ + } + + OCIStringAssignText(ctxptr->envhp, ctxptr->errhp, + (text *)"NV", 2, &addr_obj->state); + OCIStringAssignText(ctxptr->envhp, ctxptr->errhp, + (text *)"11111", 5, &addr_obj->zip); + + OCIObjectGetInd(ctxptr->envhp, ctxptr->errhp, (dvoid *)addr_obj, &nind); + ADDR_SETNOTNULL(nind); + + checkerr(ctxptr->errhp, OCIAnyDataConvert(ctxptr->svchp, + ctxptr->errhp, OCI_TYPECODE_OBJECT, + addr_tdo, OCI_DURATION_SESSION, (dvoid *)nind, + addr_obj, 0, &oan_buffer)); + break; + + case OCI_TYPECODE_RAW: + for (i = 0; i < BUFLEN; i++) + lbuf1[i] = (ub1) 'R'; + checkerr(ctxptr->errhp, OCIRawAssignBytes(ctxptr->envhp, + ctxptr->errhp, lbuf1, BUFLEN, &raw_col)); + checkerr(ctxptr->errhp, OCIAnyDataConvert(ctxptr->svchp, + ctxptr->errhp, (OCITypeCode)OCI_TYPECODE_RAW, + (OCIType *)0, OCI_DURATION_SESSION, (dvoid *)&indp, + (dvoid *) raw_col, 0, &oan_buffer)); + break; + + case OCI_TYPECODE_NAMEDCOLLECTION: + checkerr(ctxptr->errhp, OCITypeByName(ctxptr->envhp, + ctxptr->errhp, ctxptr->svchp, + (CONST text *)"", (ub4) strlen(""), + (const text *) "ADDR_TAB", + (ub4) strlen((const char *) "ADDR_TAB"), + (CONST text *) 0, (ub4) 0, OCI_DURATION_SESSION, + OCI_TYPEGET_ALL, &addr_tab_tdo)); + + checkerr(ctxptr->errhp, OCIObjectNew(ctxptr->envhp, ctxptr->errhp, + ctxptr->svchp, OCI_TYPECODE_NAMEDCOLLECTION, + addr_tab_tdo, (dvoid *) 0, + OCI_DURATION_DEFAULT, TRUE, + (dvoid **) &addr_tab)); + + for(i=0;i<3;i++) { + addr_coll[i] = (address *) 0; + checkerr(ctxptr->errhp, OCIObjectNew(ctxptr->envhp, ctxptr->errhp, + ctxptr->svchp, OCI_TYPECODE_OBJECT, addr_tdo, (dvoid *) 0, + OCI_DURATION_DEFAULT, TRUE, (dvoid **) &addr_coll[i])); + OCIStringAssignText(ctxptr->envhp, ctxptr->errhp, + (text *)"CA", 2, &addr_coll[i]->state); + (void) sprintf((char *) zip, "%s%d", "9406", i); + OCIStringAssignText(ctxptr->envhp, ctxptr->errhp, + (text *) zip, 5, &addr_coll[i]->zip); + checkerr(ctxptr->errhp, OCICollAppend(ctxptr->envhp, ctxptr->errhp, + addr_coll[i], addr_tab_null, (OCIColl *)addr_tab)); + } + + OCIObjectGetInd(ctxptr->envhp, ctxptr->errhp, (dvoid *)addr_tab, &nind); + ADDR_SETNOTNULL(nind); + + checkerr(ctxptr->errhp, OCIAnyDataConvert(ctxptr->svchp, + ctxptr->errhp, OCI_TYPECODE_NAMEDCOLLECTION, + addr_tab_tdo, OCI_DURATION_SESSION, (dvoid *)nind, + addr_tab, 0, &oan_buffer)); + + break; + } + + /* + * associate items in insert statement with output buffer variables + */ + checkerr(ctxptr->errhp,OCIBindByName(ctxptr->stmthp,&bndp1, + ctxptr->errhp, (text *) ":first_col", (sb4) -1, + (dvoid*) &first_col, (sb4) sizeof(sword), (ub2)SQLT_INT, + (dvoid*) 0, (ub2 *) 0, (ub2 *) 0, (ub4) 0, (ub4 *) 0, + (ub4) OCI_DEFAULT)); + checkerr(ctxptr->errhp, OCIBindByName(ctxptr->stmthp, &bndp2, + ctxptr->errhp, (text *) ":oan_buffer", (sb4)-1, + (dvoid *)0, (sb4) 0, (ub2)SQLT_NTY, (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4) 0, (ub4 *) 0, (ub4)OCI_DEFAULT)); + checkerr(ctxptr->errhp, OCIBindObject(bndp2, ctxptr->errhp, + any_tdo, (dvoid **) &oan_buffer, (ub4 *) 0, + (dvoid **)&any_indp, (ub4 *) 0)); + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, + ctxptr->stmthp, ctxptr->errhp, + (ub4)1, (ub4)0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4)OCI_DEFAULT)); + + OCIAnyDataDestroy(ctxptr->svchp, ctxptr->errhp, oan_buffer); + +} /* end sql_exe_insert() */ + + +/********************************************************************* + * execute select statement * + * This function selects OCIANYDATA from table anydatatab, retrieves * + * the type information from resulting OCIANYDATA and accesses data * + * according to the type using OCIANYDATACCESS(). + *********************************************************************/ +void sql_exec_select(ctxptr, typecode, recnum) +cdemoanctx *ctxptr; +OCITypeCode typecode; +ub4 recnum; +{ + sword col1; + OCIDefine *defnp1 = (OCIDefine *) NULL; + OCIDefine *defnp2 = (OCIDefine *) NULL; + + OCIType *any_tdo = (OCIType *)0; + OCIType *addr_tdo = (OCIType *)0; + address *addr_obj = (address *)0; + OCIType *type = (OCIType *)0; + OCITypeCode tc; + OCIInd indp; + OCIInd *any_indp = (OCIInd *) 0; + + OCIAnyData *oan_buffer = (OCIAnyData *)0; + ub4 len, col2, i; + OCINumber num; + OCINumber *num_ptr = # + OCIString *str = (OCIString *) 0; + OCIDate date; + OCIDate *date_ptr = &date; + text sel_stmt[200]; + sb2 year1; + ub1 month1, day1; + OCIRaw *raw_col = (OCIRaw *)0; + ub1 *raw_ptr = (ub1 *)0; + + OCITable *addr_tab = (OCITable *) 0; + OCIType *addr_tab_tdo = (OCIType *)0; + sb4 collsiz; + address *addr = (address *)0, *addr2 = (address *)0; + boolean exist; + sb4 index; + dvoid *elem = (dvoid *)0; + dvoid *elemind = (dvoid *)0; + + OCIInd ind2=OCI_IND_NOTNULL; + OCIInd *ind2p = &ind2; + + + checkerr(ctxptr->errhp, OCITypeByName(ctxptr->envhp, + ctxptr->errhp, ctxptr->svchp, + (const text *) "", (ub4) strlen((const char *) ""), + (const text *) "ADDRESS_OBJECT", + (ub4) strlen((const char *) "ADDRESS_OBJECT"), + (CONST text *) 0, (ub4) 0, + OCI_DURATION_SESSION, OCI_TYPEGET_ALL, &addr_tdo)); + + (void) sprintf((char *) sel_stmt, "%s%d", sel1, recnum); + + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, + ctxptr->errhp, sel_stmt, (ub4) strlen((char *)sel_stmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("Testing SELECT ... \n"); + + checkerr(ctxptr->errhp, OCITypeByName(ctxptr->envhp, + ctxptr->errhp, ctxptr->svchp, + (CONST text *)"SYS", (ub4) strlen("SYS"), + (CONST text *) "ANYDATA", (ub4) strlen("ANYDATA"), + (CONST text *) 0, (ub4) 0, OCI_DURATION_SESSION, + OCI_TYPEGET_ALL, &any_tdo)); + /* + * associate items in select statement with output buffer variables + */ + checkerr(ctxptr->errhp,OCIDefineByPos(ctxptr->stmthp, &defnp1, + ctxptr->errhp,(ub4) 1,(dvoid*) &col1, + (sb4) sizeof(col1), (ub2)SQLT_INT, (dvoid*) 0, + (ub2 *) 0, (ub2 *) 0, OCI_DEFAULT)); + checkerr(ctxptr->errhp, OCIDefineByPos(ctxptr->stmthp, &defnp2, + ctxptr->errhp, (ub4)2, (dvoid *)0, + (sb4) 0, (ub2)SQLT_NTY, (dvoid *)0, + (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT)); + checkerr(ctxptr->errhp, OCIDefineObject(defnp2, + ctxptr->errhp, any_tdo, + (dvoid **) &oan_buffer, (ub4 *) 0, + (dvoid **)&any_indp, (ub4 *) 0)); + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, ctxptr->stmthp, + ctxptr->errhp, (ub4)1, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + (ub4)OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIAnyDataGetType(ctxptr->svchp, + ctxptr->errhp, (OCIAnyData *)oan_buffer, + (OCITypeCode *)&tc, (OCIType **)&type)); + + if(tc != typecode) + printf("ERROR: OCIAnyDataGetType retrieved wrong type information\n"); + + /* print out results */ + printf("Printing out select stmt results ... \n"); + printf("c1 is: %d\n",col1); + + switch (typecode) + { + case OCI_TYPECODE_NUMBER: + /*checkerr(ctxptr->errhp, + OCIAnyDataAccess(ctxptr->svchp, ctxptr->errhp, + oan_buffer, (OCITypeCode)OCI_TYPECODE_NUMBER, + (OCIType *)0, (dvoid *)&indp, (dvoid *)&num, &len)); + OCINumberToInt(ctxptr->errhp, &num, sizeof(col2), 0, &col2); */ + + checkerr(ctxptr->errhp, OCIAnyDataAccess(ctxptr->svchp, ctxptr->errhp, + oan_buffer, (OCITypeCode)OCI_TYPECODE_NUMBER, + (OCIType *)0, (dvoid *)&indp, (dvoid **)&num_ptr, &len)); + OCINumberToInt(ctxptr->errhp, num_ptr, sizeof(col2), 0, &col2); + + printf("c2 is: %d\n",col2); + break; + + case OCI_TYPECODE_VARCHAR2: + checkerr(ctxptr->errhp, OCIAnyDataAccess(ctxptr->svchp, ctxptr->errhp, + oan_buffer, (OCITypeCode)OCI_TYPECODE_VARCHAR2, + (OCIType *)0, (dvoid *)&indp, (dvoid *)&str, &len)); + + printf("c2 is %s \n", OCIStringPtr(ctxptr->envhp, str)); + break; + + case OCI_TYPECODE_DATE: + /*checkerr(ctxptr->errhp, OCIAnyDataAccess(ctxptr->svchp, + ctxptr->errhp, oan_buffer, + (OCITypeCode)OCI_TYPECODE_DATE, + (OCIType *)0, (dvoid *)&indp, (dvoid *)&date, &len)); + OCIDateGetDate( (CONST OCIDate *) &date, &year1, &month1, &day1 ); */ + + checkerr(ctxptr->errhp, OCIAnyDataAccess(ctxptr->svchp, + ctxptr->errhp, oan_buffer, + (OCITypeCode)OCI_TYPECODE_DATE, + (OCIType *)0, (dvoid *)&indp, + (dvoid **)&date_ptr, &len)); + OCIDateGetDate( (CONST OCIDate *) date_ptr, &year1, &month1, &day1 ); + + printf("c2 is %d/%d/%d\n", day1, month1, year1); + + break; + + case OCI_TYPECODE_OBJECT: + checkerr(ctxptr->errhp, OCIAnyDataAccess(ctxptr->svchp, ctxptr->errhp, + oan_buffer, (OCITypeCode) OCI_TYPECODE_OBJECT, + (OCIType *)addr_tdo, (dvoid *) &ind2p, + (dvoid **)&addr_obj, &len)); + printf("state is %s \n", + OCIStringPtr(ctxptr->envhp, addr_obj->state)); + printf("zip is %s \n", + OCIStringPtr(ctxptr->envhp, addr_obj->zip)); + break; + + case OCI_TYPECODE_CHAR: + checkerr(ctxptr->errhp, OCIAnyDataAccess(ctxptr->svchp, + ctxptr->errhp, oan_buffer, + (OCITypeCode)OCI_TYPECODE_CHAR, + (OCIType *)0, (dvoid *)&indp, (dvoid *)&str, &len)); + + printf("c2 is %s \n", OCIStringPtr(ctxptr->envhp, str)); + break; + + case OCI_TYPECODE_RAW: + checkerr(ctxptr->errhp, OCIAnyDataAccess(ctxptr->svchp, ctxptr->errhp, + oan_buffer, (OCITypeCode)OCI_TYPECODE_RAW, + (OCIType *)0, (dvoid *)&indp, (dvoid *)&raw_col, &len)); + + raw_ptr = OCIRawPtr(ctxptr->envhp, raw_col); + printf("RAW data is: "); + for(i=0;ierrhp, OCITypeByName(ctxptr->envhp, + ctxptr->errhp, ctxptr->svchp, + (CONST text *)"", (ub4) strlen(""), + (const text *) "ADDR_TAB", + (ub4) strlen((const char *) "ADDR_TAB"), + (CONST text *) 0, (ub4) 0, OCI_DURATION_SESSION, + OCI_TYPEGET_ALL, &addr_tab_tdo)); + + checkerr(ctxptr->errhp, OCIAnyDataAccess(ctxptr->svchp, + ctxptr->errhp, oan_buffer, + (OCITypeCode)OCI_TYPECODE_NAMEDCOLLECTION, + (OCIType *) addr_tab_tdo, (dvoid *) &ind2p, + (dvoid *)&addr_tab, &len)); + + /* check how many elements in the typed table */ + checkerr(ctxptr->errhp, OCICollSize(ctxptr->envhp, ctxptr->errhp, + (CONST OCIColl *) addr_tab, &collsiz)); + printf("c2 is a typed table with %d elements:\n", collsiz); + if (collsiz == 0) + break; + + /*Dump the table from the top to the bottom. */ + /* go to the first element and print out the index */ + checkerr(ctxptr->errhp, OCITableFirst(ctxptr->envhp, + ctxptr->errhp, addr_tab, &index)); + checkerr(ctxptr->errhp, OCICollGetElem(ctxptr->envhp, + ctxptr->errhp, + (CONST OCIColl *) addr_tab, index, + &exist, &elem, &elemind)); + addr = (address *)elem; + + printf("\tAddress 1 is: %s", + OCIStringPtr(ctxptr->envhp,addr->state)); + printf("\t%s\n", OCIStringPtr(ctxptr->envhp, addr->zip)); + + for(;!OCITableNext(ctxptr->envhp, ctxptr->errhp, index, + addr_tab, &index, &exist) && exist;) + { + checkerr(ctxptr->errhp, OCICollGetElem(ctxptr->envhp, + ctxptr->errhp, + (CONST OCIColl *) addr_tab,index, + &exist, &elem, &elemind)); + addr = (address *)elem; + printf("\tAddress %d is: %s", index+1, + OCIStringPtr(ctxptr->envhp,addr->state)); + printf("\t%s\n", OCIStringPtr(ctxptr->envhp, addr->zip)); + } + break; + + DEFAULT: + printf("TYPED DATA CAN'T BE DISPLAYED IN THIS PROGRAM\n"); + break; + } +} /* end sql_exe_select() */ + + +/******************************************************* + * initialize envionment and handlers * + * * + *******************************************************/ + +void initialize(ctxptr) +cdemoanctx *ctxptr; +{ + + if (OCIEnvCreate((OCIEnv **) &ctxptr->envhp, + (ub4)OCI_THREADED|OCI_OBJECT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0, + (size_t) 0, (dvoid **) 0 )) + printf("FAILED: OCIEnvCreate()\n"); + + + printf("\n ######## Connect to server ############# \n"); + + if (OCIHandleAlloc((dvoid *) ctxptr->envhp, (dvoid **) &ctxptr->errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + printf("FAILED: OCIHandleAlloc() on ctxptr->errhp\n"); + + if (OCIHandleAlloc((dvoid *) ctxptr->envhp, (dvoid **) &ctxptr->srvhp, + (ub4) OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0)) + printf("FAILED: OCIHandleAlloc() on ctxptr->srvhp\n"); + + if (OCIHandleAlloc((dvoid *) ctxptr->envhp, (dvoid **) &ctxptr->svchp, + (ub4) OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0)) + printf("FAILED: OCIHandleAlloc() on ctxptr->svchp\n"); + + + if (OCIHandleAlloc((dvoid *) ctxptr->envhp, (dvoid **) &ctxptr->authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0)) + printf("FAILED: OCIHandleAlloc() on ctxptr->authp\n"); + + if (OCIServerAttach(ctxptr->srvhp, ctxptr->errhp, (text *) "", + (sb4) strlen((char *) ""), (ub4) OCI_DEFAULT)) + printf("FAILED: OCIServerAttach()\n"); + + if (OCIAttrSet((dvoid *) ctxptr->svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) ctxptr->srvhp, (ub4) 0, (ub4) OCI_ATTR_SERVER, + ctxptr->errhp)) + printf("FAILED: OCIAttrSet() server attribute\n"); + + + /*begin log_on part */ + + if (OCIAttrSet((dvoid *) ctxptr->authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) username, (ub4) strlen((char *) username), + (ub4) OCI_ATTR_USERNAME, ctxptr->errhp)) + printf("FAILED: OCIAttrSet() userid\n"); + + if (OCIAttrSet((dvoid *) ctxptr->authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) password, (ub4) strlen((char *) password), + (ub4) OCI_ATTR_PASSWORD, ctxptr->errhp)) + printf("FAILED: OCIAttrSet() passwd\n"); + + printf("Logging on as %s ....\n", username); + + checkerr(ctxptr->errhp, OCISessionBegin((dvoid *)ctxptr->svchp, + ctxptr->errhp,ctxptr->authp, + (ub4) OCI_CRED_RDBMS,(ub4) OCI_DEFAULT )); + + printf("%s logged on.\n", username); + + if (OCIAttrSet((dvoid *) ctxptr->svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) ctxptr->authp, (ub4) 0, (ub4) OCI_ATTR_SESSION, + ctxptr->errhp)) + printf("FAILED: OCIAttrSet() session\n"); + + /* end log_on part */ + + /* alocate stmt handle for sql queries */ + if (OCIHandleAlloc((dvoid *)ctxptr->envhp, (dvoid **) &ctxptr->stmthp, + (ub4)OCI_HTYPE_STMT, (CONST size_t) 0, (dvoid **) 0)) + printf("FAILED: alloc statement handle\n"); + + +} /* end initialize() */ + + +/******************************************************* + * clean up envionment and handlers * + * * + *******************************************************/ +void cleanup(ctxptr) +cdemoanctx *ctxptr; +{ + printf("\n ########## clean up ############ \n"); + + if (OCISessionEnd(ctxptr->svchp, ctxptr->errhp, + ctxptr->authp, (ub4) 0)) + printf("FAILED: OCISessionEnd()\n"); + + printf("%s Logged off.\n", username); + + if (OCIServerDetach(ctxptr->srvhp, ctxptr->errhp, (ub4) OCI_DEFAULT)) + printf("FAILED: OCIServerDetach()\n"); + + printf("Detached from server.\n"); + + printf("Freeing handles ...\n"); + if (ctxptr->stmthp) + OCIHandleFree((dvoid *) ctxptr->stmthp, (ub4) OCI_HTYPE_STMT); + if (ctxptr->errhp) + OCIHandleFree((dvoid *) ctxptr->errhp, (ub4) OCI_HTYPE_ERROR); + if (ctxptr->srvhp) + OCIHandleFree((dvoid *) ctxptr->srvhp, (ub4) OCI_HTYPE_SERVER); + if (ctxptr->svchp) + OCIHandleFree((dvoid *) ctxptr->svchp, (ub4) OCI_HTYPE_SVCCTX); + if (ctxptr->authp) + OCIHandleFree((dvoid *) ctxptr->authp, (ub4) OCI_HTYPE_SESSION); + if (ctxptr->envhp) + OCIHandleFree((dvoid *) ctxptr->envhp, (ub4) OCI_HTYPE_ENV); + +} /* end cleanup() */ + + +/******************************************************* + * check status and print error information * + * * + *******************************************************/ +void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", 512, errbuf); + if(errcode == 22303){ + printf("Please run cdemoanydata1.sql before executing the demo! \n"); + exit(1); + } + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} /* end checkerr() */ + + +/* end of file cdemoAnyData1.c */ + + + + + + + + + + + + + + + + + + + + + diff --git a/cdemoanydata1.sql b/cdemoanydata1.sql new file mode 100644 index 0000000..246a383 --- /dev/null +++ b/cdemoanydata1.sql @@ -0,0 +1,59 @@ +Rem +Rem $Header: cdemoanydata1.sql 04-may-2001.16:09:54 jchai Exp $ +Rem +Rem cdemoAnyData1.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem cdemoAnyData1.sql - Demo program for ANYDATA +Rem +Rem DESCRIPTION +Rem SQL script to prepare table anydatatab and address_object type +Rem +Rem NOTES +Rem Neet to run before cdemoAnyData. +Rem +Rem MODIFIED (MM/DD/YY) +Rem jchai 05/04/01 - Merged jchai_add_oci_demos_to_shiphome +Rem ani 04/30/01 - Merged ani_ocidemo +Rem ani 04/24/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +connect scott/tiger +/ +drop table anydatatab +/ +drop table addr_objtab +/ +drop type addr_tab +/ +drop type address_object +/ + +CREATE OR REPLACE TYPE address_object AS OBJECT +( + state varchar2(3), + zip varchar2(13) +) +/ + +create or replace type addr_tab is table of address_object +/ + +create table addr_objtab of address_object +/ +insert into addr_objtab values(address_object('CA','94065')) +/ + +CREATE TABLE anydatatab(col1 number, col2 Sys.AnyData) +/ + diff --git a/cdemoanydata2.c b/cdemoanydata2.c new file mode 100644 index 0000000..e74e753 --- /dev/null +++ b/cdemoanydata2.c @@ -0,0 +1,776 @@ +/* Copyright (c) 2001, 2002, Oracle Corporation. All rights reserved. */ + +/* + + NAME + cdemoAnyData2.c - OCI demo program for ANYDATA. + + DESCRIPTION + An example program which creates an TYPE piecewise using OCITypeBeginCreate() + and then describe the new type created. Three types are created and described. + An OCIANYDATA is constructed piecewise using OCIAnyDataBeginCreate() and + accessed piecewise. + + EXPORT FUNCTION(S) + + + INTERNAL FUNCTION(S) + + + STATIC FUNCTION(S) + + + NOTES + Dependent Files: + cdemoAnyData2.sql - SQL script to be run before execution. + + MODIFIED (MM/DD/YY) + jchai 06/13/02 - fix bug 2360431 + ani 09/17/01 - Change access interface for DATE,NUMBER + jchai 05/04/01 - Merged jchai_add_oci_demos_to_shiphome + ani 04/30/01 - Merged ani_ocidemo + ani 04/24/01 - Creation + +*/ + +#include +#include +#include + +#ifndef OCI_ORACLE +# include +#endif + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ +#define MAXNAME 30 + +typedef struct cdemoctx +{ + OCIEnv *envhp; + OCIError *errhp; + OCISvcCtx *svchp; + OCIServer *svrhp; + OCISession *usrhp; +} cdemoctx; + +/* boolean IS_CHARTYPE(OCITypeCode tc) */ +#define IS_CHARTYPE(tc) ((tc == OCI_TYPECODE_CHAR) || \ +(tc == OCI_TYPECODE_VARCHAR) || (tc == OCI_TYPECODE_VARCHAR2) || \ +(tc == OCI_TYPECODE_CLOB) || (tc == OCI_TYPECODE_CFILE)) + + +static text *username = (text *) "scott"; +static text *password = (text *) "tiger"; + + +/*--------------------------------------------------------------------------- + STATIC FUNCTION DECLARATIONS + ---------------------------------------------------------------------------*/ +static void chk_typecoll (/*_ cdemoctx *ctx, OCIParam *parmp, boolean is_array _*/); +static void describe_type(/*_ cdemoctx *ctx, OCIType *tdo _*/); +static void checkerr(/*_ OCIError *errhp, sword status _*/); +static void initialize(cdemoctx *ctx); +static void setup_param(/*_ OCIError *errhp, OCIParam *parm, OCITypeCode tc, + ub1 prec, sb1 scale, ub4 len, ub2 csid, ub1 csfrm, + OCIType *attr_tdo, OraText *schm, OraText *typn _*/); +static OCIType *create_builtin(/*_ OCISvcCtx *svchp, OCIEnv *envhp, OCIError *errhp, + OCIParam *parm, OCIDuration dur _*/); +static OCIType *create_usertype(/*_ OCISvcCtx *svchp, OCIEnv *envhp, OCIError *errhp, + OCITypeCode tc, ub4 cnt, OCIParam *parm1, OCIParam *parm2, + OCIParam *parm3, OCIParam *parm4, OCIParam *parm5, OCIDuration dur _*/); +static void build_data(/*_ OCIEnv *envhp, OCIError *errhp, OCISvcCtx *svchp _*/); +void main(/*_ int argc, char *argv[] _*/); + + +/* check status and print error information */ +void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = OCI_SUCCESS; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NO_DATA\n"); + break; + case OCI_ERROR: + OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); + (void) printf("Error - %s\n", errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } + if (errcode == 1034) + exit(1); + else + return; +} + + +/* initialize envionment and handlers */ +void initialize(ctx) +cdemoctx *ctx; +{ + OCIInitialize((ub4) OCI_THREADED | OCI_OBJECT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t)) 0, + (void (*)(dvoid *, dvoid *)) 0 ); + + OCIHandleAlloc( (dvoid *) NULL, (dvoid **) &ctx->envhp, + (ub4) OCI_HTYPE_ENV, + 0, (dvoid **)0); + + OCIEnvInit( &ctx->envhp, (ub4) OCI_DEFAULT, 0, (dvoid **) 0 + ); + + OCIHandleAlloc( (dvoid *) ctx->envhp, + (dvoid **) &ctx->errhp, (ub4) OCI_HTYPE_ERROR, 0, (dvoid **)0); + + /* Allocate server handle and attach to server */ + OCIHandleAlloc( (dvoid *) ctx->envhp, + (dvoid **) &ctx->svrhp, + (ub4) OCI_HTYPE_SERVER, 0, (dvoid **) 0); + checkerr(ctx->errhp, OCIServerAttach( ctx->svrhp, + ctx->errhp, (text *) 0, + (sb4) 0, (ub4) OCI_DEFAULT)); + + /* Allocate and setup service context */ + OCIHandleAlloc( (dvoid *) ctx->envhp, + (dvoid **) &ctx->svchp, + (ub4) OCI_HTYPE_SVCCTX, 0, (dvoid **)0); + checkerr(ctx->errhp, OCIAttrSet( (dvoid *) ctx->svchp, + (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) ctx->svrhp, (ub4) 0, + (ub4) OCI_ATTR_SERVER, (OCIError *) ctx->errhp)); + + /* allocate a user context handle */ + OCIHandleAlloc((dvoid *)ctx->envhp, + (dvoid **)&ctx->usrhp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0); + checkerr(ctx->errhp, OCIAttrSet((dvoid *)ctx->usrhp, + (ub4)OCI_HTYPE_SESSION, + (dvoid *) username, (ub4)strlen((char *) username), + (ub4)OCI_ATTR_USERNAME, ctx->errhp)); + checkerr(ctx->errhp, OCIAttrSet((dvoid *)ctx->usrhp, + (ub4)OCI_HTYPE_SESSION, + (dvoid *) password, (ub4)strlen((char *) password), + (ub4)OCI_ATTR_PASSWORD, ctx->errhp)); + checkerr(ctx->errhp, + OCISessionBegin (ctx->svchp, ctx->errhp, + ctx->usrhp, (ub4)OCI_CRED_RDBMS, + (ub4)OCI_DEFAULT)); + + /* Set up user context inside service context */ + checkerr(ctx->errhp, OCIAttrSet((dvoid *)ctx->svchp, + (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)ctx->usrhp, (ub4)0, + (ub4)OCI_ATTR_SESSION, ctx->errhp)); +} + + +/* Setup param handle with type info */ +void setup_param(errhp, parm, tc, prec, scale, len, csid, csfrm, + attr_tdo, schm, typn) +OCIError *errhp; +OCIParam *parm; +OCITypeCode tc; +ub1 prec; +sb1 scale; +ub4 len; +ub2 csid; +ub1 csfrm; +OCIType *attr_tdo; /* attribute TDO or schema, typename specified */ +OraText *schm; +OraText *typn; +{ + + /* Setup type code */ + OCIAttrSet((dvoid *)parm, (ub4)OCI_DTYPE_PARAM, (dvoid *)&tc, + (ub4) sizeof(ub2), (ub4)OCI_ATTR_TYPECODE, errhp); + + switch (tc) + { + case OCI_TYPECODE_NUMBER: /* Setup precision and scale */ + OCIAttrSet((dvoid *)parm, (ub4)OCI_DTYPE_PARAM, (dvoid *)&prec, + (ub4) sizeof(ub1), (ub4)OCI_ATTR_PRECISION, errhp); + OCIAttrSet((dvoid *)parm, (ub4)OCI_DTYPE_PARAM, (dvoid *)&scale, + (ub4) sizeof(sb1), (ub4)OCI_ATTR_SCALE, errhp); + break; + case OCI_TYPECODE_RAW: /* Setup length of raw */ + OCIAttrSet((dvoid *)parm, (ub4)OCI_DTYPE_PARAM, (dvoid *)&len, + (ub4) sizeof(ub4), (ub4)OCI_ATTR_DATA_SIZE, errhp); + break; + case OCI_TYPECODE_VARCHAR2: /* Set Len, csid, csfrm for varchar2's */ + case OCI_TYPECODE_VARCHAR: + case OCI_TYPECODE_CHAR: + OCIAttrSet((dvoid *)parm, (ub4)OCI_DTYPE_PARAM, (dvoid *)&len, + (ub4) sizeof(ub4), (ub4)OCI_ATTR_DATA_SIZE, errhp); + /* FALLTHROUGH */ + case OCI_TYPECODE_CLOB: + case OCI_TYPECODE_CFILE: + OCIAttrSet((dvoid *)parm, (ub4)OCI_DTYPE_PARAM, (dvoid *)&csid, + (ub4) sizeof(ub2), (ub4)OCI_ATTR_CHARSET_ID, errhp); + OCIAttrSet((dvoid *)parm, (ub4)OCI_DTYPE_PARAM, (dvoid *)&csfrm, + (ub4) sizeof(ub1), (ub4)OCI_ATTR_CHARSET_FORM, errhp); + break; + case OCI_TYPECODE_REF: + case OCI_TYPECODE_OBJECT: /* handle later */ + case OCI_TYPECODE_VARRAY: + case OCI_TYPECODE_TABLE: + OCIAttrSet((dvoid *)parm, (ub4)OCI_DTYPE_PARAM, (dvoid *)attr_tdo, + (ub4) sizeof(OCIType *), (ub4)OCI_ATTR_TDO, errhp); + break; + default: + break; + } +} + + +/* create OCIType of built in types */ +OCIType *create_builtin(svchp, envhp, errhp, parm, dur) +OCISvcCtx *svchp; +OCIEnv *envhp; +OCIError *errhp; +OCIParam *parm; +OCIDuration dur; +{ + ub2 tc; + OCIType *builtin; + ub4 siz; + + /* Get Typecode */ + OCIAttrGet((dvoid *)parm, (ub4)OCI_DTYPE_PARAM, (dvoid *)&tc, + &siz, (ub4)OCI_ATTR_TYPECODE, errhp); + + /* Create transient builtin based on the typecode */ + checkerr(errhp, OCITypeBeginCreate(svchp, errhp, tc, dur, &builtin)); + + checkerr(errhp, OCITypeSetBuiltin(svchp, errhp, builtin, parm)); + + checkerr(errhp, OCITypeEndCreate(svchp, errhp, builtin)); + + return(builtin); +} + + +/* Create a user defined type of given typecode - OBJECT, VARRAY etc. */ +OCIType *create_usertype(svchp, envhp, errhp, tc, cnt, parm1, parm2, + parm3, parm4, parm5, dur) +OCISvcCtx *svchp; +OCIEnv *envhp; +OCIError *errhp; +OCITypeCode tc; +ub4 cnt; +OCIParam *parm1; /* MUST - param for collection info / 1st object attribute */ +OCIParam *parm2; /* OPTIONAL - for 2nd attribute */ +OCIParam *parm3; /* OPTIONAL - for 3rd attribute */ +OCIParam *parm4; /* OPTIONAL - for 4th attribute */ +OCIParam *parm5; /* OPTIONAL - for 5th attribute */ +OCIDuration dur; +{ + OCIType *usertype; + ub4 siz; + sword status; + /* Create transient usertype based on the typecode */ + status = OCITypeBeginCreate(svchp, errhp, tc, dur, &usertype); + checkerr(errhp, status); + if(status!=0){ + printf("exiting.... \n"); + exit(1); + } + + switch (tc) + { + case OCI_TYPECODE_OBJECT: + checkerr(errhp, OCITypeAddAttr(svchp, errhp, usertype, (text *)"attr1", + (ub4)strlen("attr1"), parm1)); + if (parm2) + checkerr(errhp, OCITypeAddAttr(svchp, errhp, usertype, (text *)"attr2", + (ub4)strlen("attr2"), parm2)); + if (parm3) + checkerr(errhp, OCITypeAddAttr(svchp, errhp, usertype, (text *)"attr3", + (ub4)strlen("attr3"), parm3)); + if (parm4) + checkerr(errhp, OCITypeAddAttr(svchp, errhp, usertype, (text *)"attr4", + (ub4)strlen("attr4"), parm4)); + if (parm5) + checkerr(errhp, OCITypeAddAttr(svchp, errhp, usertype, (text *)"attr5", + (ub4)strlen("attr5"), parm5)); + break; + case OCI_TYPECODE_VARRAY: + checkerr(errhp,OCITypeSetCollection(svchp, errhp, usertype, parm1, cnt)); + break; + default: + printf ("Incorrect parameters to create_usertype\n"); + return((OCIType *)0); + } + + checkerr(errhp, OCITypeEndCreate(svchp, errhp, usertype)); + + return(usertype); +} + + +/* Using OCIDescribeAny to describe type */ +static void chk_type (ctx, parmp) +cdemoctx *ctx; +OCIParam *parmp; +{ + OCITypeCode typecode, + collection_typecode; + ub4 size; + OCIType *tdo; + ub2 num_attr; + ub1 is_incomplete, + is_predefined, + is_transient, + has_table; + OCIParam *collection_parmp; + ub1 prec; + sb1 scale; + ub2 len; + ub2 csid; + ub1 csfrm; + ub2 sqltype; + + checkerr(ctx->errhp, OCIAttrGet((dvoid*) parmp, + (ub4) OCI_DTYPE_PARAM, + (dvoid*) &tdo, (ub4 *) 0, + (ub4) OCI_ATTR_TDO, (OCIError *) ctx->errhp)); + + checkerr(ctx->errhp, + OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &typecode, (ub4 *) 0, + (ub4) OCI_ATTR_TYPECODE, (OCIError *) ctx->errhp)); + + if (typecode == OCI_TYPECODE_NAMEDCOLLECTION) + { + checkerr(ctx->errhp, + OCIAttrGet((dvoid *)parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&collection_typecode, (ub4 *)0, + (ub4)OCI_ATTR_COLLECTION_TYPECODE, + (OCIError *)ctx->errhp)); + checkerr(ctx->errhp, + OCIAttrGet((dvoid *)parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&collection_parmp, (ub4 *)0, + (ub4)OCI_ATTR_COLLECTION_ELEMENT, (OCIError *)ctx->errhp)); + } + + checkerr(ctx->errhp, + OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &is_incomplete, (ub4 *) 0, + (ub4) OCI_ATTR_IS_INCOMPLETE_TYPE, (OCIError *) ctx->errhp)); + + checkerr(ctx->errhp, + OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &is_predefined, (ub4 *) 0, + (ub4) OCI_ATTR_IS_PREDEFINED_TYPE, (OCIError *) ctx->errhp)); + + checkerr(ctx->errhp, + OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &is_transient, (ub4 *) 0, + (ub4) OCI_ATTR_IS_TRANSIENT_TYPE, (OCIError *) ctx->errhp)); + + checkerr(ctx->errhp, + OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &has_table, (ub4 *) 0, + (ub4) OCI_ATTR_HAS_NESTED_TABLE, + (OCIError *) ctx->errhp)); + + checkerr(ctx->errhp, + OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &num_attr, (ub4 *) 0, + (ub4) OCI_ATTR_NUM_TYPE_ATTRS, (OCIError *) ctx->errhp)); + + /* Get constraint info for predefined transient types */ + if (is_predefined && is_transient) + { + checkerr(ctx->errhp, + OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &prec, (ub4 *) 0, + (ub4) OCI_ATTR_PRECISION, + (OCIError *) ctx->errhp)); + checkerr(ctx->errhp, + OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &scale, (ub4 *) 0, + (ub4) OCI_ATTR_SCALE, + (OCIError *) ctx->errhp)); + if (IS_CHARTYPE(typecode)) + { + checkerr(ctx->errhp, + OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &csid, (ub4 *) 0, + (ub4) OCI_ATTR_CHARSET_ID, + (OCIError *) ctx->errhp)); + checkerr(ctx->errhp, + OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &csfrm, (ub4 *) 0, + (ub4) OCI_ATTR_CHARSET_FORM, + (OCIError *) ctx->errhp)); + } + + checkerr(ctx->errhp, + OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &len, (ub4 *) 0, + (ub4) OCI_ATTR_DATA_SIZE, + (OCIError *) ctx->errhp)); + checkerr(ctx->errhp, + OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &sqltype, (ub4 *) 0, + (ub4) OCI_ATTR_DATA_TYPE, + (OCIError *) ctx->errhp)); + } + + printf ( "TYPE\n"); + printf ( "Typecode: %d\n", typecode); + if (typecode == OCI_TYPECODE_NAMEDCOLLECTION) + printf ( "Collection typecode: %d\n", collection_typecode); + printf ( "Number of attrs: %d\n", num_attr); + printf ( "Is incomplete: %d\n", is_incomplete); + printf ( "Is predefined: %d\n", is_predefined); + printf ( "Is transient: %d\n", is_transient); + printf ( "Has nested table: %d\n", has_table); + + if (is_predefined && is_transient) + { + printf( "Predefined transient type information :\n"); + printf( "Precision : %d\n", prec ); + printf( "Scale : %d\n", scale); + printf( "Length : %d\n", len); + printf( "SQLT code : %d\n", sqltype); + if (IS_CHARTYPE(typecode)) + { + printf( "Charset id : %d\n", csid ); + printf( "Charset form : %d\n", csfrm); + } + } + + if (typecode == OCI_TYPECODE_NAMEDCOLLECTION) + chk_typecoll(ctx, collection_parmp, + collection_typecode == OCI_TYPECODE_VARRAY); +} + + +/*describe collection type */ +static void chk_typecoll (ctx, parmp, is_array) +cdemoctx *ctx; +OCIParam *parmp; +boolean is_array; +{ + text schema[MAXNAME], + type[MAXNAME], + *namep; + ub4 size; + ub2 len = 0; + ub4 num_elems; + OCITypeCode typecode; + ub2 datatype; + + checkerr(ctx->errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &len, (ub4 *) 0, + (ub4) OCI_ATTR_DATA_SIZE, (OCIError *) ctx->errhp)); + + checkerr(ctx->errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &size, + (ub4) OCI_ATTR_TYPE_NAME, (OCIError *) ctx->errhp)); + + strncpy((char *)type, (char *)namep, (size_t) size); + type[size] = '\0'; + + checkerr(ctx->errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &size, + (ub4) OCI_ATTR_SCHEMA_NAME, (OCIError *) ctx->errhp)); + + strncpy((char *)schema, (char *)namep, (size_t) size); + schema[size] = '\0'; + + checkerr(ctx->errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &typecode, (ub4 *) 0, (ub4) OCI_ATTR_TYPECODE, + (OCIError *) ctx->errhp)); + + checkerr(ctx->errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &datatype, (ub4 *) 0, (ub4) OCI_ATTR_DATA_TYPE, + (OCIError *) ctx->errhp)); + + num_elems = 0; + if (is_array) + checkerr(ctx->errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &num_elems, (ub4 *) 0, + (ub4) OCI_ATTR_NUM_ELEMS, (OCIError *) ctx->errhp)); + + + printf ( "Schema Type Length Type Datatype Elements\n"); + printf ( "_________________________________________________________\n"); + + printf("%10s%16s%9d%5d%9d%8d\n", schema, type, + len, typecode, datatype, num_elems); + +} + + +/* Describe a type given the OCIType */ +static void describe_type(ctx, tdo) +cdemoctx *ctx; +OCIType *tdo; +{ + OCIDescribe *dschp; + OCIParam *parmp; + + OCIHandleAlloc((dvoid *)ctx->envhp, (dvoid **) &dschp, + (ub4) OCI_HTYPE_DESCRIBE, (size_t) 0, (dvoid **) 0); + + checkerr(ctx->errhp, + OCIDescribeAny(ctx->svchp, ctx->errhp, (dvoid *)tdo, + (ub4)0, OCI_OTYPE_PTR, (ub1)1, OCI_PTYPE_TYPE, dschp)); + + checkerr(ctx->errhp, OCIAttrGet((dvoid *)dschp, (ub4)OCI_HTYPE_DESCRIBE, + (dvoid *)&parmp, (ub4 *)0, (ub4)OCI_ATTR_PARAM, + ctx->errhp)); + + chk_type(ctx, parmp); +} + + +/* constructs an ANYDATA piecewise using OCIAnyDataBeginCreate() + and access the data piecewise */ +static void build_data(envhp, errhp, svchp) +OCIEnv *envhp; +OCIError *errhp; +OCISvcCtx *svchp; +{ + OCIAnyData *addressimgh = (OCIAnyData *) 0; + OCIAnyData *addressimgh2 = (OCIAnyData *) 0; + text *addressimg_buf; + OCITypeCode typecode; + OCIInd indp; + ub4 zip_size, state_size; + ub2 len; + OCIRef *Ref, *Ref2; + OCIType *tdo = (OCIType *) 0; + sword error; + + OCIString *str = (OCIString *) 0; + OCIRaw *Raw = (OCIRaw *)0; + OCIRaw *Raw2 = (OCIRaw *)0; + ub1 raw_data[5] = {1, 1, 1, 1, 1}; + OCIDate date1, *date2 = (OCIDate *)0; + OCINumber num1, *num2 = (OCINumber *)0; + OCIInd ind1 = OCI_IND_NOTNULL; + + printf("\nBeginning piecewise construction and access ANYDATA\n"); + + checkerr(errhp, OCITypeByName(envhp, errhp, svchp, (const text *) "", + (ub4) strlen((const char *) ""), + (const text *) "BASIC_OBJECT", + (ub4) strlen((const char *) "BASIC_OBJECT"), + (CONST text *) 0, (ub4) 0, + OCI_DURATION_SESSION, OCI_TYPEGET_ALL, &tdo)); + + printf("Constructing image\n"); + + /* begin to construct the data piecewise */ + OCIAnyDataBeginCreate(svchp, errhp, OCI_TYPECODE_OBJECT, tdo, + OCI_DURATION_SESSION, &addressimgh); + + printf("Adding scalar values for the attributes in the image handle\n"); + + OCIStringAssignText(envhp, errhp, (text *)"CA", 2, &str); + printf("state is %s \n", OCIStringPtr(envhp, str)); + OCIAnyDataAttrSet(svchp, errhp, addressimgh, OCI_TYPECODE_CHAR, + (OCIType *)0, (dvoid *)&ind1, str, 2, FALSE); + OCIStringAssignText(envhp, errhp, (text *)"94065", 5, &str); + printf("zip is %s \n", OCIStringPtr(envhp, str)); + OCIAnyDataAttrSet(svchp, errhp, addressimgh, OCI_TYPECODE_CHAR, + (OCIType *)0, (dvoid *)&ind1, str, 5, FALSE); + + OCIRawAssignBytes(envhp, errhp, raw_data, 5, &Raw); + OCIAnyDataAttrSet(svchp, errhp, addressimgh, OCI_TYPECODE_RAW, + (OCIType *)0, (dvoid *)&ind1, Raw, (ub4) 5, FALSE); + + error = OCIDateSysDate(errhp, &date1); + OCIAnyDataAttrSet(svchp, errhp, addressimgh, OCI_TYPECODE_DATE, + (OCIType *)0, (dvoid *)&ind1, &date1, (ub4)0, FALSE); + + zip_size = 10; + error = OCINumberFromInt(errhp, &zip_size, sizeof(zip_size), + OCI_NUMBER_UNSIGNED, &num1); + OCIAnyDataAttrSet(svchp, errhp, addressimgh, OCI_TYPECODE_NUMBER, + (OCIType *)0, (dvoid *)&ind1, &num1, (ub4)0, FALSE); + + printf("Generating Image\n\n"); + OCIAnyDataEndCreate(svchp, errhp, addressimgh); + + /* Access the image */ + printf("Accessing image\n"); + + zip_size = 11; + state_size = 3; + + OCIAnyDataAttrGet(svchp, errhp, addressimgh, + OCI_TYPECODE_CHAR, (OCIType *)0, (dvoid *)&indp, + (dvoid **)&str, &state_size, FALSE); + printf("state is %s \n", OCIStringPtr(envhp, str)); + OCIAnyDataAttrGet(svchp, errhp, addressimgh, + OCI_TYPECODE_CHAR, (OCIType *)0, (dvoid *)&indp, + (dvoid **)&str, &zip_size, FALSE); + printf("zip is %s \n", OCIStringPtr(envhp, str)); + + checkerr(errhp, OCIObjectNew(envhp, errhp, svchp, OCI_TYPECODE_RAW, + (OCIType *) 0, (dvoid *) 0, OCI_DURATION_TRANS, FALSE, + (dvoid **) &Raw2)); + OCIAnyDataAttrGet(svchp, errhp, addressimgh, + OCI_TYPECODE_RAW, (OCIType *)0, (dvoid *)&indp, + (dvoid **)&Raw2, &state_size, FALSE); + if (!memcmp((dvoid *)OCIRawPtr(envhp, Raw), (dvoid *)OCIRawPtr(envhp, Raw2), + OCIRawSize(envhp, Raw))) + printf("RAWs are same \n"); + else + printf("Error! RAWs are diff \n"); + + error = OCIObjectNew(envhp, errhp, svchp, OCI_TYPECODE_DATE, + (OCIType *) 0, (dvoid *) 0, OCI_DURATION_DEFAULT, FALSE, + (dvoid **) &date2); + /*OCIAnyDataAttrGet(svchp, errhp, addressimgh, + OCI_TYPECODE_DATE, (OCIType *)0, (dvoid *)&indp, + (dvoid **)date2, &state_size, FALSE); */ + OCIAnyDataAttrGet(svchp, errhp, addressimgh, + OCI_TYPECODE_DATE, (OCIType *)0, (dvoid *)&indp, + (dvoid **)&date2, &state_size, FALSE); + (void) OCIDateCompare(errhp, &date1, date2, &error); + + + if (!error) + printf("Dates are same \n"); + else + printf("Error! dates are diff \n"); + + checkerr(errhp, OCIObjectNew(envhp, errhp, svchp, OCI_TYPECODE_NUMBER, + (OCIType *) 0, (dvoid *) 0, OCI_DURATION_TRANS, FALSE, + (dvoid **) &num2)); + /*OCIAnyDataAttrGet(svchp, errhp, addressimgh, + OCI_TYPECODE_NUMBER, (OCIType *)0, (dvoid *)&indp, + (dvoid **)num2, &state_size, FALSE);*/ + OCIAnyDataAttrGet(svchp, errhp, addressimgh, + OCI_TYPECODE_NUMBER, (OCIType *)0, (dvoid *)&indp, + (dvoid **)&num2, &state_size, FALSE); + OCINumberCmp(errhp, &num1, num2, &error); + if (!error) + printf("Numbers are same \n"); + else + printf("Error! Numbers are diff \n"); + OCINumberToInt(errhp, num2, sizeof(zip_size), 0, + &zip_size); + printf("Number (num2) is %d \n", zip_size); + + /* + ** Free the handles + */ + + printf("Freeing FDO, TDS and Image structures\n\n\n"); + OCIAnyDataDestroy(svchp, errhp, addressimgh); +} + + +void main(int argc, char *argv[]) +{ + cdemoctx ctx; + OCIType *tdo; /* AnyType */ + OCIParam *parm = (OCIParam *)0; /* parameter handle */ + OCIParam *parm2 = (OCIParam *)0; + OCIParam *parm3 = (OCIParam *)0; + OCIDuration dur; + OCIType *attr_tdo; + OCIType *obj_tdo; + OCIType *coll_tdo; + ub1 t_precision; + sb1 t_scale; + ub2 t_charset_id; + ub1 t_charset_form; + ub4 t_data_size; + ub2 t_typecode; + OCIType *t_tdo; + + initialize(&ctx); + + /* Allocate parameter handle for transient type creation */ + OCIDescriptorAlloc((dvoid *)ctx.envhp, (dvoid **)&parm, + (ub4)OCI_DTYPE_PARAM, 0, (dvoid **)0); + OCIDescriptorAlloc((dvoid *)ctx.envhp, (dvoid **)&parm2, + (ub4)OCI_DTYPE_PARAM, 0, (dvoid **)0); + OCIDescriptorAlloc((dvoid *)ctx.envhp, (dvoid **)&parm3, + (ub4)OCI_DTYPE_PARAM, 0, (dvoid **)0); + + OCIDurationBegin(ctx.envhp, ctx.errhp, ctx.svchp, + OCI_DURATION_CALL, &dur); + + + /* Create transient built-in types and descrie types*/ + + /* NUMBER(5,2) */ + setup_param(ctx.errhp, parm, OCI_TYPECODE_NUMBER, (ub1)5, (sb1)2, + (ub4)0, (ub2)0, + (ub1)0, (OCIType *)0, (OraText *)0, (OraText *)0); + + tdo = create_builtin(ctx.svchp, ctx.envhp, ctx.errhp, + parm, dur); + + describe_type(&ctx, tdo); + + /* CHAR(20), csid = OCI_UCS2ID, csfrm = SQLCS_NCHAR */ + setup_param(ctx.errhp, parm, OCI_TYPECODE_CHAR, (ub1)0, (sb1)0, + (ub4)20, (ub2)OCI_UCS2ID, + (ub1)SQLCS_NCHAR, (OCIType *)0, (OraText *)0, (OraText *)0); + tdo = create_builtin(ctx.svchp, ctx.envhp, + ctx.errhp, parm, dur); + describe_type(&ctx, tdo); + + OCIDurationEnd(ctx.envhp, ctx.errhp, ctx.svchp, + dur); + + + OCITypeByName(ctx.envhp, ctx.errhp, + ctx.svchp, (text *)0, (ub4)0, + (text *)"FOO", (ub4)3, (text *)0, (ub4)0, + OCI_DURATION_SESSION, OCI_TYPEGET_ALL, &attr_tdo); + + /* create a transient collection - VARRAY(100) of SCOTT.FOO */ + setup_param(ctx.errhp, parm, OCI_TYPECODE_OBJECT, (ub1)0, (sb1)0, + (ub4)0, (ub2)0, + (ub1)SQLCS_IMPLICIT, attr_tdo, (OraText *)0, (OraText *)0); + coll_tdo = create_usertype(ctx.svchp, ctx.envhp, + ctx.errhp, OCI_TYPECODE_VARRAY, (ub4)100, + parm, (OCIParam *)0, (OCIParam *)0, (OCIParam *)0, + (OCIParam *)0, dur); + describe_type(&ctx, coll_tdo); + + /* piecewise construct an ANYDATA and access it piecewise */ + build_data(ctx.envhp, ctx.errhp, ctx.svchp); + + /* Cleanup */ + OCIHandleFree((dvoid *)ctx.envhp, (ub4) OCI_HTYPE_ENV); + OCITerminate((ub4)OCI_OBJECT); +} + +/* end of file cdemoAnyData2.c */ diff --git a/cdemoanydata2.sql b/cdemoanydata2.sql new file mode 100644 index 0000000..1adbd87 --- /dev/null +++ b/cdemoanydata2.sql @@ -0,0 +1,49 @@ +Rem +Rem $Header: cdemoanydata2.sql 04-may-2001.16:09:55 jchai Exp $ +Rem +Rem cdemoAnyData1.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem cdemoAnyData2.sql - Demo program for ANYDATA +Rem +Rem DESCRIPTION +Rem SQL script to prepare table anydatatab and address_object type +Rem +Rem NOTES +Rem Neet to run before cdemoAnyData2. +Rem +Rem MODIFIED (MM/DD/YY) +Rem jchai 05/04/01 - Merged jchai_add_oci_demos_to_shiphome +Rem ani 04/30/01 - Merged ani_ocidemo +Rem ani 04/24/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +connect scott/tiger + +drop type foo +/ +drop type basic_object +/ + +CREATE OR REPLACE TYPE foo as OBJECT +( + a DATE, + b VARCHAR2(50), + c CLOB +) +/ + +create or replace type basic_object as object (state char(2), zip char(10), + a3 raw(10), a4 date, a5 number) +/ + diff --git a/cdemobj.c b/cdemobj.c new file mode 100644 index 0000000..07ef8c1 --- /dev/null +++ b/cdemobj.c @@ -0,0 +1,895 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemobj.c 18-feb-2005.15:01:08 aliu Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1995, 2005, Oracle. All rights reserved. +*/ + +/* + NAME + cdemobj.c + DESCRIPTION + Demo of selection of a REF and display the pinned object through + navigational interface. + + NOTES + see routines. + + MODIFIED (MM/DD/YY) + aliu 02/17/05 - lint issues + aliu 02/16/05 - fix bug 4184313 + aliu 07/17/03 - Free dschp after printing in dump_adt + nireland 04/11/00 - Fix porting exception. #1264324 + mpjoshi 02/15/00 - bug 531229 + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 09/09/98 - lines longer than 79 chars reformatted - bug 722491 + svedala 02/18/98 - OCI obsoletion changes + svedala 04/13/98 - + echen 06/04/97 - remove TypeTypeCode call + echen 06/02/97 - fix a bug + echen 06/02/97 - remove obsolete ORT code + skmishra 05/14/97 - stdcc compatibility changes + azhao 03/28/97 - add AS OBJECT to create type + echen 03/24/97 - fix a sequent bug + azhao 03/05/97 - fix compile errors + echen 03/05/97 - remove unnecessary code + cchau 03/03/97 - change functions to long names + cxcheng 02/10/97 - remove short ORO names + echen 01/09/97 - modify the sql syntax + echen 01/03/97 - fix test bugs + echen 11/15/96 - change obsolete type code + skrishna 11/07/96 - continue OCICollGetElem interface change + jboonl10/30/96 - new ori interface + echen 11/06/96 - fix OCICollGetElem + echen 07/19/96 - remove obsolete pin option + echen 07/19/96 - remove obsolete pin option + dchatt07/18/96 - delete Oracle spec code like static + echen 07/16/96 - Creation +*/ + +#ifndef CDEMOBJ_ORACLE +#include "cdemobj.h" +#endif + +/* statement to select a ref from an extent table customer_tab */ +static const text *const selref = (text *) + "SELECT REF(c) from customer_tab c"; + +/* statement to create the type address */ +static const text *const create_type_address = (text *) +"CREATE TYPE address AS OBJECT (\ + no NUMBER,\ + street VARCHAR(60),\ + state CHAR(2),\ + zip CHAR(10)\ +)"; + +/* statement to create the typed table address_tab */ +static const text *const create_type_addr_tab = (text *) +"create type addr_tab is table of address"; + +/* statement to create the type person */ +static const text *const create_type_person = (text *) +"CREATE TYPE person AS OBJECT (\ + firstname CHAR(20),\ + lastname varchar(20),\ + age int,\ + salary float,\ + bonus double precision,\ + retirement_fund int,\ + number_of_kids smallint,\ + years_of_school numeric(10, 2),\ + preaddr addr_tab,\ + birthday date,\ + number_of_pets real,\ + comment1 raw(200),\ + comment2 clob,\ + comment3 varchar2(200),\ + addr ADDRESS\ +)"; + +/* statement to create the type customer */ +static const text *const create_type_customer = (text *) +"CREATE TYPE customer AS OBJECT (\ + account char(20),\ + aperson REF person\ +)"; + +/* statement to create the typed table person */ +static const text *const create_table_person = (text *) +"create table person_tab of person nested table preaddr \ + store as person_preaddr_table"; + +/* statement to create the typed table customer_tab */ +static const text *const create_table_customer = (text *) +"create table customer_tab of customer"; + +/* statement to insert data into table customer_tab */ +static const text *const insert_customer = (text *) +"insert into customer_tab values('00001', null)"; + +/* statement to insert data into table person_tab */ +static const text *const insert_person = (text *) +"insert into person_tab values('Sandy', 'Wood', 25, 32000, 10000, 20000, 3,\ + 15, addr_tab(),\ + to_date('1961 08 23', 'YYYY MM DD'), 2,\ + '1234567890', 'This is a test', 'This is a test',\ + ADDRESS(8888, 'Fenley Road', 'CA', '91406'))"; + +/* statement to insert data into the nested table in person_tab */ +static const text *const insert_address1 = (text *) +"insert into the (select preaddr from person_tab where\ + firstname='Sandy') values\ + (715, 'South Henry', 'ca', '95117')"; +static const text *const insert_address2 = (text *) +"insert into the (select preaddr from person_tab where\ + firstname='Sandy') values\ + (6830, 'Woodley Ave', 'ca', '90416')"; + +/* statement to update the ref in the table customer_tab */ +static const text *const update_customer = (text *) +"update customer_tab set aperson = (select ref(p)\ + from person_tab p where\ + p.firstname = 'Sandy')"; + +/*************************************************************************** +* Check the error and display the error message * +****************************************************************************/ +static void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + break; + case OCI_NEED_DATA: + break; + case OCI_NO_DATA: + break; + case OCI_ERROR: /* get the error back and display on the screen */ + (void) OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); + (void) printf("Error - %s\n", errbuf); + break; + case OCI_INVALID_HANDLE: + break; + case OCI_STILL_EXECUTING: + break; + case OCI_CONTINUE: + break; + default: + break; + } +} +/**************************************************************************** +* Display attribute value of an ADT * +****************************************************************************/ +static void display_attr_val(envhp, errhp, names, typecode, attr_value) +OCIEnv *envhp; /* environment handle */ +OCIError *errhp; /* error handle */ +text *names; /* the name of the attribute */ +OCITypeCode typecode; /* the type code */ +dvoid *attr_value; /* the value pointer */ +{ + text str_buf[200]; + double dnum; + ub4 text_len, str_len; + OCIRaw *raw = (OCIRaw *) 0; + OCIString *vs = (OCIString *) 0; + ub1 *temp = (ub1 *)0; + ub4 rawsize = 0; + ub4 i = 0; + + /* display the data based on the type code */ + switch (typecode) + { + case OCI_TYPECODE_DATE : /* fixed length string */ + str_len = 200; + (void) OCIDateToText(errhp, (CONST OCIDate *) attr_value, + (CONST text*) "Month dd, SYYYY, HH:MI A.M.", + (ub1) 27, (CONST text*) "American", (ub4) 8, + (ub4 *)&str_len, str_buf); + str_buf[str_len+1] = '\0'; + (void) printf("attr %s = %s\n", names, (text *) str_buf); + break; + case OCI_TYPECODE_RAW : /* RAW */ + raw = *(OCIRaw **) attr_value; + temp = OCIRawPtr(envhp, raw); + rawsize = OCIRawSize (envhp, raw); + (void) printf("attr %s = ", names); + for (i=0; i < rawsize; i++) + { + (void) printf("0x%x ", temp[i]); + } + (void) printf("\n"); + break; + case OCI_TYPECODE_CHAR : /* fixed length string */ + case OCI_TYPECODE_VARCHAR : /* varchar */ + case OCI_TYPECODE_VARCHAR2 : /* varchar2 */ + vs = *(OCIString **) attr_value; + (void) printf("attr %s = %s\n", + names, (text *) OCIStringPtr(envhp, vs)); + break; + case OCI_TYPECODE_SIGNED8 : /* BYTE - sb1 */ + (void) printf("attr %s = %d\n", names, *(sb1 *) attr_value); + break; + case OCI_TYPECODE_UNSIGNED8 : /* UNSIGNED BYTE - ub1 */ + (void) printf("attr %s = %d\n", names, *(ub1 *) attr_value); + break; + case OCI_TYPECODE_OCTET : /* OCT */ + (void) printf("attr %s = %d\n", names, *(ub1 *) attr_value); + break; + case OCI_TYPECODE_UNSIGNED16 : /* UNSIGNED SHORT */ + case OCI_TYPECODE_UNSIGNED32 : /* UNSIGNED LONG */ + case OCI_TYPECODE_REAL : /* REAL */ + case OCI_TYPECODE_DOUBLE : /* DOUBLE */ + case OCI_TYPECODE_INTEGER : /* INT */ + case OCI_TYPECODE_SIGNED16 : /* SHORT */ + case OCI_TYPECODE_SIGNED32 : /* LONG */ + case OCI_TYPECODE_DECIMAL : /* DECIMAL */ + case OCI_TYPECODE_FLOAT : /* FLOAT */ + case OCI_TYPECODE_NUMBER : /* NUMBER */ + case OCI_TYPECODE_SMALLINT : /* SMALLINT */ + (void) OCINumberToReal(errhp, (CONST OCINumber *) attr_value, + (uword) sizeof(dnum), (dvoid *) &dnum); + (void) printf("attr %s = %f\n", names, dnum); + break; + default: + (void) printf("attr %s - typecode %d\n", names, typecode); + break; + } +} + + +/**************************************************************************** +* Dump the info of any ADT * +****************************************************************************/ +static void dump_adt(envhp, errhp, svchp, tdo, obj, null_obj) +OCIEnv *envhp; /* environment handle */ +OCIError *errhp; /* error handle */ +OCISvcCtx *svchp; /* service handle */ +OCIType *tdo; /* type descriptor */ +dvoid *obj; /* object pointer */ +dvoid *null_obj; /* parallel null struct pointer */ +{ + text *names[50]; + text *lengths[50]; + text *indexes[50]; + ub2 count, pos; + OCITypeElem *ado; + ub4 text_len, str_len; + ub4 i; + OCITypeCode typecode; + OCIInd attr_null_status; + dvoid *attr_null_struct; + dvoid *attr_value; + OCIType *attr_tdo, *element_type; + dvoid *object; + dvoid *null_object; + OCIType *object_tdo; + ub1 status; + OCIRef *type_ref; + text str_buf[200]; + double dnum; + dvoid *element = (dvoid *) 0, *null_element = (dvoid *) 0; + boolean exist, eoc, boc; + sb4 index; + OCIDescribe *dschp = (OCIDescribe *) 0, *dschp1 = (OCIDescribe *) 0; + text *namep, *typenamep; + dvoid *list_attr; + OCIIter *itr = (OCIIter *) 0; + dvoid *parmp = (dvoid *) 0, + *parmdp = (dvoid *) 0, + *parmp1 = (dvoid *) 0, + *parmp2 = (dvoid *) 0; + OCIRef *elem_ref = (OCIRef *) 0; + + checkerr(errhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **) &dschp, + (ub4) OCI_HTYPE_DESCRIBE, + (size_t) 0, (dvoid **) 0)); + + checkerr(errhp, OCIDescribeAny(svchp, errhp, (dvoid *) tdo, + (ub4) 0, OCI_OTYPE_PTR, (ub1)1, + (ub1) OCI_PTYPE_TYPE, dschp)); + + checkerr(errhp, OCIAttrGet((dvoid *) dschp, (ub4) OCI_HTYPE_DESCRIBE, + (dvoid *)&parmp, (ub4 *)0, (ub4)OCI_ATTR_PARAM, errhp)); + + checkerr(errhp, OCIAttrGet((dvoid*) parmp,(ub4) OCI_DTYPE_PARAM, + (dvoid*) &typenamep, (ub4 *) &str_len, + (ub4) OCI_ATTR_NAME, (OCIError *) errhp)); + typenamep[str_len] = '\0'; + + printf("starting displaying instance of type '%s'\n", typenamep); + + /* loop through all attributes in the type */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &count, (ub4 *) 0, + (ub4) OCI_ATTR_NUM_TYPE_ATTRS, (OCIError *) errhp)); + + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&list_attr, (ub4 *)0, + (ub4)OCI_ATTR_LIST_TYPE_ATTRS, (OCIError *)errhp)); + + /* loop through all attributes in the type */ + for (pos = 1; pos <= count; pos++) + { + + checkerr(errhp, OCIParamGet((dvoid *) list_attr, + (ub4) OCI_DTYPE_PARAM, errhp, + (dvoid *)&parmdp, (ub4) pos)); + + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &str_len, + (ub4) OCI_ATTR_NAME, (OCIError *) errhp)); + namep[str_len] = '\0'; + + /* get the attribute */ + if (OCIObjectGetAttr(envhp, errhp, obj, null_obj, tdo, + (CONST oratext **)&namep, &str_len, 1, + (ub4 *)0, 0, &attr_null_status, &attr_null_struct, + &attr_value, &attr_tdo) != OCI_SUCCESS) + (void) printf("BUG -- OCIObjectGetAttr, expect OCI_SUCCESS.\n"); + + /* get the type code of the attribute */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &typecode, (ub4 *) 0, + (ub4) OCI_ATTR_TYPECODE, + (OCIError *) errhp)); + + /* support only fixed length string, ref and embedded ADT */ + switch (typecode) + { + case OCI_TYPECODE_OBJECT : /* embedded ADT */ + printf("attribute %s is an embedded ADT. Display instance ....\n", + namep); + /* recursive call to dump nested ADT data */ + dump_adt(envhp, errhp, svchp, attr_tdo, attr_value, + attr_null_struct); + break; + case OCI_TYPECODE_REF : /* embedded ADT */ + printf("attribute %s is a ref. Pin and display instance ...\n", + namep); + /* pin the object */ + if (OCIObjectPin(envhp, errhp, *(OCIRef **)attr_value, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&object) != OCI_SUCCESS) + (void) printf("BUG -- OCIObjectPin, expect OCI_SUCCESS.\n"); + /* allocate the ref */ + if (( status = OCIObjectNew(envhp, errhp, svchp, + OCI_TYPECODE_REF, (OCIType *)0, + (dvoid *)0, OCI_DURATION_DEFAULT, TRUE, + (dvoid **) &type_ref)) != OCI_SUCCESS) + (void) printf("BUG -- OCIObjectNew, expect OCI_SUCCESS.\n"); + /* get the ref of the type from the object */ + if (( status = OCIObjectGetTypeRef(envhp, errhp, object, type_ref)) + != OCI_SUCCESS) + (void) printf("BUG -- ORIOGTR, expect OCI_SUCCESS.\n"); + /* pin the type ref to get the type object */ + if (OCIObjectPin(envhp, errhp, type_ref, (OCIComplexObject *)0, + OCI_PIN_ANY, OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **) &object_tdo) != OCI_SUCCESS) + (void) printf("BUG -- OCIObjectPin, expect OCI_SUCCESS.\n"); + /* get null struct of the object */ + if (( status = OCIObjectGetInd(envhp, errhp, object, + &null_object)) != OCI_SUCCESS) + (void) printf("BUG -- ORIOGNS, expect OCI_SUCCESS.\n"); + /* call the function recursively to dump the pinned object */ + dump_adt(envhp, errhp, svchp, object_tdo, object, + null_object); + case OCI_TYPECODE_NAMEDCOLLECTION : + checkerr(errhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **) &dschp1, + (ub4) OCI_HTYPE_DESCRIBE, + (size_t) 0, (dvoid **) 0)); + + checkerr(errhp, OCIDescribeAny(svchp, errhp, (dvoid *) attr_tdo, + (ub4) 0, OCI_OTYPE_PTR, (ub1)1, + (ub1) OCI_PTYPE_TYPE, dschp1)); + + checkerr(errhp, OCIAttrGet((dvoid *) dschp1, + (ub4) OCI_HTYPE_DESCRIBE, + (dvoid *)&parmp1, (ub4 *)0, (ub4)OCI_ATTR_PARAM, errhp)); + + /* get the collection type code of the attribute */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp1, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &typecode, (ub4 *) 0, + (ub4) OCI_ATTR_COLLECTION_TYPECODE, + (OCIError *) errhp)); + switch (typecode) + { + case OCI_TYPECODE_VARRAY : /* variable array */ + (void) printf + ("\n---> Dump the table from the top to the bottom.\n"); + checkerr(errhp, OCIAttrGet((dvoid*) parmp1, + (ub4) OCI_DTYPE_PARAM, + (dvoid*) &parmp2, (ub4 *) 0, + (ub4) OCI_ATTR_COLLECTION_ELEMENT, + (OCIError *) errhp)); + checkerr(errhp, OCIAttrGet((dvoid*) parmp2, + (ub4) OCI_DTYPE_PARAM, + (dvoid*) &elem_ref, (ub4 *) 0, + (ub4) OCI_ATTR_REF_TDO, + (OCIError *) errhp)); + checkerr(errhp, OCITypeByRef(envhp, errhp, elem_ref, + OCI_PIN_DEFAULT, (OCITypeGetOpt)0, &element_type)); + /* initialize the iterator */ + checkerr(errhp, OCIIterCreate(envhp, errhp, + (CONST OCIColl*) attr_value, &itr)); + /* loop through the iterator */ + for(eoc = FALSE;!OCIIterNext(envhp, errhp, itr, + (dvoid **) &element, + (dvoid **)&null_element, &eoc) && !eoc;) + { + /* if type is named type, call the same function recursively + */ + if (typecode == OCI_TYPECODE_OBJECT) + dump_adt(envhp, errhp, svchp, element_type, element, + null_element); + else /* else, display the scaler type attribute */ + display_attr_val(envhp, errhp, namep, typecode, element); + } + break; + + case OCI_TYPECODE_TABLE : /* nested table */ + (void) printf + ("\n---> Dump the table from the top to the bottom.\n"); + /* go to the first element and print out the index */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp1, + (ub4) OCI_DTYPE_PARAM, + (dvoid*) &parmp2, (ub4 *) 0, + (ub4) OCI_ATTR_COLLECTION_ELEMENT, + (OCIError *) errhp)); + checkerr(errhp, OCIAttrGet((dvoid*) parmp2, + (ub4) OCI_DTYPE_PARAM, + (dvoid*) &elem_ref, (ub4 *) 0, + (ub4) OCI_ATTR_REF_TDO, + (OCIError *) errhp)); + checkerr(errhp, OCITypeByRef(envhp, errhp, elem_ref, + OCI_DURATION_SESSION, + OCI_TYPEGET_HEADER, &element_type)); + attr_value = *(dvoid **)attr_value; + /* move to the first element in the nested table */ + checkerr(errhp, OCITableFirst(envhp, errhp, + (CONST OCITable*) attr_value, &index)); + (void) printf + (" The index of the first element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, + (CONST OCIColl *) attr_value, index, + &exist, (dvoid **) &element, + (dvoid **) &null_element)); + /* if it is named type, recursively call the same function */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp2, + (ub4) OCI_DTYPE_PARAM, + (dvoid*) &typecode, (ub4 *) 0, + (ub4) OCI_ATTR_TYPECODE, + (OCIError *) errhp)); + if (typecode == OCI_TYPECODE_OBJECT) + dump_adt(envhp, errhp, svchp, element_type, + (dvoid *)element, (dvoid *)null_element); + else + display_attr_val(envhp, errhp, namep, typecode, element); + + for(;!OCITableNext(envhp, errhp, index, + (CONST OCITable *) attr_value, + &index, &exist) && exist;) + { + checkerr(errhp, OCICollGetElem(envhp, errhp, + (CONST OCIColl *) attr_value, index, + &exist, (dvoid **) &element, + (dvoid **) &null_element)); + if (typecode == OCI_TYPECODE_OBJECT) + dump_adt(envhp, errhp, svchp, element_type, + (dvoid *)element, (dvoid *)null_element); + else + display_attr_val(envhp, errhp, namep, typecode, element); + } + break; + default: + break; + } + checkerr(errhp, OCIHandleFree((dvoid *) dschp1, + (ub4) OCI_HTYPE_DESCRIBE)); + break; + default: /* scaler type, display the attribute value */ + if (attr_null_status == OCI_IND_NOTNULL) + { + display_attr_val(envhp, errhp, namep, typecode, attr_value); + } + else + printf("attr %s is null\n", namep); + break; + } + } + + printf("finishing displaying instance of type '%s'\n", typenamep); + checkerr(errhp, OCIHandleFree((dvoid *) dschp, (ub4) OCI_HTYPE_DESCRIBE)); +} + + +/**************************************************************************** +* Setup the schema and insert the data * +*****************************************************************************/ +void setup(envhp, svchp, stmthp, errhp) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIError *errhp; +{ + /* create the schema and populate the data */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) create_type_address, + (ub4) strlen((char *) create_type_address), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) create_type_addr_tab, + (ub4) strlen((char *) create_type_addr_tab), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) create_type_person, + (ub4) strlen((char *) create_type_person), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) create_type_customer, + (ub4) strlen((char *) create_type_customer), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) create_table_person, + (ub4) strlen((char *) create_table_person), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) create_table_customer, + (ub4) strlen((char *) create_table_customer), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) insert_customer, + (ub4) strlen((char *) insert_customer), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) insert_person, + (ub4) strlen((char *) insert_person), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) insert_address1, + (ub4) strlen((char *) insert_address1), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) insert_address2, + (ub4) strlen((char *) insert_address2), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) update_customer, + (ub4) strlen((char *) update_customer), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); +} + + +/*****************************************************************************/ +void select_pin_display(envhp, svchp, stmthp, errhp) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIError *errhp; +{ + sword status = OCI_SUCCESS; + OCIDefine *defnp; + OCIRef *custref = (OCIRef *) 0, *per_type_ref = (OCIRef *) 0; + OCIRef *cust_type_ref = (OCIRef *) 0; + ub4 custsize; + customer *cust = (customer *) 0, *custnew = (customer *) 0; + null_customer *null_cust = (null_customer *) 0, + *null_custnew = (null_customer *) 0; + person *per = (person *) 0; + null_person *null_per = (null_person *) 0; + null_address *nt_null = (null_address *) 0; + OCIType *pertdo = (OCIType *) 0, *custtdo = (OCIType *) 0; + address *addr = (address *) 0; + sb4 index; + boolean exist; + dvoid *tabobj = (dvoid *) 0; + + (void) printf("\n=============================================\n"); + + /* allocate ref */ + if (( status = OCIObjectNew(envhp, errhp, svchp, OCI_TYPECODE_REF, + (OCIType *)0, (dvoid *)0, OCI_DURATION_DEFAULT, + TRUE, (dvoid **) &per_type_ref)) + != OCI_SUCCESS) + (void) printf("BUG -- OCIObjectNew, expect OCI_SUCCESS.\n"); + + /* allocate ref */ + if (( status = OCIObjectNew(envhp, errhp, svchp, OCI_TYPECODE_REF, + (OCIType *)0, (dvoid *)0, OCI_DURATION_DEFAULT, + TRUE, (dvoid **) &cust_type_ref)) + != OCI_SUCCESS) + (void) printf("BUG -- OCIObjectNew, expect OCI_SUCCESS.\n"); + + /* define the application request */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) selref, + (ub4) strlen((char *) selref), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + +/* + checkerr(errhp, OCIHandleAlloc( (dvoid *) stmthp, (dvoid **) &defnp, + (ub4) OCI_HTYPE_DEFINE, + 0, (dvoid **) 0)); +*/ + + checkerr(errhp, OCIDefineByPos(stmthp, &defnp, errhp, (ub4) 1, (dvoid *) 0, + (sb4) 0, SQLT_REF, (dvoid *) 0, (ub2 *)0, + (ub2 *)0, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIDefineObject(defnp, errhp, (OCIType *) 0, + (dvoid **) &custref, + &custsize, (dvoid **) 0, (ub4 *) 0)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 0, + (ub4) 0, (OCISnapshot *) + NULL, (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)); + + while ((status = OCIStmtFetch(stmthp, errhp, (ub4) 1, (ub4) OCI_FETCH_NEXT, + (ub4) OCI_DEFAULT)) == 0) + { + + (void) printf("\n-----------------------------------------\n"); + + /* pin the ref and get the typed table to get to person */ + checkerr(errhp, OCIObjectPin(envhp, errhp, custref, + (OCIComplexObject *)0, + OCI_PIN_ANY, OCI_DURATION_SESSION, + OCI_LOCK_NONE, (dvoid **) &cust)); + (void) printf("The customer account number is %s\n", + OCIStringPtr(envhp, cust->account)); + if (( status = OCIObjectGetInd(envhp, errhp, (dvoid *) cust, + (dvoid **) &null_cust)) != OCI_SUCCESS) + { + (void) printf("BUG -- ORIOGNS, expect OCI_SUCCESS.\n"); + } + else + { + (void) printf("null_cus = %d, null_account = %d, null_aperson = %d\n", + null_cust->null_cus, null_cust->null_account, + null_cust->null_aperson); + } + + checkerr(errhp, OCIObjectPin(envhp, errhp, cust->aperson, + (OCIComplexObject *)0, + OCI_PIN_ANY, OCI_DURATION_SESSION, + OCI_LOCK_NONE, (dvoid **) &per)); + + if (( status = OCIObjectGetInd(envhp, errhp, (dvoid *) per, + (dvoid **) &null_per)) != OCI_SUCCESS) + { + (void) printf("BUG -- ORIOGNS, expect OCI_SUCCESS.\n"); + } + else + { + checkerr(errhp, OCIObjectGetTypeRef(envhp, errhp, (dvoid *)per, + per_type_ref)); + checkerr(errhp, OCIObjectPin(envhp, errhp, per_type_ref, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **) &pertdo)); + dump_adt(envhp, errhp, svchp, pertdo, (dvoid *) per, + (dvoid *) null_per); + } + } + + if ( status != OCI_NO_DATA ) + checkerr(errhp, status); + + (void) printf("\n\n"); +} + + +/**************************************************************************** +* Clean up the schema and the data * +*****************************************************************************/ +void cleanup(envhp, svchp, stmthp, errhp) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIError *errhp; +{ + /* clean up the schema */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, + (text *) "drop table customer_tab", + (ub4) strlen((char *)"drop table customer_tab" ), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) + NULL, (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, + (text *) "drop table person_tab", + (ub4) strlen((char *)"drop table person_tab" ), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) + NULL, (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) "drop type customer", + (ub4) strlen((char *)"drop table customer" ), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) + NULL, (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) "drop type person", + (ub4) strlen((char *)"drop table person" ), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) + NULL, (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) "drop type addr_tab", + (ub4) strlen((char *)"drop table addr_tab" ), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) + NULL, (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) "drop type address", + (ub4) strlen((char *) "drop type address"), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) + NULL, (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); +} + + +/*****************************************************************************/ +int main() +{ + OCIEnv *envhp; + OCIServer *srvhp; + OCIError *errhp; + OCISvcCtx *svchp; + OCISession *usrhp; + OCIStmt *stmthp; + dvoid *tmp; + + /* initialize the process */ + (void) OCIInitialize((ub4) OCI_THREADED | OCI_OBJECT, + (dvoid *)0, (dvoid * (*)()) 0, + (dvoid * (*)()) 0, (void (*)()) 0 ); + + /* initialize the environmental handle */ + (void) OCIEnvInit( &envhp, (ub4) OCI_DEFAULT, 21, (dvoid **) &tmp ); + + /* get the error handle */ + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, + 52, (dvoid **) &tmp); + + /* two server contexts */ + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, + 52, (dvoid **) &tmp); + /* attach the server */ + (void) OCIServerAttach( srvhp, errhp, (text *) "", (sb4) 0, + (ub4) OCI_DEFAULT); + + /* get the service handle */ + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, + 52, (dvoid **) &tmp); + + /* set attribute server context in the service context */ + (void) OCIAttrSet( (dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, + (ub4) OCI_ATTR_SERVER, (OCIError *) errhp); + + /* get the user handle */ + (void) OCIHandleAlloc((dvoid *)envhp, (dvoid **)&usrhp, + (ub4)OCI_HTYPE_SESSION, 0, (dvoid **)0); + + /* set the attribute user name */ + (void) OCIAttrSet((dvoid *) usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"scott", (ub4)strlen((char *)"scott"), + (ub4)OCI_ATTR_USERNAME, errhp); + + /* set the attribute password */ + (void) OCIAttrSet((dvoid *) usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"tiger", (ub4)strlen((char *)"tiger"), + (ub4)OCI_ATTR_PASSWORD, errhp); + + /* authenticate */ + checkerr(errhp, OCISessionBegin (svchp, errhp, usrhp, + OCI_CRED_RDBMS, OCI_DEFAULT)); + + /* set the attribute user context of the service handle */ + (void) OCIAttrSet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)usrhp, (ub4)0, + (ub4)OCI_ATTR_SESSION, errhp); + + /* get the statement handle */ + checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp, + (ub4) OCI_HTYPE_STMT, 50, (dvoid **) &tmp)); + + (void) printf("\n*********************************************\n"); + (void) printf("--- Setup the schema and insert the data.\n"); + setup(envhp, svchp, stmthp, errhp); + + (void) printf("\n*********************************************\n"); + (void) printf("--- Select a REF, pin the REF, then display the object.\n"); + select_pin_display(envhp, svchp, stmthp, errhp); + + (void) printf("\n*********************************************\n"); + (void) printf("--- Clean up the schema and the data.\n"); + cleanup(envhp, svchp, stmthp, errhp); + + checkerr(errhp, OCISessionEnd (svchp, errhp, usrhp, OCI_DEFAULT)); + + /* dettach */ + (void) OCIServerDetach( srvhp, errhp, (ub4) OCI_DEFAULT ); + checkerr(errhp, OCIHandleFree((dvoid *) stmthp, (ub4) OCI_HTYPE_STMT)); + checkerr(errhp, OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX)); + checkerr(errhp, OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR)); + checkerr(errhp, OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER)); + + return (0); +} + diff --git a/cdemobj.h b/cdemobj.h new file mode 100644 index 0000000..27c42d4 --- /dev/null +++ b/cdemobj.h @@ -0,0 +1,150 @@ +/* + * $Header: cdemobj.h 17-feb-2005.17:47:43 aliu Exp $ + */ + +/* Copyright (c) 1995, 2005, Oracle. All rights reserved. +*/ + +/* + NAME + cdemobj.h + + DESCRIPTION + This file contains the header information for the cdemobj.c + + RELATED DOCUMENTS + None. + + INSPECTION STATUS + Inspection date: + Inspection status: + Estimated increasing cost defects per page: + Rule sets: + + ACCEPTANCE REVIEW STATUS + Review date: + Review status: + Reviewers: + + PUBLIC FUNCTION(S) + None. + + PRIVATE FUNCTION(S) + As defined below. + + EXAMPLES + + NOTES + + MODIFIED (MM/DD/YY) + aliu 02/17/05 - lint issues + aliu 02/16/05 - fix bug 4184313 + aliu 12/07/00 - fix bug 1237851: add #include . + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + skmishra 05/14/97 - stdcc compatibility changes + azhao 03/28/97 - include ocikp.h + echen 11/15/96 - remove unnecessary header files + dchatter 07/18/96 - delete spurious .h files + echen 07/16/96 - Creation +*/ + +#ifndef CDEMOBJ_ORACLE +#define CDEMOBJ_ORACLE + +#ifndef OCI_ORACLE +#include +#endif + +#include + +#include + +#ifndef ORID_ORACLE +#include +#endif + +/*--------------------------------------------------------------------------- + PUBLIC TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ +struct address +{ + OCINumber no; + OCIString *street; + OCIString *state; + OCIString *zip; +}; +typedef struct address address; + +struct null_address +{ + sb2 null_addr; + sb2 null_no; + sb2 null_street; + sb2 null_state; + sb2 null_zip; +}; +typedef struct null_address null_address; + +struct person +{ + OCIString *fname; + OCIString *lname; + OCINumber age; + OCINumber salary; + OCINumber bonus; + OCINumber retirement_fund; + OCINumber number_of_kids; + OCINumber years_of_school; + OCITable *preaddr; + OCIDate birthday; + OCINumber number_of_pets; + OCIRaw *comment1; + OCILobLocator *comment2; + OCIString *comment3; + address addr; +}; +typedef struct person person; + +struct null_person +{ + OCIInd null_per; + OCIInd null_fname; + OCIInd null_lname; + OCIInd null_age; + OCIInd null_salary; + OCIInd null_bonus; + OCIInd null_retirement_fund; + OCIInd null_number_of_kids; + OCIInd null_years_of_school; + OCIInd null_preaddr; + OCIInd null_birthday; + OCIInd null_number_of_pets; + OCIInd null_comment1; + OCIInd null_comment2; + OCIInd null_comment3; + null_address null_addr; +}; +typedef struct null_person null_person; + +struct customer +{ + OCIString *account; + OCIRef *aperson; +}; +typedef struct customer customer; + +struct null_customer +{ + OCIInd null_cus; + OCIInd null_account; + OCIInd null_aperson; +}; +typedef struct null_customer null_customer; + +int main(/*_ void _*/); + +#endif /* TKPOTTA_ORACLE */ diff --git a/cdemocoll.c b/cdemocoll.c new file mode 100644 index 0000000..4ce4d1d --- /dev/null +++ b/cdemocoll.c @@ -0,0 +1,720 @@ +/* Copyright (c) 2004, 2006, Oracle. All rights reserved. */ + +/* + + NAME + cdemocoll.c - collection demo program in OCI + + DESCRIPTION - demo of insertion(bind) and selection(define) of collection + columns (nested table and varray) as named datatype SQLT_NTY + using OCI interface. + + Note: Before running this program, ensure that the database is + started up and tables of cdemocoll_customer_nt and + cdemocoll_customer_va and types of cdemocoll_int_nt and + cdemocoll_char_va do not exist in SCOTT/TIGER sample account. + + + EXPORT FUNCTION(S) + + + INTERNAL FUNCTION(S) + + + STATIC FUNCTION(S) + + + NOTES + + + MODIFIED (MM/DD/YY) + azhao 10/10/06 - case-senstive password change + aliu 05/06/04 - aliu_add_coll_demo + aliu 05/04/04 - Creation + +*/ + +#ifndef CDEMOCOLL +#define CDEMOCOLL + +/*------------------------------------------------------------------------ + * Include Files + */ + +#ifndef ORATYPES +#include +#endif + +#ifndef STDIO +#include +#endif + +#ifndef STDLIB +#include +#endif + +#ifndef STRING +#include +#endif + +#ifndef OCI_ORACLE +#include +#endif + +#ifndef CDEMOCOLL_ORACLE +#include "cdemocoll.h" +#endif + +/*----------------- End of including files -----------------*/ + +/*--------------------- Public Constants and Variables ----------------------*/ + +/* constants */ +#define MAXBUFLEN 200 + +/* database login information */ +static text *user=(text *)"SCOTT"; +static text *password=(text *)"tiger"; + +/* OCI Handles and Variables */ +static OCIEnv *envhp; +static OCIServer *srvhp; +static OCISvcCtx *svchp; +static OCIError *errhp; +static OCISession *authp; +static OCIStmt *stmthp; + +/* Misellaneous */ +static sword status; +static boolean tab_exists = FALSE; + +/*----------------- End of Constants and Variables -----------------*/ + +/*--------------------- Functions Declaration --------------------*/ + +static void checkerr(/*_ OCIError *errhp, sword status _*/); +static void cleanup(/*_ void _*/); +static sb4 connect_server(/*_ void _*/); +static void disconnect_server(/*_ void _*/); +static void drop_table(/*_ void _*/); +static sb4 init_env_handle(/*_ void _*/); +static sb4 init_table(/*_ void _*/); +static sb4 insert_coll(/*_ ub4 custno, ub4 flag _*/); +static sb4 select_coll(/*_ ub4 custno, ub4 flag _*/); + +/*--------------------- End of Functions Declaration --------------------*/ + +#endif + + +/*---------------------------Main function -----------------------------*/ +int main() +{ + ub4 custno; + ub4 flag; + + /* Initialize the environment and allocate handles */ + if (init_env_handle()) + { + printf("FAILED: init_env_handle()!\n"); + return OCI_ERROR; + } + + /* Log on to the server and begin a session */ + if (connect_server()) + { + printf("FAILED: connect_server()!\n"); + cleanup(); + return OCI_ERROR; + } + + /* Initialize the types/tables */ + if (init_table()) + { + printf("FAILED: init_table()\n"); + disconnect_server(); + return OCI_ERROR; + } + + custno = 1; + /* flag = 1: nested table column + otherwise: varray column */ + for (flag = 1; flag <= 2; flag++) { + /* Insertion */ + if (insert_coll(custno, flag)) + { + printf("FAILED: insert_coll()!\n"); + disconnect_server(); + return OCI_ERROR; + } + + /* Selection */ + if (select_coll(custno, flag)) + { + printf("FAILED: select_coll()!\n"); + disconnect_server(); + return OCI_ERROR; + } + } + + /* Drop types/tables, detach from a server, and clean up the environment */ + disconnect_server(); + + return OCI_SUCCESS; +} + + +/*---------------------------Subfunctions -----------------------------*/ + +/*--------------------------------------------------------*/ +/* Return corresponding messages in differrent cases */ +/*--------------------------------------------------------*/ +void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text msgbuf[512]; + sb4 errcode = 0; + + memset((void *) msgbuf, (int)'\0', (size_t)512); + + switch (status) + { + case OCI_SUCCESS: break; + case OCI_SUCCESS_WITH_INFO: + printf("status = OCI_SUCCESS_WITH_INFO\n"); + OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + printf("ERROR CODE = %d\n", errcode); + printf("%.*s\n", 512, msgbuf); + if (errcode == 436 || errcode == 437 || errcode == 438 || errcode == 439) + exit(1); + break; + case OCI_NEED_DATA: + printf("status = OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + printf("status = OCI_NO_DATA\n"); + break; + case OCI_ERROR: + printf("status = OCI_ERROR\n"); + OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + printf("ERROR CODE = %d\n", errcode); + printf("%.*s\n", 512, msgbuf); + if (errcode == 436 || errcode == 437 || errcode == 438 || errcode == 439) + exit(1); + break; + case OCI_INVALID_HANDLE: + printf("status = OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + printf("status = OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + printf("status = OCI_CONTINUE\n"); + break; + default: + break; + } + + return; +} + + +/*--------------------------------------------------------*/ +/* Free the envhp whenever there is an error */ +/*--------------------------------------------------------*/ +void cleanup() +{ + if (envhp) { + OCIHandleFree((dvoid *)envhp, OCI_HTYPE_ENV); + } + + return; +} + + +/*--------------------------------------------------------*/ +/* attach to server, set attributes, and begin session */ +/*--------------------------------------------------------*/ +sb4 connect_server() +{ + /* attach to server */ + if (status = OCIServerAttach((OCIServer *) srvhp, (OCIError *) errhp, + (text *) "", (sb4) strlen(""), (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIServerAttach() on srvhp\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* set server attribute to service context */ + if (status = OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, (ub4) OCI_ATTR_SERVER, + (OCIError *) errhp)) + { + printf("FAILED: OCIAttrSet() on svchp\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* set user attribute to session */ + if (status = OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) user, (ub4) strlen((char *)user), + (ub4) OCI_ATTR_USERNAME, (OCIError *) errhp)) + { + printf("FAILED: OCIAttrSet() on authp for user\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* set password attribute to session */ + if (status = OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) password, (ub4) strlen((char *)password), + (ub4) OCI_ATTR_PASSWORD, (OCIError *) errhp)) + { + printf("FAILED: OCIAttrSet() on authp for password\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* Begin a session */ + if (status = OCISessionBegin((OCISvcCtx *) svchp, (OCIError *) errhp, + (OCISession *) authp, (ub4) OCI_CRED_RDBMS, + (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCISessionBegin()\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* set session attribute to service context */ + if (status = OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) authp, (ub4) 0, (ub4) OCI_ATTR_SESSION, + (OCIError *) errhp)) + { + printf("FAILED: OCIAttrSet() on svchp\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* End the session, detach server and free handles. */ +/*--------------------------------------------------------*/ +void disconnect_server() +{ + printf("\n\nLogged off and detached from server.\n"); + + /* Drop the tables/types if any */ + if (tab_exists) + drop_table(); + + /* End a session */ + if (status = OCISessionEnd((OCISvcCtx *)svchp, (OCIError *)errhp, + (OCISession *)authp, (ub4) OCI_DEFAULT)) { + checkerr(errhp, status); + cleanup(); + return; + } + + /* Detach from the server */ + if (status = OCIServerDetach((OCIServer *)srvhp, (OCIError *)errhp, + (ub4)OCI_DEFAULT)) { + checkerr(errhp, status); + cleanup(); + return; + } + + /* Free the handles */ + if (stmthp) { + OCIHandleFree((dvoid *)stmthp, (ub4) OCI_HTYPE_STMT); + } + if (authp) { + OCIHandleFree((dvoid *)authp, (ub4) OCI_HTYPE_SESSION); + } + if (svchp) { + OCIHandleFree((dvoid *)svchp, (ub4) OCI_HTYPE_SVCCTX); + } + if (srvhp) { + OCIHandleFree((dvoid *)srvhp, (ub4) OCI_HTYPE_SERVER); + } + if (errhp) { + OCIHandleFree((dvoid *)errhp, (ub4) OCI_HTYPE_ERROR); + } + if (envhp) { + OCIHandleFree((dvoid *)envhp, (ub4) OCI_HTYPE_ENV); + } + + return; +} + + +/*--------------------------------------------------------*/ +/* Drop tables/types */ +/*--------------------------------------------------------*/ +void drop_table() +{ + text *dropstmt[4] = { (text *) "drop table cdemocoll_customer_nt", + (text *) "drop type cdemocoll_int_nt", + (text *) "drop table cdemocoll_customer_va", + (text *) "drop type cdemocoll_char_va" }; + int i=0; + + for (i=0; i<4; i++) { + + /* prepare drop statement */ + if (OCIStmtPrepare(stmthp, errhp, dropstmt[i], (ub4) strlen((char *) dropstmt[i]), (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIStmtPrepare() dropstmt\n"); + return; + } + /* execute drop statement */ + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) 0, (OCISnapshot *) 0, + (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIStmtExecute() dropstmt\n"); + return; + } + + } /* end of for (i=0; ... ) */ + + return; +} + + +/*--------------------------------------------------------*/ +/* Initialize the environment and allocate handles */ +/*--------------------------------------------------------*/ +sb4 init_env_handle() +{ + /* Environment initialization and creation */ + if (OCIEnvCreate((OCIEnv **) &envhp, (ub4) OCI_OBJECT, (dvoid *) 0, + (dvoid * (*)(dvoid *,size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t)) 0, + (void (*)(dvoid *, dvoid *)) 0, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIEnvCreate()\n"); + return OCI_ERROR; + } + + /* allocate error handle */ + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on errhp\n"); + return OCI_ERROR; + } + + /* allocate server handle */ + if (status = OCIHandleAlloc((dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on srvhp\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* allocate service context handle */ + if (status = OCIHandleAlloc((dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on svchp\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* allocate session handle */ + if (status = OCIHandleAlloc((dvoid *) envhp, (dvoid **) &authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on authp\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* Allocate statement handle */ + if (status = OCIHandleAlloc((dvoid *) envhp, (dvoid **) &stmthp, + (ub4) OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on stmthp\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* create types and tables */ +/*--------------------------------------------------------*/ +sb4 init_table() +{ + int colc; + text *crtstmt[4] = { (text *) "create type cdemocoll_int_nt is table of integer", + (text *) "create table cdemocoll_customer_nt (custno number, income cdemocoll_int_nt)\ + nested table income store as cdemocoll_income_table", + (text *) "create type cdemocoll_char_va is varray(10) of char(20)", + (text *) "create table cdemocoll_customer_va (custno number, names cdemocoll_char_va)" }; + int i=0; + + for (i=0; i<4; i++) { + + /* prepare create statement */ + if (status = OCIStmtPrepare(stmthp, errhp, crtstmt[i], (ub4) strlen((char *) crtstmt[i]), (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIStmtPrepare() crtstmt\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + /* execute create statement */ + if (status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) 0, (OCISnapshot *) 0, + (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIStmtExecute() crtstmt\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* commit the Xn */ + OCITransCommit(svchp, errhp, (ub4)0); + + } /* end of for (i=0; ... ) */ + + /* set flag to be used by disconnect_server() to drop the tables */ + tab_exists = TRUE; + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* insert collection column into the table */ +/* flag = 1: nested table column + otherwise: varray column */ +/*--------------------------------------------------------*/ +sb4 insert_coll(custno, flag) +ub4 custno; +ub4 flag; +{ + text inst[MAXBUFLEN]; + OCIBind *bndp1 = (OCIBind *)0; + OCIBind *bndp2 = (OCIBind *)0; + OCIType *coll_tdo= (OCIType *)0; + OCIColl *ptrcoll = (OCIColl *)0; + ub4 i = 0, elem = 0; + OCINumber ocinum; + OCIString *ocistr = (OCIString *)0; + text *str[5] = { (text *)"Andy", (text *)"Bill", (text *)"Cathy", + (text *)"David", (text *)"Eddy" }; + + if (flag == 1) { + strcpy((char *)inst, (char *)"INSERT INTO cdemocoll_customer_nt VALUES (:num, :coll)"); + } + else { + strcpy((char *)inst, (char *)"INSERT INTO cdemocoll_customer_va VALUES (:num, :coll)"); + } + + printf("\n=> %s for custno %d ......\n", inst, custno); + + /* get type information */ + OCITypeByName(envhp, errhp, svchp, (CONST text *)"", (ub4)0, + (CONST text *) ((flag == 1) ? "CDEMOCOLL_INT_NT" : "CDEMOCOLL_CHAR_VA"), + (ub4) ((flag == 1) ? strlen("CDEMOCOLL_INT_NT") : strlen("CDEMOCOLL_CHAR_VA")), + (CONST text *) 0, (ub4) 0, OCI_DURATION_SESSION, + OCI_TYPEGET_HEADER, &coll_tdo); + + /* instantiate the collection */ + OCIObjectNew(envhp, errhp, svchp, + ((flag == 1) ? OCI_TYPECODE_TABLE : OCI_TYPECODE_VARRAY), + (OCIType *) coll_tdo, + (dvoid *) 0, OCI_DURATION_SESSION, TRUE, + (dvoid **) &ptrcoll); + + if (flag == 1) { + /* populate the nested table */ + for (i = 0; i < 5; i++) + { + elem = i; + checkerr(errhp,OCINumberFromInt(errhp, &elem, sizeof(elem), OCI_NUMBER_UNSIGNED, + &ocinum)); + checkerr(errhp,OCICollAppend(envhp, errhp, (CONST dvoid *)&ocinum, + (dvoid *) 0, (OCIColl *) ptrcoll)); + } + } + else { + /* populate VARRAY */ + for (i = 0; i < 5; i++) + { + checkerr(errhp, OCIStringAssignText(envhp, + errhp, str[i], (ub4)strlen((char *) str[i]), + &ocistr)); + checkerr(errhp, OCICollAppend(envhp, + errhp, (CONST dvoid *)ocistr, (dvoid *) 0, + (OCIColl *) ptrcoll)); + } + } + + /* insert the collection column into the table */ + printf ("\n ######## inserting the collection ############ \n"); + OCIStmtPrepare(stmthp, errhp, inst, (ub4) strlen((char *)inst), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT); + + i = custno; + OCIBindByName(stmthp, &bndp1, errhp, + (text *)":num", (sb4)strlen(":num"), (dvoid*)&i, sizeof(i), + SQLT_INT, (dvoid*)0, (ub2*)0, (ub2*)0, (ub4)0, (ub4*)0, + OCI_DEFAULT); + + OCIBindByName(stmthp, &bndp2, errhp, + (text *)":coll", (sb4)strlen (":coll"), (dvoid*)0, (sb4)0, + SQLT_NTY, (dvoid*)0, (ub2*)0, (ub2*)0, (ub4)0, (ub4*)0, + OCI_DEFAULT); + if (status = OCIBindObject(bndp2, errhp, coll_tdo, (dvoid **) &ptrcoll, (ub4 *) 0, + (dvoid **)0, (ub4 *) 0)) { + checkerr(errhp, status); + } + + if (status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, (OCISnapshot *)NULL, + (OCISnapshot *)NULL, OCI_COMMIT_ON_SUCCESS)) { + checkerr(errhp, status); + } + + /* free the collection */ + OCIObjectFree(envhp, errhp, ptrcoll, OCI_OBJECTFREE_FORCE); + + printf("\n=> Insertion done\n"); + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* select collection column from the table */ +/* flag = 1: nested table column + otherwise: varray column */ +/*--------------------------------------------------------*/ +sb4 select_coll(custno, flag) +ub4 custno; +ub4 flag; +{ + text sel[MAXBUFLEN]; + OCIDefine *defp1 = (OCIDefine *)0; + OCIBind *bndp1 = (OCIBind *)0; + OCIType *coll_tdo= (OCIType *)0; + OCIColl *ptrcoll = (OCIColl *)0; + ub4 i = 0; + dvoid *elem = (dvoid *)0; + ub4 size = 0; + boolean exists = FALSE; + int nt_value = 0; + OCIString *va_value = (OCIString *)0; + + if (flag == 1) { + strcpy((char *)sel, (char *)"SELECT income FROM cdemocoll_customer_nt WHERE custno = :num"); + } + else { + strcpy((char *)sel, (char *)"SELECT names FROM cdemocoll_customer_va WHERE custno = :num"); + } + + printf("\n=> %s for custno %d ......\n", sel, custno); + + /* get type information */ + /* get type information */ + OCITypeByName(envhp, errhp, svchp, (CONST text *)"", (ub4)0, + (CONST text *) ((flag == 1) ? "CDEMOCOLL_INT_NT" : "CDEMOCOLL_CHAR_VA"), + (ub4) ((flag == 1) ? strlen("CDEMOCOLL_INT_NT") : strlen("CDEMOCOLL_CHAR_VA")), + (CONST text *) 0, (ub4) 0, OCI_DURATION_SESSION, + OCI_TYPEGET_HEADER, &coll_tdo); + + /* instantiate the collection */ + OCIObjectNew(envhp, errhp, svchp, + ((flag == 1) ? OCI_TYPECODE_TABLE : OCI_TYPECODE_VARRAY), + (OCIType *) coll_tdo, + (dvoid *) 0, OCI_DURATION_SESSION, TRUE, + (dvoid **) &ptrcoll); + + /* select the collection column from the table */ + printf ("\n ######## selecting the collection ############ \n"); + OCIStmtPrepare(stmthp, errhp, sel, (ub4) strlen((char *)sel), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT); + + OCIDefineByPos(stmthp, &defp1, errhp, (ub4) 1, (dvoid *)0, + (sb4) 0, SQLT_NTY, (dvoid *) 0, + (ub2 *)0, (ub2 *)0, (ub4) OCI_DEFAULT); + if (status = OCIDefineObject(defp1, errhp, coll_tdo, (dvoid **) &ptrcoll, &size, + (dvoid **)0, (ub4 *)0)) { + checkerr(errhp, status); + } + + i = custno; + OCIBindByName(stmthp, &bndp1, errhp, + (text *)":num", (sb4)strlen(":num"), (dvoid*)&i, sizeof(i), + SQLT_INT, (dvoid*)0, (ub2*)0, (ub2*)0, (ub4)0, (ub4*)0, + OCI_DEFAULT); + + if (status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 0, (ub4) 0, (OCISnapshot *)NULL, + (OCISnapshot *)NULL, OCI_DEFAULT)) { + checkerr(errhp, status); + } + + if (status = OCIStmtFetch2(stmthp, errhp, (ub4)1, OCI_FETCH_NEXT, (sb4) 0, OCI_DEFAULT)) { + checkerr(errhp, status); + } + + /* print out the results */ + if (flag == 1) { + /* print out the nested table */ + printf ("\n ######## printing out the nested table ############ \n"); + for (i=0; i < 5; i++) + { + OCICollGetElem(envhp, errhp, (CONST OCIColl *) ptrcoll, (sb4) i, &exists, + (dvoid **)&elem, (dvoid **)0); + if (!exists) + { + printf("Error: end of collection\n"); + break; + } + else { + OCINumberToInt(errhp, elem, sizeof(nt_value), 0, &nt_value); + printf ("%d\n", nt_value); + } + } + } + else { + /* print out VARRAY */ + printf ("\n ######## printing out the VARRAY ############ \n"); + for (i =0; i < 5; i++) + { + checkerr(errhp, OCICollGetElem(envhp, + errhp, (CONST OCIColl *) ptrcoll, (sb4) i, &exists, + (dvoid **)&elem, (dvoid **)0)); + if (!exists) + { + printf("Error: end of collection\n"); + break; + } + else { + va_value = *(OCIString **)elem; + printf("%s\n", (text *)OCIStringPtr(envhp, (CONST OCIString *)va_value)); + } + } + } + + /* free the collection */ + OCIObjectFree(envhp, errhp, ptrcoll, OCI_OBJECTFREE_FORCE); + + printf("\n=> Selection done\n"); + + return OCI_SUCCESS; +} + + +/* end of file cdemocoll.c */ diff --git a/cdemocoll.h b/cdemocoll.h new file mode 100644 index 0000000..d12c615 --- /dev/null +++ b/cdemocoll.h @@ -0,0 +1,37 @@ +/* Copyright (c) 2004, Oracle. All rights reserved. */ + +/* + NAME + cdemocoll.h - collection demo program in OCI + + DESCRIPTION + demo of insertion(bind) and selection(define) of collection + columns (nested table and varray) as named datatype SQLT_NTY + using OCI interface. + + RELATED DOCUMENTS + + + EXPORT FUNCTION(S) + + + INTERNAL FUNCTION(S) + + + EXAMPLES + + NOTES + + + MODIFIED (MM/DD/YY) + aliu 05/06/04 - aliu_add_coll_demo + aliu 05/04/04 - Creation + +*/ + +#ifndef CDEMOCOLL_ORACLE +# define CDEMOCOLL_ORACLE + +int main(/*_ void _*/); + +#endif /* CDEMOCOLL_ORACLE */ diff --git a/cdemocor.c b/cdemocor.c new file mode 100644 index 0000000..48a187a --- /dev/null +++ b/cdemocor.c @@ -0,0 +1,1098 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemocor.c 18-feb-2005.15:07:29 aliu Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1995, 2005, Oracle. All rights reserved. +*/ + +/* + NAME + cdemocor.c + DESCRIPTION + Demo COR user interface. Run cdemocor.sql bfirst. + + NOTES + see routines. + + MODIFIED (MM/DD/YY) + aliu 02/17/05 - lint issues + aliu 02/16/05 - fix bug 4184560 + emendez 09/13/00 - fix top 5 olint errors + mpjoshi 07/29/99 - updating file from 806 (Add OCICacheUnpin: HSBEDI) + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 09/09/98 - lines longer than 79 chars reformatted - bug 722491 + svedala 07/02/98 - no handlealloc required for define handles + tanguyen 08/19/97 - + echen 06/04/97 - fix warning mesg + echen 05/31/97 - Creation +*/ + +#ifndef CDEMOCOR_ORACLE +#include "cdemocor.h" +#endif + +/* + * COR is a prefetching mechanism which does not add any more + * functionality but improves performance. This demo shows how + * you can use COR to improve the performance of your application + * by cutting down on the number of network roundtrips. Since it + * may not be easy for you to track the actual network roundtrips + * you can turn VERIFY_COR to TRUE which lets you verify that the + * pin calls find the prefetched objects in the object cache and + * thus do not incur a n/w roundtrip. By setting VERIFY_COR to + * TRUE, you modify the data corresponding to the prefetched + * objects (in the object cache) in the server. When you access + * these prefetched objects on the client side, you get the ones + * locally cached in the object cache (and not the new modified + * ones in the server). + */ +#define VERIFY_COR FALSE + +static const text *const selref = (text *) + "SELECT REF(po) from po_table po where po.po_number = 1"; +static const text *const selall = (text *) + "SELECT REF(po) from po_table po"; +static const text *sch_name_arr[] = {(const text *)0, (const text *)0}; +static ub4 sch_name_len_arr[] = {(ub4)0, (ub4)0}; +static const text *type_name_arr[] = + {(const text *)"PURCHASE_ORDER", (const text *)"CUSTOMER"}; +static ub4 type_name_len_arr[] = {(ub4)14, (ub4)8}; +static const text *version_arr[] = {(const text *)0, (const text *)0}; +static ub4 version_len_arr[] = {(ub4)0, (ub4)0}; + +/*****************************************************************************/ +void checkerr1(errhp, status, file, line) +OCIError *errhp; +sword status; +const char *file; +int line; +{ + text errbuf[512]; + sb4 errcode; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NO_DATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet ((dvoid *) errhp, (ub4) 1, + (text *) NULL, (sb4 *) &errcode, + errbuf, (ub4) sizeof(errbuf), + (ub4) OCI_HTYPE_ERROR); + (void) printf("Error - %s, file %s, line %d\n", + errbuf, file, line); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} + +static void demo_cor_1(envhp, svchp, stmthp, errhp) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIError *errhp; +{ + OCIRef *poref = (OCIRef *)0; + OCIIter *itr; + boolean eoc; + purchase_order *po = (purchase_order *)0; + purchase_order *related_po = (purchase_order *)0; + customer *cust = (customer *)0; + OCIDefine *defnp; + OCIComplexObject *corhp, *corhp3; + OCIComplexObjectComp *cordp1, *cordp3; + OCIType *custtdo, *custtdo2; + OCIRef *custref = (OCIRef *)0; + OCIComplexObjectComp *cordp2; + OCIType *po_tdo; + ub4 po_size; + OCIRef *po_ref = (OCIRef *)0; + ub4 level = 0; + ub4 mylevel, siz, paramcount = 0; + dvoid *tdo_arr[2]; + dvoid *tmp; + sword status = OCI_SUCCESS; + OCIParam *parmp; + ub1 outofline = FALSE; + int age, po_num; + address *addr = (address *) 0; + sb4 index; + boolean exist; +#ifdef VERIFY_COR + text *stmt11 = (text *) + "update cust_table set name = 'Anil' where name = 'JOHN'"; + text *stmt12 = (text *) + "update cust_table set name = 'Chin' where name = 'MIKE'"; + text *stmt13 = (text *) + "insert into the (select addr from cust_table where name='Anil') \ + select 'ca', '90417', ref(x) from person_table x where name='JOHN2'"; + text *stmt14 = (text *) + "insert into the (select addr from cust_table where name='Chin') \ + select 'ca', '90417', ref(x) from person_table x where name='JOHN2'"; +#endif + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) selref, + (ub4) strlen((char *) selref), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIDefineByPos(stmthp, &defnp, errhp, (ub4) 1, + (dvoid *) 0, (sb4) 0, SQLT_REF, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) OCI_DEFAULT)); + + /* get type of purchase_order to set in COR descriptor */ + checkerr(errhp, OCITypeArrayByName(envhp, errhp, svchp, 2, + (CONST oratext **) sch_name_arr, + sch_name_len_arr, (CONST oratext **) type_name_arr, + type_name_len_arr, (CONST oratext **) version_arr, + version_len_arr, OCI_DURATION_SESSION, + OCI_TYPEGET_ALL, (OCIType **) tdo_arr)); + po_tdo = (OCIType *)tdo_arr[0]; + custtdo = (OCIType *)tdo_arr[1]; + + checkerr(errhp, OCIDefineObject(defnp, errhp, po_tdo, (dvoid **) &poref, + &po_size, (dvoid **) 0, (ub4 *) 0)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 0, + (ub4) 0, (OCISnapshot *)NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtFetch(stmthp, errhp, (ub4) 1, (ub4) OCI_FETCH_NEXT, + (ub4) OCI_DEFAULT)); + + /*---------------------------- C O R --------------------------------*/ + /* get COR Handle */ + checkerr(errhp, OCIHandleAlloc((dvoid *)envhp, (dvoid **)&corhp, + (ub4)OCI_HTYPE_COMPLEXOBJECT, 0, + (dvoid **)0)); + + /*---------------------------- put customer -------------------------*/ + /* get COR descriptor for type customer */ + checkerr(errhp, OCIDescriptorAlloc((dvoid *)envhp, (dvoid **)&cordp1, + (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, 0, + (dvoid **)0)); + + /* set customer type in COR descriptor */ + checkerr(errhp, OCIAttrSet((dvoid *)cordp1, + (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, (dvoid *)custtdo, + (ub4)sizeof(dvoid *), (ub4)OCI_ATTR_COMPLEXOBJECTCOMP_TYPE, + (OCIError *)errhp)); + + level = 2; + /* set depth level for customer in COR descriptor */ + checkerr(errhp, OCIAttrSet((dvoid *)cordp1, + (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, + (dvoid *)&level, (ub4)sizeof(ub4), + (ub4)OCI_ATTR_COMPLEXOBJECTCOMP_TYPE_LEVEL, (OCIError *)errhp)); + + /* set attributes to COR handle */ + if (OCIAttrSet((dvoid *)corhp,(ub4) OCI_HTYPE_COMPLEXOBJECT, + (dvoid *)&outofline, (ub4)sizeof(ub1), + (ub4)OCI_ATTR_COMPLEXOBJECT_COLL_OUTOFLINE, + (OCIError *)errhp)) + (void) printf("BUG: set COR attribute out of line\n"); + + if (OCIAttrSet((dvoid *)corhp,(ub4) OCI_HTYPE_COMPLEXOBJECT, + (dvoid *)&outofline, (ub4)sizeof(ub1), (ub4)OCI_ATTR_SERVER, + (OCIError *)errhp) != OCI_ERROR) + (void) printf("BUG: set COR attribute to server\n"); + + /* get attributes from COR handle */ + if (OCIAttrGet((dvoid *)corhp, (ub4)OCI_HTYPE_COMPLEXOBJECT, + (dvoid *) &mylevel, (ub4 *) &siz, + (ub4)OCI_ATTR_COMPLEXOBJECT_LEVEL, (OCIError *)errhp)) + (void) printf("BUG: get COR attribute\n"); + + if (OCIAttrGet((dvoid *)corhp, (ub4)OCI_HTYPE_COMPLEXOBJECT, + (dvoid *) ¶mcount, (ub4 *) &siz, + (ub4)OCI_ATTR_PARAM_COUNT, (OCIError *)errhp)) + (void) printf("BUG: get COR attribute\n"); + + if (OCIAttrGet((dvoid *)corhp, (ub4)OCI_HTYPE_COMPLEXOBJECT, + (dvoid *) &outofline, (ub4 *) 0, + (ub4)OCI_ATTR_COMPLEXOBJECT_COLL_OUTOFLINE, + (OCIError *)errhp)) + (void) printf("BUG: get COR attribute\n"); + + if (OCIAttrGet((dvoid *)corhp, (ub4)OCI_HTYPE_COMPLEXOBJECT, + (dvoid *) &outofline, (ub4 *) 0, + (ub4)OCI_ATTR_SCALE, (OCIError *)errhp) == OCI_SUCCESS) + (void) printf("BUG: get COR attribute\n"); + + + /* get attributes from COR descriptor */ + if (OCIAttrGet((dvoid *)cordp1, (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, + (dvoid *) &custtdo2, (ub4 *) 0, + (ub4)OCI_ATTR_COMPLEXOBJECTCOMP_TYPE, (OCIError *)errhp)) + (void) printf("BUG: get COR attribute\n"); + + if (OCIAttrGet((dvoid *)cordp1, (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, + (dvoid *) &custtdo2, (ub4 *) 0, + (ub4)OCI_ATTR_SCALE, (OCIError *)errhp) == OCI_SUCCESS) + (void) printf("BUG: get COR attribute\n"); + + if (OCIAttrGet((dvoid *)cordp1, (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, + (dvoid *) &mylevel, (ub4 *) 0, + (ub4)OCI_ATTR_COMPLEXOBJECTCOMP_TYPE_LEVEL, + (OCIError *)errhp)) + (void) printf("BUG: get COR attribute\n"); + + if (mylevel != level) + (void) printf("BUG: mylevel = %d, level = %d\n", mylevel, level); + + + /* put COR descriptor in COR handle */ + checkerr(errhp, OCIParamSet(corhp, OCI_HTYPE_COMPLEXOBJECT, errhp, + cordp1, OCI_DTYPE_COMPLEXOBJECTCOMP, 1)); + + if (OCIParamGet(corhp, OCI_HTYPE_COMPLEXOBJECT, errhp, (dvoid *) &corhp3, 1) + != OCI_SUCCESS) + (void) printf("BUG: get parm on corhp\n"); + + if (OCIParamGet(stmthp, OCI_HTYPE_STMT, errhp, (dvoid *) &parmp, 1) + != OCI_SUCCESS) + (void) printf("BUG: get parm on stmthp with position 1\n"); + + + /*------------------------- put purchase_order ------------------------*/ + /* get COR descriptor for type purchase_order */ + checkerr(errhp, OCIDescriptorAlloc((dvoid *)envhp, + (dvoid **)&cordp2, (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, 0, + (dvoid **)0)); + + /* set customer type in COR descriptor */ + checkerr(errhp, OCIAttrSet((dvoid *)cordp2, + (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, (dvoid *)po_tdo, + (ub4)sizeof(dvoid *), (ub4)OCI_ATTR_COMPLEXOBJECTCOMP_TYPE, + (OCIError *)errhp)); + + level = 2; + + /* set depth level for customer in COR descriptor */ + checkerr(errhp, OCIAttrSet((dvoid *)cordp2, + (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, (dvoid *)&level, + (ub4)sizeof(ub4), (ub4)OCI_ATTR_COMPLEXOBJECTCOMP_TYPE_LEVEL, + (OCIError *)errhp)); + + /* put COR descriptor in COR handle */ + checkerr(errhp, OCIParamSet(corhp, OCI_HTYPE_COMPLEXOBJECT, + errhp, cordp2, OCI_DTYPE_COMPLEXOBJECTCOMP, 2)); + + + if (OCIParamGet(corhp, OCI_HTYPE_COMPLEXOBJECT, errhp, (dvoid *) &cordp3, 1)) + (void) printf("BUG: get parm on cordp\n"); + + + /* pin the purchase order */ + checkerr(errhp, OCIObjectPin(envhp, errhp, poref, corhp, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, (dvoid **)&po)); + + checkerr(errhp, OCINumberToInt(errhp, &po->po_number, + sizeof(po_num), OCI_NUMBER_SIGNED, + (dvoid *) &po_num)); + (void) printf(" The po number is %d\n", po_num); + +#ifdef VERIFY_COR + /* Modify the data */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt11, + (ub4) strlen((char *) stmt11), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt12, + (ub4) strlen((char *) stmt12), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt13, + (ub4) strlen((char *) stmt13), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt14, + (ub4) strlen((char *) stmt14), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); +#endif + + /* pin the customer (shouldn't go over the n/w) */ + /* you should see MIKE and JOHN and should not see newly inserted records */ + checkerr(errhp, OCIObjectPin(envhp, errhp, po->cust, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&cust)); + + (void) printf("The name is %s\n", OCIStringPtr(envhp, cust->name)); + checkerr(errhp, OCINumberToInt(errhp, &cust->age, sizeof(age), + OCI_NUMBER_SIGNED, (dvoid *) &age)); + (void) printf(" The age is %d\n", age); + + (void) printf("\n---> Dump the table from the top to the bottom.\n"); + /* go to the first element and print out the index */ + checkerr(errhp, OCITableFirst(envhp, errhp, cust->addr, &index)); + (void) printf(" The index of the first element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &addr, (dvoid **) 0)); + + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + + for(;!OCITableNext(envhp, errhp, index, cust->addr, + &index, &exist) && exist;) + { + (void) printf(" The index of the next element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &addr, (dvoid **) 0)); + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + } + + /* pin the purchase_order (shouldn't go over the n/w) */ + checkerr(errhp, OCIObjectPin(envhp, errhp, po->related_orders, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, + OCI_LOCK_NONE, (dvoid **)&related_po)); + + /* pin the customer (shouldn't go over the n/w) */ + checkerr(errhp, OCIObjectPin(envhp, errhp, related_po->cust, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&cust)); + + (void) printf("The name is %s\n", OCIStringPtr(envhp, cust->name)); + checkerr(errhp, OCINumberToInt(errhp, &cust->age, sizeof(age), + OCI_NUMBER_SIGNED, (dvoid *) &age)); + (void) printf(" The age is %d\n", age); + + (void) printf("\n---> Dump the table from the top to the bottom.\n"); + /* go to the first element and print out the index */ + checkerr(errhp, OCITableFirst(envhp, errhp, cust->addr, &index)); + (void) printf(" The index of the first element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &addr, (dvoid **) 0)); + + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + + for(;!OCITableNext(envhp, errhp, index, cust->addr, + &index, &exist) && exist;) + { + (void) printf(" The index of the next element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &addr, (dvoid **) 0)); + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + } + + checkerr(errhp, OCICacheUnpin(envhp, errhp, svchp)); + checkerr(errhp, OCICacheFree(envhp, errhp, svchp)); + + /* free COR descriptor and COR handle */ + checkerr(errhp, OCIDescriptorFree((dvoid *)cordp1, + (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP)); + checkerr(errhp, OCIDescriptorFree((dvoid *)cordp2, + (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP)); + checkerr(errhp, OCIHandleFree((dvoid *)corhp, + (ub4)OCI_HTYPE_COMPLEXOBJECT)); +} + + +static void demo_cor_2(envhp, svchp, stmthp, errhp) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIError *errhp; +{ + OCIType *po_tdo; + ub4 po_size; + OCIRef *poref = (OCIRef *)0; + purchase_order *po = (purchase_order *)0; + purchase_order *related_po = (purchase_order *)0; + customer *cust = (customer *)0; + OCIDefine *defnp; + OCIComplexObject *corhp; + ub4 level = 0; + dvoid *tmp; + sword status = OCI_SUCCESS; + int age, po_num; + address *addr = (address *) 0; + sb4 index; + boolean exist; +#ifdef VERIFY_COR + text *stmt11 = (text *) + "update cust_table set name = 'JOHN' where name = 'Anil'"; + text *stmt12 = (text *) + "update cust_table set name = 'MIKE' where name = 'Chin'"; + text *stmt13 = (text *) + "insert into the (select addr from cust_table where name='JOHN') \ + select 'ca', '90418', ref(x) from person_table x where name='JOHN3'"; + text *stmt14 = (text *) + "insert into the (select addr from cust_table where name='MIKE') \ + select 'ca', '90418', ref(x) from person_table x where name='JOHN3'"; +#endif + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) + selref, (ub4) strlen((char *) selref), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIDefineByPos(stmthp, &defnp, errhp, (ub4) 1, + (dvoid *) 0, (sb4) 0, SQLT_REF, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) OCI_DEFAULT)); + + /* get type of purchase_order to set in COR descriptor */ + OCITypeByName(envhp, errhp, svchp, (text *)0, (ub4)0, + (text *)"PURCHASE_ORDER", + (ub4)strlen((char *)"PURCHASE_ORDER"), + (text *) 0, (ub4) 0, OCI_DURATION_SESSION, + OCI_TYPEGET_HEADER, &po_tdo); + + checkerr(errhp, OCIDefineObject(defnp, errhp, po_tdo, + (dvoid **) &poref, &po_size, (dvoid **) 0, + (ub4 *) 0)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 0, + (ub4) 0, (OCISnapshot *)NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtFetch(stmthp, errhp, (ub4) 1, (ub4) OCI_FETCH_NEXT, + (ub4) OCI_DEFAULT)); + + /*---------------------------- C O R --------------------------------*/ + /* get COR Handle */ + checkerr(errhp, OCIHandleAlloc((dvoid *)envhp, (dvoid **)&corhp, + (ub4)OCI_HTYPE_COMPLEXOBJECT, 0, + (dvoid **)0)); + + level = 5; + /* put level in COR handle */ + checkerr(errhp, OCIAttrSet((dvoid *)corhp, (ub4)OCI_HTYPE_COMPLEXOBJECT, + (dvoid *)&level, (ub4)sizeof(ub4), + (ub4)OCI_ATTR_COMPLEXOBJECT_LEVEL, (OCIError *)errhp)); + + /* pin the purchase order */ + checkerr(errhp, OCIObjectPin(envhp, errhp, poref, corhp, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, (dvoid **)&po)); + +#ifdef VERIFY_COR + /* Modify the data */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt11, + (ub4) strlen((char *) stmt11), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt12, + (ub4) strlen((char *) stmt12), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt13, + (ub4) strlen((char *) stmt13), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt14, + (ub4) strlen((char *) stmt14), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); +#endif + + /* pin the customer (shouldn't go over the n/w) */ + /* you should see Anil and Chin */ + checkerr(errhp, OCIObjectPin(envhp, errhp, po->cust, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&cust)); + + (void) printf("The name is %s\n", OCIStringPtr(envhp, cust->name)); + checkerr(errhp, OCINumberToInt(errhp, &cust->age, sizeof(age), + OCI_NUMBER_SIGNED, (dvoid *) &age)); + (void) printf(" The age is %d\n", age); + + (void) printf("\n---> Dump the table from the top to the bottom.\n"); + /* go to the first element and print out the index */ + checkerr(errhp, OCITableFirst(envhp, errhp, cust->addr, &index)); + (void) printf(" The index of the first element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &addr, (dvoid **) 0)); + + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + + for(;!OCITableNext(envhp, errhp, index, cust->addr, + &index, &exist) && exist;) + { + (void) printf(" The index of the next element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &addr, (dvoid **) 0)); + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + } + + /* pin the purchase_order (shouldn't go over the n/w) */ + checkerr(errhp, OCIObjectPin(envhp, errhp, po->related_orders, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, + OCI_LOCK_NONE, (dvoid **)&related_po)); + + /* pin the customer (shouldn't go over the n/w) */ + checkerr(errhp, OCIObjectPin(envhp, errhp, related_po->cust, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&cust)); + + (void) printf("The name is %s\n", OCIStringPtr(envhp, cust->name)); + checkerr(errhp, OCINumberToInt(errhp, &cust->age, sizeof(age), + OCI_NUMBER_SIGNED, (dvoid *) &age)); + (void) printf(" The age is %d\n", age); + + (void) printf("\n---> Dump the table from the top to the bottom.\n"); + /* go to the first element and print out the index */ + checkerr(errhp, OCITableFirst(envhp, errhp, cust->addr, &index)); + (void) printf(" The index of the first element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &addr, (dvoid **) 0)); + + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + + for(;!OCITableNext(envhp, errhp, index, cust->addr, + &index, &exist) && exist;) + { + (void) printf(" The index of the next element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &addr, (dvoid **) 0)); + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + } + + checkerr(errhp, OCICacheUnpin(envhp, errhp, svchp)); + checkerr(errhp, OCICacheFree(envhp, errhp, svchp)); + + /* free COR handle */ + checkerr(errhp, OCIHandleFree((dvoid *)corhp, (ub4)OCI_HTYPE_COMPLEXOBJECT)); +} + +static void demo_cor_3(envhp, svchp, stmthp, errhp) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIError *errhp; +{ + OCIType *po_tdo; + ub4 po_size; + OCIRef *poref = (OCIRef *)0; + purchase_order *po = (purchase_order *)0; + purchase_order *related_po = (purchase_order *)0; + customer *cust = (customer *)0; + OCIDefine *defnp; + OCIComplexObject *corhp; + ub1 outofline; + dvoid *tmp; + sword status = OCI_SUCCESS; + dvoid *elem = (dvoid *)0; + dvoid *elemind = (dvoid *)0; + sb4 collsiz; + boolean exist; + address *addr = (address *) 0; + null_address *null_addr = (null_address *) 0; + sb4 index = 0, counter = 0; +#ifdef VERIFY_COR + text *stmt11 = (text *) + "update cust_table set name = 'Anil' where name = 'JOHN'"; + text *stmt12 = (text *) + "update cust_table set name = 'Chin' where name = 'MIKE'"; + text *stmt13 = (text *) + "insert into the (select addr from cust_table where name='Anil') \ + select NULL, '90419', ref(x) from person_table x where name='MIKE1'"; + text *stmt14 = (text *) + "insert into the (select addr from cust_table where name='Chin') \ + select NULL, '90419', ref(x) from person_table x where name='MIKE1'"; +#endif + + /*-------------------------- get po ref -----------------------------*/ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) selref, + (ub4) strlen((char *) selref), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIDefineByPos(stmthp, &defnp, errhp, (ub4) 1, (dvoid *) 0, + (sb4) 0, SQLT_REF, (dvoid *) 0, (ub2 *)0, + (ub2 *)0, (ub4) OCI_DEFAULT)); + + /* get type of purchase_order to set in COR descriptor */ + OCITypeByName(envhp, errhp, svchp, (text *)0, (ub4)0, + (text *)"PURCHASE_ORDER", + (ub4)strlen((char *)"PURCHASE_ORDER"), + (text *) 0, (ub4) 0, OCI_DURATION_SESSION, + OCI_TYPEGET_HEADER, &po_tdo); + + checkerr(errhp, OCIDefineObject(defnp, errhp, po_tdo, + (dvoid **) &poref, &po_size, (dvoid **) 0, + (ub4 *) 0)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 0, + (ub4) 0, (OCISnapshot *)NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtFetch(stmthp, errhp, (ub4) 1, (ub4) OCI_FETCH_NEXT, + (ub4) OCI_DEFAULT)); + + /*---------------------------- C O R --------------------------------*/ + /* get COR Handle */ + checkerr(errhp, OCIHandleAlloc((dvoid *)envhp, (dvoid **)&corhp, + (ub4)OCI_HTYPE_COMPLEXOBJECT, 0, + (dvoid **)0)); + + /* pin the purchase order */ + checkerr(errhp, OCIObjectPin(envhp, errhp, poref, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, (dvoid **)&po)); + + outofline = TRUE; + /* put level in COR handle */ + checkerr(errhp, OCIAttrSet((dvoid *)corhp, (ub4)OCI_HTYPE_COMPLEXOBJECT, + (dvoid *)&outofline, (ub4)sizeof(ub1), + (ub4)OCI_ATTR_COMPLEXOBJECT_COLL_OUTOFLINE, + (OCIError *)errhp)); + + /* pin the customer (shouldn't go over the n/w) */ + checkerr(errhp, OCIObjectPin(envhp, errhp, po->cust, corhp, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&cust)); + +#ifdef VERIFY_COR + /* Modify the data */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt11, + (ub4) strlen((char *) stmt11), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt12, + (ub4) strlen((char *) stmt12), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + /* add new records */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt13, + (ub4) strlen((char *) stmt13), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt14, + (ub4) strlen((char *) stmt14), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); +#endif + + /* should see the new records */ + (void) printf("\n---> Dump the table from the top to the bottom.\n"); + /* go to the first element and print out the index */ + checkerr(errhp, OCITableFirst(envhp, errhp, cust->addr, &index)); + (void) printf(" The index of the first element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &elem, &elemind)); + addr = (address *)elem; + null_addr = (null_address *)elemind; + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + (void) printf(" atomic null indicator is %d\n", null_addr->null_address); + (void) printf(" zip null indicator is %d\n", null_addr->null_zip); + (void) printf(" state null indicator is %d\n", null_addr->null_state); + + + for(;!OCITableNext(envhp, errhp, index, cust->addr, + &index, &exist) && exist;) + { + (void) printf(" The index of the next element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &elem, &elemind)); + addr = (address *)elem; + null_addr = (null_address *)elemind; + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + (void) printf(" atomic null indicator is %d\n", + null_addr->null_address); + (void) printf(" zip null indicator is %d\n", null_addr->null_zip); + (void) printf(" state null indicator is %d\n", null_addr->null_state); + } + + + /* pin the purchase_order (shouldn't go over the n/w) */ + checkerr(errhp, OCIObjectPin(envhp, errhp, po->related_orders, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, + OCI_LOCK_NONE, (dvoid **)&related_po)); + + checkerr(errhp, OCICacheUnpin(envhp, errhp, svchp)); + checkerr(errhp, OCICacheFree(envhp, errhp, svchp)); + + /* free COR handle */ + checkerr(errhp, OCIHandleFree((dvoid *)corhp, (ub4)OCI_HTYPE_COMPLEXOBJECT)); +} + +static void demo_cor_4(envhp, svchp, stmthp, errhp) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIError *errhp; +{ + OCIType *po_tdo; + ub4 po_size[3], i; + OCIRef *poref[3]; + purchase_order *po[3]; + purchase_order *related_po = (purchase_order *)0; + customer *cust = (customer *)0; + OCIDefine *defnp; + OCIComplexObject *corhp[3]; + ub4 level = 0; + dvoid *tmp; + sword status = OCI_SUCCESS; + int age, po_num; + address *addr = (address *) 0; + sb4 index; + boolean exist; +#ifdef VERIFY_COR + text *stmt11 = (text *) + "update cust_table set name = 'JOHN' where name = 'Anil'"; + text *stmt12 = (text *) + "update cust_table set name = 'MIKE' where name = 'Chin'"; + text *stmt13 = (text *) + "insert into the (select addr from cust_table where name='JOHN') \ + select 'ca', '90418', ref(x) from person_table x where name='JOHN3'"; + text *stmt14 = (text *) + "insert into the (select addr from cust_table where name='MIKE') \ + select 'ca', '90418', ref(x) from person_table x where name='JOHN3'"; +#endif + + for (i=0; i<3; i++) + poref[i] = (OCIRef *) 0; + + for (i=0; i<3; i++) + po[i] = (purchase_order *) 0; + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) selall, + (ub4) strlen((char *) selall), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIDefineByPos(stmthp, &defnp, errhp, (ub4) 1, + (dvoid *) 0, (sb4) 0, SQLT_REF, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, (ub4) OCI_DEFAULT)); + + /* get type of purchase_order to set in COR descriptor */ + OCITypeByName(envhp, errhp, svchp, (text *)0, (ub4)0, + (text *)"PURCHASE_ORDER", + (ub4)strlen((char *)"PURCHASE_ORDER"), + (text *) 0, (ub4) 0, OCI_DURATION_SESSION, + OCI_TYPEGET_HEADER, &po_tdo); + + checkerr(errhp, OCIDefineObject(defnp, errhp, po_tdo, + (dvoid **) poref, po_size, (dvoid **) 0, + (ub4 *) 0)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, + (ub4) 0, (ub4) 0, (OCISnapshot *)NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtFetch(stmthp, errhp, (ub4) 3, (ub4) OCI_FETCH_NEXT, + (ub4) OCI_DEFAULT)); + + /*---------------------------- C O R --------------------------------*/ + /* get COR Handle */ + for (i=0; i<3; i++) + OCIHandleAlloc((dvoid *)envhp, (dvoid **)&corhp[i], + (ub4)OCI_HTYPE_COMPLEXOBJECT, 0, + (dvoid **)0); + + level = 1; + /* put level in COR handle */ + for (i=0; i<3; i++) + OCIAttrSet((dvoid *)corhp[i], (ub4)OCI_HTYPE_COMPLEXOBJECT, + (dvoid *)&level, (ub4)sizeof(ub4), + (ub4)OCI_ATTR_COMPLEXOBJECT_LEVEL, (OCIError *)errhp); + + checkerr(errhp, OCIObjectArrayPin(envhp, errhp, poref, (ub4) 3, + corhp, (ub4) 3, + OCI_PIN_LATEST, OCI_DURATION_SESSION, + OCI_LOCK_NONE, (dvoid **) po, 0)); + +#ifdef VERIFY_COR + /* modify the records */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt11, + (ub4) strlen((char *) stmt11), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt12, + (ub4) strlen((char *) stmt12), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + /* add new records */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt13, + (ub4) strlen((char *) stmt13), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt14, + (ub4) strlen((char *) stmt14), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); +#endif + + /* pin the purchase order */ + for (i=0; i<3; i++) + { + /* pin the customer (shouldn't go over the n/w) */ + /* you should see Anil and Chin */ + checkerr(errhp, OCIObjectPin(envhp, errhp, po[i]->cust, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&cust)); + + (void) printf("The name is %s\n", OCIStringPtr(envhp, cust->name)); + checkerr(errhp, OCINumberToInt(errhp, &cust->age, sizeof(age), + OCI_NUMBER_SIGNED, (dvoid *) &age)); + (void) printf(" The age is %d\n", age); + + (void) printf("\n---> Dump the table from the top to the bottom.\n"); + /* go to the first element and print out the index */ + checkerr(errhp, OCITableFirst(envhp, errhp, cust->addr, &index)); + (void) printf(" The index of the first element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &addr, (dvoid **) 0)); + + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + + for(;!OCITableNext(envhp, errhp, index, cust->addr, + &index, &exist) && exist;) + { + (void) printf(" The index of the next element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, + index, &exist, (void **) &addr, (dvoid **) 0)); + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + } + + /* pin the purchase_order (shouldn't go over the n/w) */ + checkerr(errhp, OCIObjectPin(envhp, errhp, po[i]->related_orders, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, + OCI_LOCK_NONE, (dvoid **)&related_po)); + + /* pin the customer (shouldn't go over the n/w) */ + checkerr(errhp, OCIObjectPin(envhp, errhp, related_po->cust, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&cust)); + + (void) printf("The name is %s\n", OCIStringPtr(envhp, cust->name)); + checkerr(errhp, OCINumberToInt(errhp, &cust->age, sizeof(age), + OCI_NUMBER_SIGNED, (dvoid *) &age)); + (void) printf(" The age is %d\n", age); + + (void) printf("\n---> Dump the table from the top to the bottom.\n"); + /* go to the first element and print out the index */ + checkerr(errhp, OCITableFirst(envhp, errhp, cust->addr, &index)); + (void) printf(" The index of the first element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &addr, (dvoid **) 0)); + + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + + for(;!OCITableNext(envhp, errhp, index, cust->addr, + &index, &exist) && exist;) + { + (void) printf(" The index of the next element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, + index, &exist, (void **) &addr, (dvoid **) 0)); + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + } + + } + + checkerr(errhp, OCICacheUnpin(envhp, errhp, svchp)); + checkerr(errhp, OCICacheFree(envhp, errhp, svchp)); + + /* free COR handle */ + for (i=0; i<3; i++) + checkerr(errhp, OCIHandleFree((dvoid *)corhp[i], + (ub4)OCI_HTYPE_COMPLEXOBJECT)); +} + + +int main(int argc, char *argv[]) +{ + OCIEnv *envhp; + OCISvcCtx *svchp; + OCIError *errhp; + OCIServer *srvhp; + OCISession *usrhp; + OCIStmt *stmthp; + sword status = OCI_SUCCESS; + dvoid *tmp = (dvoid *) 0; + + (void) OCIInitialize((ub4) OCI_OBJECT | OCI_DEFAULT, + (dvoid *)0, (dvoid * (*)()) 0, + (dvoid * (*)()) 0, (void (*)()) 0 ); + + (void) OCIEnvInit( &envhp, (ub4) OCI_DEFAULT, 21, (dvoid **) &tmp ); + + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, + 52, (dvoid **) &tmp); + + checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, + 52, (dvoid **) &tmp)); + + checkerr(errhp, OCIServerAttach( srvhp, errhp, (text *) "", + (sb4) strlen((char *)""), (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, + 52, (dvoid **) &tmp)); + + /* set attribute server context in the service context */ + checkerr(errhp, OCIAttrSet( (dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, + (ub4) OCI_ATTR_SERVER, (OCIError *) errhp)); + + checkerr(errhp, OCIHandleAlloc((dvoid *)envhp, (dvoid **)&usrhp, + (ub4)OCI_HTYPE_SESSION, 0, (dvoid **)0)); + + checkerr(errhp, OCIAttrSet((dvoid *) usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"cdemocor", (ub4)strlen((char *)"cdemocor"), + (ub4)OCI_ATTR_USERNAME, errhp)); + + checkerr(errhp, OCIAttrSet((dvoid *) usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"cdemocor", (ub4)strlen((char *)"cdemocor"), + (ub4)OCI_ATTR_PASSWORD, errhp)); + + checkerr(errhp, OCISessionBegin (svchp, errhp, usrhp, (ub4) OCI_CRED_RDBMS, + (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIAttrSet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)usrhp, (ub4)0, + (ub4)OCI_ATTR_SESSION, errhp)); + + /*-------------------------- get po ref -----------------------------*/ + checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp, + (ub4) OCI_HTYPE_STMT, 50, + (dvoid **) &tmp)); + + (void) printf("Complex object retrieval demo # 1\n"); + (void) printf(" --> Set level in COR descriptor\n"); + demo_cor_1(envhp, svchp, stmthp, errhp); + (void) printf("Complex object retrieval demo # 2\n"); + (void) printf(" --> Set level in COR handle\n"); + demo_cor_2(envhp, svchp, stmthp, errhp); + (void) printf("Complex object retrieval demo # 3\n"); + (void) printf(" --> Set outofline equal to TRUE\n"); + demo_cor_3(envhp, svchp, stmthp, errhp); + (void) printf("Complex object retrieval demo # 4\n"); + (void) printf(" --> ArrayPin with COR\n"); + demo_cor_4(envhp, svchp, stmthp, errhp); + + OCIDescriptorFree((dvoid *)envhp, (ub4)OCI_HTYPE_ENV); + +} + diff --git a/cdemocor.h b/cdemocor.h new file mode 100644 index 0000000..da6e587 --- /dev/null +++ b/cdemocor.h @@ -0,0 +1,106 @@ +/* + * $Header: cdemocor.h 16-feb-2005.12:23:27 aliu Exp $ + */ + +/* Copyright (c) 1995, 2005, Oracle. All rights reserved. +*/ + +/* + NAME + cdemocor.h + + DESCRIPTION + This file contains the header information for the cdemocor.c + + RELATED DOCUMENTS + None. + + INSPECTION STATUS + Inspection date: + Inspection status: + Estimated increasing cost defects per page: + Rule sets: + + ACCEPTANCE REVIEW STATUS + Review date: + Review status: + Reviewers: + + PUBLIC FUNCTION(S) + None. + + PRIVATE FUNCTION(S) + As defined below. + + EXAMPLES + + NOTES + + MODIFIED (MM/DD/YY) + aliu 02/16/05 - fix bug 4184560 + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + echen 06/05/97 - remove ifdefed code + echen 05/30/97 - Creation +*/ + +#ifndef CDEMOCOR_ORACLE +#define CDEMOCOR_ORACLE + +#ifndef OCI_ORACLE +#include +#endif + +#include + + +#ifdef __FILE__ +#ifdef __LINE__ +#define checkerr(a, b) checkerr1(a, b, __FILE__, __LINE__) +#else +#define checkerr(a, b) checkerr1(a, b, __FILE__, 0) +#endif +#else +#define checkerr(a, b) checkerr1(a, b, "???", 0) +#endif + + +/*--------------------------------------------------------------------------- + PUBLIC TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ +struct purchase_order +{ + OCINumber po_number; + OCIRef *cust; + OCIRef *related_orders; +}; +typedef struct purchase_order purchase_order; + +struct customer +{ + OCIString *name; + OCINumber age; + OCITable *addr; +}; +typedef struct customer customer; + +struct address +{ + OCIString *state; /* text state[3]; */ + OCIString *zip; /* text zip[11]; */ +}; +typedef struct address address; + +struct null_address +{ + sb2 null_address; + sb2 null_state; + sb2 null_zip; +}; +typedef struct null_address null_address; + +#endif /* CDEMOCOR_ORACLE */ diff --git a/cdemocor.sql b/cdemocor.sql new file mode 100644 index 0000000..77ccedd --- /dev/null +++ b/cdemocor.sql @@ -0,0 +1,145 @@ +rem +rem $Header: cdemocor.sql 18-jun-2004.14:32:05 stsun Exp $ +rem +rem Copyright (c) 1997, 2004, Oracle. All rights reserved. +rem +rem Owner : echen +rem +rem NAME +rem cdemocor.sql +rem DESCRIPTION +rem A sql script to setup schema before running the demo cdemocor +rem +rem NOTE +rem MODIFIED (MM/DD/YY) +rem stsun 06/18/04 - system/manager instead of sysdba +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem svedala 09/11/98 - a "/" required after create type - bug 717842 +rem cchau 08/18/97 - enable dictionary protection +rem echen 05/30/97 - Creation +rem + +set echo on; + +connect system/manager; + +drop user cdemocor cascade; + +grant connect, resource to cdemocor identified by cdemocor; + +connect cdemocor/cdemocor + +create type person as object (name char(20), age number); +/ + +create type person_tab as table of REF person; +/ + +create type address_object as object (state char(2), zip char(10), + owner REF person); +/ + +create type addr_tab is table of address_object; +/ + +create type CUSTOMER as object +( + name CHAR(20), + age NUMBER, + addr addr_tab +); +/ + +create type PURCHASE_ORDER as object +( + po_number NUMBER, + cust REF CUSTOMER, + related_orders REF PURCHASE_ORDER, + signatories person_tab +); +/ + +create table person_table of person; +create table po_table of purchase_order +nested table signatories store as purchase_order_nt_person_tab; +create table cust_table of customer +nested table addr store as customer_nt_addr_tab; + +INSERT INTO person_table VALUES ('JOHN1', 42); +INSERT INTO person_table VALUES ('JOHN2', 42); +INSERT INTO person_table VALUES ('JOHN3', 42); + +INSERT INTO person_table VALUES ('MIKE1', 29); +INSERT INTO person_table VALUES ('MIKE2', 29); +INSERT INTO person_table VALUES ('MIKE3', 29); + +INSERT INTO person_table VALUES ('GREG1', 22); +INSERT INTO person_table VALUES ('GREG2', 22); +INSERT INTO person_table VALUES ('GREG3', 22); + +INSERT INTO cust_table VALUES ('JOHN', 42, addr_tab()); +INSERT INTO cust_table VALUES ('MIKE', 29, addr_tab()); + +insert into the (select addr from cust_table where name='JOHN') + select 'ca', '90416', ref(x) from person_table x where name='JOHN1'; +insert into the (select addr from cust_table where name='JOHN') + select 'ca', '90417', ref(x) from person_table x where name='JOHN2'; +insert into the (select addr from cust_table where name='JOHN') values (NULL); +insert into the (select addr from cust_table where name='JOHN') + select 'ca', '90418', ref(x) from person_table x where name='JOHN3'; + +insert into the (select addr from cust_table where name='MIKE') + select NULL, '90419', ref(x) from person_table x where name='MIKE1'; +insert into the (select addr from cust_table where name='MIKE') + select 'ca', '90420', ref(x) from person_table x where name='MIKE2'; +insert into the (select addr from cust_table where name='MIKE') + select 'ca', '90421', ref(x) from person_table x where name='MIKE3'; + +INSERT INTO po_table (po_number, signatories) VALUES (1, person_tab()); +INSERT INTO po_table (po_number, signatories) VALUES (2, person_tab()); +INSERT INTO po_table (po_number, signatories) VALUES (3, person_tab()); + +UPDATE po_table + set cust = (select ref(x) from cust_table x where name = 'JOHN') + where po_number = 1; +UPDATE po_table + set cust = (select ref(x) from cust_table x where name = 'MIKE') + where po_number = 2; +UPDATE po_table + set cust = (select ref(x) from cust_table x where name = 'MIKE') + where po_number = 3; + +UPDATE po_table + set related_orders = (select ref(x) from po_table x where po_number = 2) + where po_number = 1; +UPDATE po_table + set related_orders = (select ref(x) from po_table x where po_number = 3) + where po_number = 2; +UPDATE po_table + set related_orders = (select ref(x) from po_table x where po_number = 1) + where po_number = 3; + +insert into the (select signatories from po_table where po_number = 1) + select ref(x) from person_table x where name='JOHN1'; +insert into the (select signatories from po_table where po_number = 1) + select ref(x) from person_table x where name='MIKE1'; +insert into the (select signatories from po_table where po_number = 1) + select ref(x) from person_table x where name='GREG1'; + +insert into the (select signatories from po_table where po_number = 2) + select ref(x) from person_table x where name='JOHN2'; +insert into the (select signatories from po_table where po_number = 2) + select ref(x) from person_table x where name='MIKE2'; +insert into the (select signatories from po_table where po_number = 2) + select ref(x) from person_table x where name='GREG2'; + +insert into the (select signatories from po_table where po_number = 3) + select ref(x) from person_table x where name='JOHN3'; +insert into the (select signatories from po_table where po_number = 3) + select ref(x) from person_table x where name='MIKE3'; +insert into the (select signatories from po_table where po_number = 3) + select ref(x) from person_table x where name='GREG3'; + +commit; + +set echo off; diff --git a/cdemocor1.c b/cdemocor1.c new file mode 100644 index 0000000..a540485 --- /dev/null +++ b/cdemocor1.c @@ -0,0 +1,645 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemocor1.c 13-sep-2000.21:32:33 emendez Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1995, 2000 Oracle Corporation. All rights reserved. +*/ + +/* + NAME + cdemocor1.c + DESCRIPTION + Demo COR user interface. Run cdemocor.sql bfirst. + + COR is a prefetching mechanism which allows for prefetching + objects related to the root object in one network roundtrip + thereby improving performance. This demo shows how + you can use COR to improve the performance of your application. + Since it may not be easy for you to track the actual network + roundtrips you can turn VERIFY_COR to TRUE which lets you verify that + the pin calls find the prefetched objects in the object cache and + thus do not incur a n/w roundtrip. By setting VERIFY_COR to + TRUE, you modify the data corresponding to the prefetched + objects (in the object cache) in the server. When you access + these prefetched objects on the client side, you get the ones + locally cached in the object cache (and not the new modified + ones in the server). + + MODIFIED (MM/DD/YY) + emendez 09/13/00 - fix top 5 olint errors + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 09/09/98 - lines longer than 79 chars reformatted - bug 722491 + svedala 07/02/98 - no handlealloc required for define handles + tanguyen 08/19/97 - + echen 06/04/97 - fix warning mesg + echen 05/31/97 - Creation +*/ + +#ifndef CDEMOCOR_ORACLE +#include +#endif + +/* In order to verify that COR works set VERIFY_COR to TRUE. The code enclosed + within the ifdef VERIFY_COR macro acts in the following way. Initially, + we perform a complex object retrieval which should have prefetched the + root object and all objects that the root object contains refs to. The + code guarded by the macro is then executed. This updates the objects that + were prefetched in the server. We then try to pin these objects using the + PIN_ANY option. If COR had worked then the objects should already have + been in the cache and therefore, would not be fetched from the server and + thus should not see the changes made by the code enclosed in the VERIFY_COR + macro */ + +#define VERIFY_COR FALSE + +static const text *const selref = (text *) + "SELECT REF(po) from po_table po where po.po_number = 1"; +static const text *const selall = (text *) + "SELECT REF(po) from po_table po"; +static const text *sch_name_arr[] = {(const text *)0, (const text *)0}; +static ub4 sch_name_len_arr[] = {(ub4)0, (ub4)0}; +static const text *type_name_arr[] = + {(const text *)"PURCHASE_ORDER", (const text *)"CUSTOMER"}; +static ub4 type_name_len_arr[] = {(ub4)14, (ub4)8}; +static const text *version_arr[] = {(const text *)0, (const text *)0}; +static ub4 version_len_arr[] = {(ub4)0, (ub4)0}; + +/****************************************************************************/ +/* checkerr1 - checks and displays errors nested in the error handle */ +void checkerr1(errhp, status, file, line) +OCIError *errhp; +sword status; +const char *file; +int line; +{ + text errbuf[512]; + sb4 errcode; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NO_DATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet ((dvoid *) errhp, (ub4) 1, + (text *) NULL, (sb4 *) &errcode, + errbuf, (ub4) sizeof(errbuf), + (ub4) OCI_HTYPE_ERROR); + (void) printf("Error - %s, file %s, line %d\n", + errbuf, file, line); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} + +/* COR demonstration using COR descriptors. COR descriptors contain the + information about what type of refs should be followed to prefetch the + objects pointed to from the root object and the depth level i.e the + objects reachable from the root object by traversing l ( where l <= the + depth level) number of refs */ + +static void demo_cor_1(envhp, svchp, stmthp, errhp) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIError *errhp; +{ + OCIRef *poref = (OCIRef *)0; + OCIIter *itr; + boolean eoc; + purchase_order *po = (purchase_order *)0; + purchase_order *related_po = (purchase_order *)0; + customer *cust = (customer *)0; + OCIDefine *defnp; + OCIComplexObject *corhp, *corhp3; + OCIComplexObjectComp *cordp1, *cordp3; + OCIType *custtdo, *custtdo2; + OCIRef *custref = (OCIRef *)0; + OCIComplexObjectComp *cordp2; + OCIType *po_tdo; + ub4 po_size; + OCIRef *po_ref = (OCIRef *)0; + ub4 level = 0; + ub4 mylevel; + dvoid *tdo_arr[2]; + dvoid *tmp; + sword status = OCI_SUCCESS; + OCIParam *parmp; + int age, po_num; + address *addr = (address *) 0; + sb4 index; + boolean exist; +#ifdef VERIFY_COR + text *stmt11 = (text *) + "update cust_table set name = 'Anil' where name = 'JOHN'"; + text *stmt12 = (text *) + "update cust_table set name = 'Chin' where name = 'MIKE'"; + text *stmt13 = (text *) + "insert into the (select addr from cust_table where name='Anil') \ + select 'ca', '90417', ref(x) from person_table x where name='JOHN2'"; + text *stmt14 = (text *) + "insert into the (select addr from cust_table where name='Chin') \ + select 'ca', '90417', ref(x) from person_table x where name='JOHN2'"; +#endif + + /* select ref to purchase order number 1 */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) selref, + (ub4) strlen((const char *) selref), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + /* get type of purchase_order and customer to set in COR descriptor */ + checkerr(errhp, OCITypeArrayByName(envhp, errhp, svchp, 2, + (text **) sch_name_arr, + sch_name_len_arr, (text **) type_name_arr, + type_name_len_arr, (text **) version_arr, + version_len_arr, OCI_DURATION_SESSION, + OCI_TYPEGET_ALL, (OCIType **) tdo_arr)); + po_tdo = (OCIType *)tdo_arr[0]; + custtdo = (OCIType *)tdo_arr[1]; + + /* define purchase order REF (poref) */ + checkerr(errhp, OCIDefineByPos(stmthp, &defnp, errhp, (ub4) 1, + (dvoid *) 0, (sb4) 0, SQLT_REF, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIDefineObject(defnp, errhp, po_tdo, (dvoid **) &poref, + &po_size, (dvoid **) 0, (ub4 *) 0)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 0, + (ub4) 0, (OCISnapshot *)NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtFetch(stmthp, errhp, (ub4) 1, (ub4) OCI_FETCH_NEXT, + (ub4) OCI_DEFAULT)); + + /*---------------------------- C O R --------------------------------*/ + /* allocate COR Handle */ + checkerr(errhp, OCIHandleAlloc((dvoid *)envhp, (dvoid **)&corhp, + (ub4)OCI_HTYPE_COMPLEXOBJECT, 0, + (dvoid **)0)); + + /*---------------------------- put customer -------------------------*/ + /* allocate COR descriptor for specifying prefetch */ + checkerr(errhp, OCIDescriptorAlloc((dvoid *)envhp, (dvoid **)&cordp1, + (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, 0, + (dvoid **)0)); + + /* specify type of objects to be prefetched; in this case 'customer' */ + checkerr(errhp, OCIAttrSet((dvoid *)cordp1, + (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, (dvoid *)custtdo, + (ub4)sizeof(dvoid *), (ub4)OCI_ATTR_COMPLEXOBJECTCOMP_TYPE, + (OCIError *)errhp)); + + /* specify depth level for 'customer' */ + level = 2; + checkerr(errhp, OCIAttrSet((dvoid *)cordp1, + (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, + (dvoid *)&level, (ub4)sizeof(ub4), + (ub4)OCI_ATTR_COMPLEXOBJECTCOMP_TYPE_LEVEL, (OCIError *)errhp)); + + /* put COR descriptor in COR handle */ + checkerr(errhp, OCIParamSet(corhp, OCI_HTYPE_COMPLEXOBJECT, errhp, + cordp1, OCI_DTYPE_COMPLEXOBJECTCOMP, 1)); + + + /*------------------------- put purchase_order ------------------------*/ + /* allocate COR descriptor for specifying prefetch */ + checkerr(errhp, OCIDescriptorAlloc((dvoid *)envhp, + (dvoid **)&cordp2, (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, 0, + (dvoid **)0)); + + /* specify type of objects to be prefetched; in this case 'purchase order' */ + checkerr(errhp, OCIAttrSet((dvoid *)cordp2, + (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, (dvoid *)po_tdo, + (ub4)sizeof(dvoid *), (ub4)OCI_ATTR_COMPLEXOBJECTCOMP_TYPE, + (OCIError *)errhp)); + + /* set depth level for purchase order in COR descriptor */ + level = 2; + checkerr(errhp, OCIAttrSet((dvoid *)cordp2, + (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP, (dvoid *)&level, + (ub4)sizeof(ub4), (ub4)OCI_ATTR_COMPLEXOBJECTCOMP_TYPE_LEVEL, + (OCIError *)errhp)); + + /* put COR descriptor in COR handle */ + checkerr(errhp, OCIParamSet(corhp, OCI_HTYPE_COMPLEXOBJECT, + errhp, cordp2, OCI_DTYPE_COMPLEXOBJECTCOMP, 2)); + + + /* pin the purchase order - complex object retrieval should take place since + we are passing in the instruction using the cor handle pointer ( corhp) */ + checkerr(errhp, OCIObjectPin(envhp, errhp, poref, corhp, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, (dvoid **)&po)); + + /* convert the purchase order number from OCINumber to int for printing */ + checkerr(errhp, OCINumberToInt(errhp, &po->po_number, sizeof(po_num), + OCI_NUMBER_SIGNED, (dvoid *) &po_num)); + (void) printf(" The po number is %d\n", po_num); + +#ifdef VERIFY_COR + /* Modify the data in the server */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt11, + (ub4) strlen((const char *) stmt11), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt12, + (ub4) strlen((const char *) stmt12), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt13, + (ub4) strlen((const char *) stmt13), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt14, + (ub4) strlen((const char *) stmt14), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); +#endif + + /* pin the customer (shouldn't go over the n/w since we did cor) */ + /* you should see MIKE and JOHN and should not see newly inserted records + if VERIFY_COR was set to true */ + checkerr(errhp, OCIObjectPin(envhp, errhp, po->cust, (OCIComplexObject *)0, + OCI_PIN_ANY, OCI_DURATION_SESSION, + OCI_LOCK_NONE, (dvoid **)&cust)); + + (void) printf("The name is %s\n", OCIStringPtr(envhp, cust->name)); + checkerr(errhp, OCINumberToInt(errhp, &cust->age, sizeof(age), + OCI_NUMBER_SIGNED, (dvoid *) &age)); + (void) printf(" The age is %d\n", age); + + (void) printf("\n---> Dump the table from the top to the bottom.\n"); + /* go to the first element and print out the index */ + checkerr(errhp, OCITableFirst(envhp, errhp, cust->addr, &index)); + (void) printf(" The index of the first element is : %d.\n", index); + + /* get the first element of the collection and print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &addr, (dvoid **) 0)); + + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + + /* keep getting the indices of the elements and the elements themselves */ + for(;!OCITableNext(envhp, errhp, index, cust->addr, + &index, &exist) && exist;) + { + (void) printf(" The index of the next element is : %d.\n", index); + /* get the next element and print it out */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &addr, (dvoid **) 0)); + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + } + + /* now repeat the process of getting the related purchase orders and printing + them out */ + /* pin the related purchase_order (shouldn't go over the n/w) */ + checkerr(errhp, OCIObjectPin(envhp, errhp, po->related_orders, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, + OCI_LOCK_NONE, (dvoid **)&related_po)); + + /* pin the customer (shouldn't go over the n/w) */ + checkerr(errhp, OCIObjectPin(envhp, errhp, related_po->cust, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&cust)); + + (void) printf("The name is %s\n", OCIStringPtr(envhp, cust->name)); + checkerr(errhp, OCINumberToInt(errhp, &cust->age, sizeof(age), + OCI_NUMBER_SIGNED, (dvoid *) &age)); + (void) printf(" The age is %d\n", age); + + (void) printf("\n---> Dump the table from the top to the bottom.\n"); + /* go to the first element and print out the index */ + checkerr(errhp, OCITableFirst(envhp, errhp, cust->addr, &index)); + (void) printf(" The index of the first element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &addr, (dvoid **) 0)); + + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + + for(;!OCITableNext(envhp, errhp, index, cust->addr, + &index, &exist) && exist;) + { + (void) printf(" The index of the next element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &addr, (dvoid **) 0)); + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + } + + /* We do not need anything in the cache anymore, so free the cache. This + will unpin and free all objects */ + checkerr(errhp, OCICacheFree(envhp, errhp, svchp)); + + /* free COR descriptor and COR handle */ + checkerr(errhp, OCIDescriptorFree((dvoid *)cordp1, + (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP)); + checkerr(errhp, OCIDescriptorFree((dvoid *)cordp2, + (ub4)OCI_DTYPE_COMPLEXOBJECTCOMP)); + checkerr(errhp, OCIHandleFree((dvoid *)corhp, + (ub4)OCI_HTYPE_COMPLEXOBJECT)); +} + +/* COR demonstration that sets the collection out of line parameter in the + COR descriptor to indicate that the collection need not be brought in its + entirety but only a locator is brought in. The collection can be brought + in on demand later on using the locator. */ + +static void demo_cor_3(envhp, svchp, stmthp, errhp) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIError *errhp; +{ + OCIType *po_tdo; + ub4 po_size; + OCIRef *poref = (OCIRef *)0; + purchase_order *po = (purchase_order *)0; + purchase_order *related_po = (purchase_order *)0; + customer *cust = (customer *)0; + OCIDefine *defnp; + OCIComplexObject *corhp; + ub1 outofline = TRUE; + dvoid *tmp; + sword status = OCI_SUCCESS; + dvoid *elem = (dvoid *)0; + dvoid *elemind = (dvoid *)0; + sb4 collsiz; + boolean exist; + address *addr = (address *) 0; + null_address *null_addr = (null_address *) 0; + sb4 index = 0, counter = 0; + OCIDescribe *dschp = (OCIDescribe *) 0; + OCIParam *parmp; + OCIRef *type_ref = (OCIRef *) 0; + +#ifdef VERIFY_COR + text *stmt11 = (text *) + "update cust_table set name = 'Anil' where name = 'JOHN'"; + text *stmt12 = (text *) + "update cust_table set name = 'Chin' where name = 'MIKE'"; + text *stmt13 = (text *) + "insert into the (select addr from cust_table where name='Anil') \ + select NULL, '90419', ref(x) from person_table x where name='MIKE1'"; + text *stmt14 = (text *) + "insert into the (select addr from cust_table where name='Chin') \ + select NULL, '90419', ref(x) from person_table x where name='MIKE1'"; +#endif + + /*-------------------------- get po ref -----------------------------*/ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) selref, + (ub4) strlen((const char *) selref), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIDefineByPos(stmthp, &defnp, errhp, (ub4) 1, (dvoid *) 0, + (sb4) 0, SQLT_REF, (dvoid *) 0, (ub2 *)0, + (ub2 *)0, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **) &dschp, + (ub4) OCI_HTYPE_DESCRIBE, + (size_t) 0, (dvoid **) 0)); + + checkerr(errhp, OCIDescribeAny(svchp, errhp, (text *)"PURCHASE_ORDER", + (ub4) strlen("PURCHASE_ORDER"), OCI_OTYPE_NAME, (ub1)1, + (ub1) OCI_PTYPE_TYPE, dschp)); + + checkerr(errhp, OCIAttrGet((dvoid *) dschp, (ub4) OCI_HTYPE_DESCRIBE, + (dvoid *)&parmp, (ub4 *)0, (ub4)OCI_ATTR_PARAM, errhp)); + + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &type_ref, (ub4 *) 0, + (ub4) OCI_ATTR_REF_TDO, (OCIError *) errhp)); + + /* get type of purchase_order to set in COR descriptor */ + checkerr(errhp, OCIObjectPin(envhp, errhp, type_ref, (OCIComplexObject *) 0, + OCI_PIN_ANY, OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&po_tdo)); + + checkerr(errhp, OCIDefineObject(defnp, errhp, po_tdo, + (dvoid **) &poref, &po_size, (dvoid **) 0, + (ub4 *) 0)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 0, + (ub4) 0, (OCISnapshot *)NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIStmtFetch(stmthp, errhp, (ub4) 1, (ub4) OCI_FETCH_NEXT, + (ub4) OCI_DEFAULT)); + + /*---------------------------- C O R --------------------------------*/ + /* get COR Handle */ + checkerr(errhp, OCIHandleAlloc((dvoid *)envhp, (dvoid **)&corhp, + (ub4)OCI_HTYPE_COMPLEXOBJECT, 0, + (dvoid **)0)); + + /* pin the purchase order - no COR done here */ + checkerr(errhp, OCIObjectPin(envhp, errhp, poref, + (OCIComplexObject *)0, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, (dvoid **)&po)); + + /* By default collections are brought in along with the containing object + (inline). By setting the attribute OCI_ATTR_COMPLEXOBJECT_COLL_OUTOFLINE + to TRUE we indicate that we do not want it to be fetched along with the + containing object, but will fetch it separately on demand (out-of-line) */ + + checkerr(errhp, OCIAttrSet((dvoid *)corhp, (ub4)OCI_HTYPE_COMPLEXOBJECT, + (dvoid *)&outofline, (ub4)sizeof(ub1), + (ub4)OCI_ATTR_COMPLEXOBJECT_COLL_OUTOFLINE, + (OCIError *)errhp)); + + /* pin the customer (should go over the n/w) */ + checkerr(errhp, OCIObjectPin(envhp, errhp, po->cust, corhp, OCI_PIN_ANY, + OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&cust)); + +#ifdef VERIFY_COR + /* Modify the data */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt11, + (ub4) strlen((const char *) stmt11), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt12, + (ub4) strlen((const char *) stmt12), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + /* add new records */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt13, + (ub4) strlen((const char *) stmt13), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) stmt14, + (ub4) strlen((const char *) stmt14), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, + (ub4) 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); +#endif + + /* should see the new records */ + (void) printf("\n---> Dump the table from the top to the bottom.\n"); + /* go to the first element and print out the index */ + checkerr(errhp, OCITableFirst(envhp, errhp, cust->addr, &index)); + (void) printf(" The index of the first element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &elem, &elemind)); + addr = (address *)elem; + null_addr = (null_address *)elemind; + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + (void) printf(" atomic null indicator is %d\n", null_addr->null_address); + (void) printf(" zip null indicator is %d\n", null_addr->null_zip); + (void) printf(" state null indicator is %d\n", null_addr->null_state); + + + for(;!OCITableNext(envhp, errhp, index, cust->addr, + &index, &exist) && exist;) + { + (void) printf(" The index of the next element is : %d.\n", index); + /* print out the element */ + checkerr(errhp, OCICollGetElem(envhp, errhp, (OCIColl *) cust->addr, index, + &exist, (void **) &elem, &elemind)); + addr = (address *)elem; + null_addr = (null_address *)elemind; + (void) printf(" address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + (void) printf(" atomic null indicator is %d\n", + null_addr->null_address); + (void) printf(" zip null indicator is %d\n", null_addr->null_zip); + (void) printf(" state null indicator is %d\n", null_addr->null_state); + } + + checkerr(errhp, OCICacheFree(envhp, errhp, svchp)); + + /* free COR handle */ + checkerr(errhp, OCIHandleFree((dvoid *)corhp, (ub4)OCI_HTYPE_COMPLEXOBJECT)); +} + +int main(int argc, char *argv[]) +{ + OCIEnv *envhp; + OCISvcCtx *svchp; + OCIError *errhp; + OCIServer *srvhp; + OCISession *usrhp; + OCIStmt *stmthp; + sword status = OCI_SUCCESS; + dvoid *tmp = (dvoid *) 0; + + (void) OCIInitialize((ub4) OCI_OBJECT | OCI_DEFAULT, + (dvoid *)0, (dvoid * (*)()) 0, + (dvoid * (*)()) 0, (void (*)()) 0 ); + + (void) OCIEnvInit( &envhp, (ub4) OCI_DEFAULT, 21, (dvoid **) &tmp ); + + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, + 52, (dvoid **) &tmp); + + checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, + 52, (dvoid **) &tmp)); + + checkerr(errhp, OCIServerAttach( srvhp, errhp, (text *) "", + (sb4) strlen(""), (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, + 52, (dvoid **) &tmp)); + + /* set attribute server context in the service context */ + checkerr(errhp, OCIAttrSet( (dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, + (ub4) OCI_ATTR_SERVER, (OCIError *) errhp)); + + checkerr(errhp, OCIHandleAlloc((dvoid *)envhp, (dvoid **)&usrhp, + (ub4)OCI_HTYPE_SESSION, 0, (dvoid **)0)); + + checkerr(errhp, OCIAttrSet((dvoid *) usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"cdemocor", (ub4)strlen("cdemocor"), + (ub4)OCI_ATTR_USERNAME, errhp)); + + checkerr(errhp, OCIAttrSet((dvoid *) usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"cdemocor", (ub4)strlen("cdemocor"), + (ub4)OCI_ATTR_PASSWORD, errhp)); + + checkerr(errhp, OCISessionBegin (svchp, errhp, usrhp, (ub4) OCI_CRED_RDBMS, + (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIAttrSet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)usrhp, (ub4)0, + (ub4)OCI_ATTR_SESSION, errhp)); + + /*-------------------------- get po ref -----------------------------*/ + checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp, + (ub4) OCI_HTYPE_STMT, 50, + (dvoid **) &tmp)); + + (void) printf("Complex object retrieval demo # 1\n"); + (void) printf(" --> Set level in COR descriptor\n"); + demo_cor_1(envhp, svchp, stmthp, errhp); + demo_cor_3(envhp, svchp, stmthp, errhp); + + OCIDescriptorFree((dvoid *)envhp, (ub4)OCI_HTYPE_ENV); + +} + diff --git a/cdemocp.c b/cdemocp.c new file mode 100644 index 0000000..4cd1c21 --- /dev/null +++ b/cdemocp.c @@ -0,0 +1,397 @@ +/* Copyright (c) 2001, 2006, Oracle. All rights reserved. */ +/* + + NAME + cdemocp.c - Basic OCI Connection Pooling functionality + + DESCRIPTION + + This demo invokes multiple threads to insert MAXTHREAD records + into hr.employees table and displays all the inserted records. + + Before running the demo, Please.. + - run rdbms/demo/cdemocp.sql to create pool users. + - make sure that the common schemas are installed. This can + be verified by connecting to hr/hr. If not installed, + please refer to the common schema documentation. + + DMLs on the following columns of hr.employees is done. + If the table structure changes in releases beyond 10iR1, the + demo *may* need to be changed accordingly. + + Name Null? Type + ----------------------------------------- -------- ------------ + EMPLOYEE_ID NOT NULL NUMBER(6) + LAST_NAME NOT NULL VARCHAR2(25) + SALARY NUMBER(8,2) + DEPARTMENT_ID NOT NULL VARCHAR2(10) + JOB_ID NOT NULL VARCHAR2(10) + EMAIL NOT NULL VARCHAR2(25) + HIRE_DATE NOT NULL DATE + + MODIFIED (MM/DD/YY) + msowdaga 04/30/08 - Fix bug 6236196, multiple threads should not share + single error handle + azhao 10/10/06 - case-senstive password change + arrajara 08/07/02 - Move to common schema (scott->hr) and cleanup + jchai 01/28/02 - Merged jchai_change_oci_sp_sc_cp_names + kmohan 04/23/01 - Merged kmohan_cpdemo + mpurayat 04/20/01 - Creation + +*/ + +#include +#include +#include +#include + + +/* Maximum number of threads */ +#define MAXTHREAD 10 +/* Number of columns in select list */ +#define MAXBINDS 7 + +static OCIError *errhp; +static OCIEnv *envhp; +static OCICPool *poolhp; +static OraText *poolName; +static sb4 poolNameLen; + +static int employeeNum[MAXTHREAD]; + +static CONST OraText *database = (OraText *)""; +static CONST OraText *username = (OraText *)"HR"; +static CONST OraText *password = (OraText *)"hr"; +static CONST OraText *appusername = (OraText *)"APPUSER"; +static CONST OraText *apppassword = (OraText *)"apppassword"; + +/* Values to be inserted into employees table */ +static char ename[MAXTHREAD][26]= + {"LASTNAME1","LASTNAME2","LASTNAME3","LASTNAME4","LASTNAME5", + "LASTNAME6","LASTNAME7","LASTNAME8","LASTNAME9","LASTNAME10"}; + +static char ejob[MAXTHREAD][11]= + {"AD_PRES", "AD_VP", "AD_ASST", "FI_MGR", "FI_ACCOUNT", + "AC_MGR", "AC_ACCOUNT", "SA_MAN", "SA_REP", "PU_MAN"}; + +static float esal[MAXTHREAD]={1000.00, 2000.00, 3000.00, 4000.00, 5000.00, + 6000.00, 7000.00, 8000.00, 9000.00, 10000.00}; +static unsigned int edept[MAXTHREAD] = {10,20,10,20,30,10,30,20,10,20}; + +static char email[MAXTHREAD][25]= + {"name1@oracle.com", "name2@oracle.com", "name3@oracle.com", + "name4@oracle.com", "name5@oracle.com", "name6@oracle.com", + "name7@oracle.com", "name8@oracle.com", "name9@oracle.com", + "name10@oracle.com"}; + +static char hdate[MAXTHREAD][10]= + {"21-DEC-01", "22-DEC-01", "23-DEC-01", "24-DEC-01", "25-DEC-01", + "26-DEC-01", "27-DEC-01", "28-DEC-01", "29-DEC-01", "30-DEC-01"}; + +/* Max, min and increment connections */ +static ub4 conMin = 1; +static ub4 conMax = 3; +static ub4 conIncr = 1; + +/* Local functions */ +static void checkerr (OCIError *errhp, sword status); +static void threadFunction (dvoid *arg); +static void queryRows(); +static void deleteRows(); +int main(); + +/*- main -------------------------------------------------------------------*/ +int main() +{ + int i = 0; + sword lstat; + + OCIEnvCreate (&envhp, OCI_THREADED | OCI_OBJECT, (dvoid *)0, NULL, + NULL, NULL, 0, (dvoid *)0); + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **) &poolhp, OCI_HTYPE_CPOOL, + (size_t) 0, (dvoid **) 0); + + /* CREATE THE CONNECTION POOL */ + if (lstat = OCIConnectionPoolCreate(envhp, + errhp,poolhp, &poolName, &poolNameLen, + database,(sb4)strlen((const signed char *)database), + conMin, conMax, conIncr, + appusername,(sb4)strlen((const signed char *)appusername), + apppassword,(sb4)strlen((const signed char *)apppassword) + ,OCI_DEFAULT)) + { + checkerr(errhp,lstat); + exit(1); + } + + /* Delete rows that are already inserted by this demo */ + deleteRows(); + + /* Multiple threads using the connection pool */ + { + OCIThreadId *thrid[MAXTHREAD]; + OCIThreadHandle *thrhp[MAXTHREAD]; + + OCIThreadProcessInit (); + checkerr (errhp, OCIThreadInit (envhp, errhp)); + for (i = 0; i < MAXTHREAD; ++i) + { + checkerr (errhp, OCIThreadIdInit (envhp, errhp, &thrid[i])); + checkerr (errhp, OCIThreadHndInit (envhp, errhp, &thrhp[i])); + } + printf("Multiple threads inserting rows into employees table\n"); + for (i = 0; i < MAXTHREAD; ++i) + { + employeeNum[i]=i; + /* Insert into hr.employees table */ + checkerr (errhp, OCIThreadCreate (envhp, errhp, threadFunction, + (dvoid *) &employeeNum[i], thrid[i], thrhp[i])); + } + for (i = 0; i < MAXTHREAD; ++i) + { + checkerr (errhp, OCIThreadJoin (envhp, errhp, thrhp[i])); + checkerr (errhp, OCIThreadClose (envhp, errhp, thrhp[i])); + checkerr (errhp, OCIThreadIdDestroy (envhp, errhp, &(thrid[i]))); + checkerr (errhp, OCIThreadHndDestroy (envhp, errhp, &(thrhp[i]))); + } + checkerr (errhp, OCIThreadTerm (envhp, errhp)); + } /* ALL THE THREADS ARE COMPLETE */ + + /* Display inserted rows */ + queryRows(); + + checkerr(errhp, OCIConnectionPoolDestroy(poolhp, errhp, OCI_DEFAULT)); + checkerr(errhp, OCIHandleFree((dvoid *)poolhp, OCI_HTYPE_CPOOL)); + checkerr(errhp, OCIHandleFree((dvoid *)errhp, OCI_HTYPE_ERROR)); + return 0; +} +/* - end of main -----------------------------------------------------------*/ + + +/* - Insert records into employees table -----------------------------------*/ +static void threadFunction (dvoid *arg) +{ + OCISvcCtx *svchp = (OCISvcCtx *) 0; + OCIStmt *stmthp = (OCIStmt *)0; + OCIError *errhp2 = (OCIError *) 0; + int empno = *(int *)arg; + sword lstat = 0; + text insertst1[256]; + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp2, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + + if (lstat = OCILogon2(envhp, errhp2, &svchp, + (CONST OraText *)username, (ub4)strlen((const signed char *)username), + (CONST OraText *)password, (ub4)strlen((const signed char *)password), + (CONST OraText *)poolName, (ub4)poolNameLen, + OCI_CPOOL)) + { + checkerr(errhp2,lstat); + exit(1); + } + (void) sprintf(insertst1, + "INSERT INTO hr.employees(employee_id, last_name, job_id, salary, \ + department_id, email, hire_date) \ + VALUES (%d,'%s','%s',%7.2f,%d,'%s','%s')", + empno+1,ename[empno],ejob[empno], + esal[empno],edept[empno], email[empno], hdate[empno]); + + printf("Inserting details of %s\n",ename[empno]); + + OCIHandleAlloc(envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0); + + checkerr(errhp2, OCIStmtPrepare (stmthp, errhp2, (CONST OraText *)insertst1, + (ub4)strlen((const signed char *)insertst1), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + + checkerr(errhp2, OCIStmtExecute (svchp, stmthp, errhp2, (ub4)1, (ub4)0, + (OCISnapshot *)0, (OCISnapshot *)0, OCI_DEFAULT )); + + checkerr(errhp2, OCITransCommit(svchp,errhp2,(ub4)0)); + + checkerr(errhp2, OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT)); + checkerr(errhp2, OCILogoff((dvoid *) svchp, errhp2)); + OCIHandleFree((dvoid *)errhp2, OCI_HTYPE_ERROR); +} +/*- end of threadFunction --------------------------------------------------*/ + + +/* Delete rows which are inserted in the previous invocation of this demo --*/ +static void deleteRows() +{ + OCISvcCtx *svchp = (OCISvcCtx *) 0; + sword status = 0; + text deletest1[256]; + sword lstat; + OCIStmt *stmthp = (OCIStmt *)0; + if (lstat = OCILogon2(envhp, errhp, &svchp, + (CONST OraText *)username, (ub4)strlen((const signed char *)username), + (CONST OraText *)password, (ub4)strlen((const signed char *)password), + (CONST OraText *)poolName, (ub4)poolNameLen, + OCI_CPOOL)) + { + checkerr(errhp,lstat); + exit(1); + } + (void) sprintf(deletest1, + "DELETE FROM hr.employees WHERE employee_id BETWEEN 1 AND %d",MAXTHREAD); + OCIHandleAlloc(envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0); + + checkerr(errhp, OCIStmtPrepare (stmthp, errhp, (text *)deletest1, + (ub4)strlen((const signed char *)deletest1), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute (svchp, stmthp, errhp, (ub4)1, (ub4)0, + (OCISnapshot *)0, (OCISnapshot *)0, OCI_DEFAULT )); + checkerr(errhp, OCITransCommit(svchp,errhp,(ub4)0)); + + checkerr(errhp, OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT)); + checkerr(errhp, OCILogoff((dvoid *) svchp, errhp)); + printf("Deleted all rows between 1 and %d\n", MAXTHREAD); + +} +/*- end of deleteRows ------------------------------------------------------*/ + + +/*- Display the contents of hr.employees table -----------------------------*/ +#define DBUFLEN 20 +static void queryRows() +{ + OCISvcCtx *svchp = (OCISvcCtx *) 0; + OCIStmt *stmthp = (OCIStmt *)0; + OCIDefine *defhp[MAXBINDS]; + OCIDate emp_hdate; + sword status = 0; + sword lstat = 0; + text selectst1[256]; + text emp_name[26]; + text emp_job[11]; + text emp_email[26]; + text datebuf[DBUFLEN]; + ub4 emp_no = 0; + ub4 emp_dept = 0; + ub4 datebuflen = DBUFLEN; + float emp_sal = 0.0; + int i = 0; + + /* Logon in Connection Pool mode */ + if (lstat = OCILogon2(envhp, errhp, &svchp, + (CONST OraText *)username, (ub4)strlen((const signed char *)username), + (CONST OraText *)password, (ub4)strlen((const signed char *)password), + (CONST OraText *)poolName, (ub4)poolNameLen, + OCI_CPOOL)) + { + checkerr(errhp,lstat); + exit(1); + } + + (void) sprintf(selectst1, + "SELECT employee_id, last_name, job_id, salary, department_id, \ + email, hire_date \ + FROM hr.employees WHERE employee_id between 1 and %d",MAXTHREAD); + + OCIHandleAlloc(envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0); + + checkerr(errhp, OCIStmtPrepare (stmthp, errhp, (text *)selectst1, + (ub4)strlen((const signed char *)selectst1), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + checkerr(errhp,OCIDefineByPos (stmthp, &defhp[0], errhp, (ub4)1, + (dvoid *)&emp_no, (sb4)sizeof(ub4), (ub2)SQLT_INT, (dvoid *)0, + (ub2 *)0, (ub2 *)0, OCI_DEFAULT)); + checkerr(errhp,OCIDefineByPos (stmthp, &defhp[1], errhp, (ub4)2, + (dvoid *)&emp_name, (sb4)sizeof(emp_name), (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT)); + checkerr(errhp,OCIDefineByPos (stmthp, &defhp[2], errhp, (ub4)3, + (dvoid *)&emp_job, (sb4)sizeof(emp_job), (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT)); + checkerr(errhp,OCIDefineByPos (stmthp, &defhp[3], errhp, (ub4)4, + (dvoid *)&emp_sal,(sb4)sizeof(float),(ub2)SQLT_FLT,(dvoid *)0, + (ub2 *)0, (ub2 *)0, OCI_DEFAULT)); + checkerr(errhp,OCIDefineByPos (stmthp, &defhp[4], errhp, (ub4)5, + (dvoid *)&emp_dept,(sb4)sizeof(ub4),(ub2)SQLT_INT,(dvoid *)0, + (ub2 *)0, (ub2 *)0, OCI_DEFAULT)); + checkerr(errhp,OCIDefineByPos (stmthp, &defhp[5], errhp, (ub4)6, + (dvoid *)&emp_email,(sb4)sizeof(emp_email),(ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT)); + checkerr(errhp,OCIDefineByPos (stmthp, &defhp[6], errhp, (ub4)7, + (dvoid *)&emp_hdate,(sb4)sizeof(emp_hdate),(ub2)SQLT_ODT, + (dvoid *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT)); + + /* Execute the Query and Fetch MAXTHREAD records */ + if (lstat = OCIStmtExecute (svchp, stmthp, errhp, (ub4)0, + (ub4)0, (OCISnapshot *)0, (OCISnapshot *)0, OCI_DEFAULT )) + { + checkerr(errhp,lstat); + exit(1); + } + /* Printing the values */ + + printf("Displaying the inserted records\n"); + status = OCIStmtFetch(stmthp,errhp,1,OCI_FETCH_NEXT,OCI_DEFAULT); + while (status != OCI_NO_DATA) + { + /* Convert OCIDate into text format for printing */ + lstat = OCIDateToText(errhp, &emp_hdate, (text *)0, (ub1)0, + (text*)"American", (ub4)8, &datebuflen, datebuf); + if (lstat) + checkerr(errhp, lstat); + printf( + "Empno:%u Name:%s Job:%s Sal:%7.2f Deptno:%u Email:%s Hiredate:%s\n", + emp_no,emp_name,emp_job,emp_sal,emp_dept, emp_email, datebuf); + status = OCIStmtFetch(stmthp,errhp,1,OCI_FETCH_NEXT,OCI_DEFAULT); + } + + checkerr(errhp, OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT)); + checkerr(errhp, OCILogoff((dvoid *) svchp, errhp)); +} +/*- end of queryRows --------------------------------------------------------*/ +#undef DBUFLEN + + +/* Handle oci error ---------------------------------------------------------*/ +void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", 512, errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} +/* end of demo -------------------------------------------------------------*/ diff --git a/cdemocp.sql b/cdemocp.sql new file mode 100644 index 0000000..42e8a9f --- /dev/null +++ b/cdemocp.sql @@ -0,0 +1,4 @@ +SET SERVEROUTPUT ON +CONNECT system/manager +CREATE USER appuser identified by apppassword; +GRANT CONNECT,RESOURCE,CREATE ANY DIRECTORY,DROP ANY DIRECTORY TO appuser; diff --git a/cdemocpproxy.c b/cdemocpproxy.c new file mode 100644 index 0000000..8f5d7d1 --- /dev/null +++ b/cdemocpproxy.c @@ -0,0 +1,332 @@ +/* Copyright (c) 2001, 2006, Oracle. All rights reserved. */ +/* + + NAME + cdemocpproxy.c - OCI Connection Pooling, proxy functionality + + DESCRIPTION + + This program invokes multiple threads to insert MAXTHREAD records + into EMP table and displays all the inserted records. + + For proxy login we should alter the user permission as the following + ALTER USER scott GRANT CONNECT THROUGH appuser; + + This demo needs the cdemocpproxy.sql file for creating Pool user. + Before running this demo the cdemocpproxy.sql should be executed. + + MODIFIED (MM/DD/YY) + msowdaga 04/30/08 - Fix bug 6236196, multiple threads should not share + single error handle + azhao 10/10/06 - case-senstive password change + jchai 01/28/02 - Merged jchai_change_oci_sp_sc_cp_names + kmohan 04/23/01 - Merged kmohan_cpdemo + mpurayat 04/20/01 - Creation + +*/ + +#include +#include +#include +#include +/* Maximum Number of threads */ +#define MAXTHREAD 10 + +static OCIError *errhp; +static OCIEnv *envhp; +static OCICPool *poolhp; + +static int employeeNum[MAXTHREAD]; + +static OraText *poolName; +static sb4 poolNameLen; +static CONST OraText *database = (OraText *)""; +static CONST OraText *username =(OraText *)"SCOTT"; +static CONST OraText *password =(OraText *)""; /* no password needed for proxy*/ +static CONST OraText *appusername =(OraText *)"APPUSER"; +static CONST OraText *apppassword =(OraText *)"apppassword"; + +/* Values to be inserted into EMP table */ +static char ename[MAXTHREAD][10]={"JOHN","JIMMY","JET","JIM","JEFREE","JAMES", + "JAMMEE","JOSEP","JOHNY","JEGAN"}; +static char ejob[MAXTHREAD][9]={"MANAGER","TYPIST","ASST MGR","CLERK","MANAGER", + "ASST MGR","CLERK","CLERK","TYPIST","TYPIST"}; +static float esal[MAXTHREAD]={10000.00 + ,5000.00 + ,8000.00 + ,6000.00 + ,10000.00 + ,8000.00 + ,6000.00 + ,6000.00 + ,5000.00 + ,5000.00}; +static unsigned int edept[MAXTHREAD] = {10,20,10,20,30,10,30,20,10,20}; + +/* Max,Min, and increment connections */ +static ub4 conMin = 1; +static ub4 conMax = 3; +static ub4 conIncr = 1; + +static void checkerr (OCIError *errhp, sword status); +static void threadFunction (dvoid *arg); +static void queryRows(); +static void deleteRows(); + +int main(argc, argv) +int argc; +char *argv[]; +{ + int i = 0; + sword lstat; + OCIEnvCreate (&envhp, OCI_THREADED, (dvoid *)0, NULL, + NULL, NULL, 0, (dvoid *)0); + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **) &poolhp, OCI_HTYPE_CPOOL, + (size_t) 0, (dvoid **) 0); + + /* CREATE THE CONNECTION POOL */ + if (lstat = OCIConnectionPoolCreate(envhp, + errhp,poolhp, &poolName, &poolNameLen, + database,(sb4)strlen((const signed char *)database), + conMin, conMax, conIncr, + appusername,(sb4)strlen((const signed char *)appusername), + apppassword,(sb4)strlen((const signed char *)apppassword) + ,OCI_DEFAULT)) + { + checkerr(errhp,lstat); + exit(1); + } + /* Delete Inserted rows by this demo previously */ + deleteRows(); + /* Multiple threads using the connection pool */ + { + OCIThreadId *thrid[MAXTHREAD]; + OCIThreadHandle *thrhp[MAXTHREAD]; + + OCIThreadProcessInit (); + checkerr (errhp, OCIThreadInit (envhp, errhp)); + for (i = 0; i < MAXTHREAD; ++i) + { + checkerr (errhp, OCIThreadIdInit (envhp, errhp, &thrid[i])); + checkerr (errhp, OCIThreadHndInit (envhp, errhp, &thrhp[i])); + } + printf("Multiple threads inserting records into EMP table\n"); + for (i = 0; i < MAXTHREAD; ++i) + { + employeeNum[i]=i; + /* Inserting into EMP table */ + checkerr (errhp, OCIThreadCreate (envhp, errhp, threadFunction, + (dvoid *) &employeeNum[i], thrid[i], thrhp[i])); + } + for (i = 0; i < MAXTHREAD; ++i) + { + checkerr (errhp, OCIThreadJoin (envhp, errhp, thrhp[i])); + checkerr (errhp, OCIThreadClose (envhp, errhp, thrhp[i])); + checkerr (errhp, OCIThreadIdDestroy (envhp, errhp, &(thrid[i]))); + checkerr (errhp, OCIThreadHndDestroy (envhp, errhp, &(thrhp[i]))); + } + checkerr (errhp, OCIThreadTerm (envhp, errhp)); + } /* ALL THE THREADS ARE COMPLETE */ + /* This function will select and display all the rows from EMP table */ + printf("Displaying the Inserted records\n"); + queryRows(); + checkerr(errhp, OCIConnectionPoolDestroy(poolhp, errhp, OCI_DEFAULT)); + checkerr(errhp, OCIHandleFree((dvoid *)poolhp, OCI_HTYPE_CPOOL)); + checkerr(errhp, OCIHandleFree((dvoid *)errhp, OCI_HTYPE_ERROR)); + return 0; +} /* end of main () */ + +/* Inserts records into EMP table */ +static void threadFunction (dvoid *arg) +{ + int empno = *(int *)arg; + OCISvcCtx *svchp = (OCISvcCtx *) 0; + text insertst1[256]; + OCIStmt *stmthp = (OCIStmt *)0; + OCIError *errhp2 = (OCIError *) 0; + sword lstat; + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp2, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + + if (lstat = OCILogon2(envhp, errhp2, &svchp, + (CONST OraText *)username, (ub4)strlen((const signed char *)username), + (CONST OraText *)password, (ub4)strlen((const signed char *)password), + (CONST OraText *)poolName, (ub4)poolNameLen, + OCI_CPOOL)) + { + checkerr(errhp2,lstat); + exit(1); + } + (void) sprintf(insertst1,"INSERT INTO emp(empno, ename, job, sal, deptno) \ + values (%d,'%s','%s',%7.2f,%d)",empno+1,ename[empno],ejob[empno], + esal[empno],edept[empno]); + + printf("Inserting %s\n",ename[empno]); + + OCIHandleAlloc(envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0); + + checkerr(errhp2, OCIStmtPrepare (stmthp, errhp2, (CONST OraText *)insertst1, + (ub4)strlen((const signed char *)insertst1), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + + checkerr(errhp2, OCIStmtExecute (svchp, stmthp, errhp2, (ub4)1, (ub4)0, + (OCISnapshot *)0, (OCISnapshot *)0, OCI_DEFAULT )); + + checkerr(errhp2, OCITransCommit(svchp,errhp2,(ub4)0)); + + checkerr(errhp2, OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT)); + checkerr(errhp2, OCILogoff((dvoid *) svchp, errhp2)); + OCIHandleFree((dvoid *)errhp2, OCI_HTYPE_ERROR); +} /* end of threadFunction (dvoid *) */ +/* Delete rows which are inserted in the prvious invocation of this demo*/ +static void deleteRows() +{ + OCISvcCtx *svchp = (OCISvcCtx *) 0; + sword status = 0; + text deletest1[256]; + sword lstat; + OCIStmt *stmthp = (OCIStmt *)0; + if (lstat = OCILogon2(envhp, errhp, &svchp, + (CONST OraText *)username, (ub4)strlen((const signed char *)username), + (CONST OraText *)password, (ub4)strlen((const signed char *)password), + (CONST OraText *)poolName, (ub4)poolNameLen, + OCI_CPOOL)) + { + checkerr(errhp,lstat); + exit(1); + } + (void) sprintf(deletest1, + "DELETE FROM emp WHERE empno BETWEEN 1 AND %d",MAXTHREAD); + OCIHandleAlloc(envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0); + + checkerr(errhp, OCIStmtPrepare (stmthp, errhp, (text *)deletest1, + (ub4)strlen((const signed char *)deletest1), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + checkerr(errhp, OCIStmtExecute (svchp, stmthp, errhp, (ub4)1, (ub4)0, + (OCISnapshot *)0, (OCISnapshot *)0, OCI_DEFAULT )); + checkerr(errhp, OCITransCommit(svchp,errhp,(ub4)0)); + + checkerr(errhp, OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT)); + checkerr(errhp, OCILogoff((dvoid *) svchp, errhp)); +} /* End of deleteRows */ + +/* Displays the contents of EMP table */ +static void queryRows() +{ + OCISvcCtx *svchp = (OCISvcCtx *) 0; + sword status = 0; + text selectst1[256]; + OCIStmt *stmthp = (OCIStmt *)0; + sword lstat; + /* Define all output variables */ + OCIDefine *defhp1 = (OCIDefine *)0; + OCIDefine *defhp2 = (OCIDefine *)0; + OCIDefine *defhp3 = (OCIDefine *)0; + OCIDefine *defhp4 = (OCIDefine *)0; + OCIDefine *defhp5 = (OCIDefine *)0; + ub4 emp_no,emp_dept; + text emp_name[10],emp_job[9]; + int i; + float emp_sal; + /* Logon in Connection Pool mode */ + if (lstat = OCILogon2(envhp, errhp, &svchp, + (CONST OraText *)username, (ub4)strlen((const signed char *)username), + (CONST OraText *)password, (ub4)strlen((const signed char *)password), + (CONST OraText *)poolName, (ub4)poolNameLen, + OCI_CPOOL)) + { + checkerr(errhp,lstat); + exit(1); + } + + (void) sprintf(selectst1,"SELECT empno, ename, job, sal, deptno FROM emp\ + WHERE empno between 1 and %d",MAXTHREAD); + + OCIHandleAlloc(envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0); + + checkerr(errhp, OCIStmtPrepare (stmthp, errhp, (text *)selectst1, + (ub4)strlen((const signed char *)selectst1), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + checkerr(errhp,OCIDefineByPos (stmthp, &defhp1, errhp, (ub4)1, + (dvoid *)&emp_no, (sb4)sizeof(ub4), (ub2)SQLT_INT, (dvoid *)0, + (ub2 *)0, (ub2 *)0, OCI_DEFAULT)); + checkerr(errhp,OCIDefineByPos (stmthp, &defhp2, errhp, (ub4)2, + (dvoid *)&emp_name, (sb4)10, (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT)); + checkerr(errhp,OCIDefineByPos (stmthp, &defhp3, errhp, (ub4)3, + (dvoid *)&emp_job, (sb4)9, (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT)); + checkerr(errhp,OCIDefineByPos (stmthp, &defhp4, errhp, (ub4)4, + (dvoid *)&emp_sal,(sb4)sizeof(float),(ub2)SQLT_FLT,(dvoid *)0, + (ub2 *)0, (ub2 *)0, OCI_DEFAULT)); + checkerr(errhp,OCIDefineByPos (stmthp, &defhp5, errhp, (ub4)5, + (dvoid *)&emp_dept,(sb4)sizeof(ub4),(ub2)SQLT_INT,(dvoid *)0, + (ub2 *)0, (ub2 *)0, OCI_DEFAULT)); + + /* Execute the Query and Fetch MAXTHREAD records */ + if (lstat = OCIStmtExecute (svchp, stmthp, errhp, (ub4)0, + (ub4)0, (OCISnapshot *)0, (OCISnapshot *)0, OCI_DEFAULT )) + { + checkerr(errhp,lstat); + exit(1); + } + /* Printing the values */ + status = OCIStmtFetch(stmthp,errhp,1,OCI_FETCH_NEXT,OCI_DEFAULT); + while (status != OCI_NO_DATA) + { + printf("Emp No : %u Name : %s Job : %s Salary : %7.2f Dept No : %u\n", + emp_no,emp_name,emp_job,emp_sal,emp_dept); + status = OCIStmtFetch(stmthp,errhp,1,OCI_FETCH_NEXT,OCI_DEFAULT); + } + + checkerr(errhp, OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT)); + checkerr(errhp, OCILogoff((dvoid *) svchp, errhp)); +} /* end of queryRows() */ + +/* This function prints the error */ +void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", 512, errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} diff --git a/cdemocpproxy.sql b/cdemocpproxy.sql new file mode 100644 index 0000000..003030b --- /dev/null +++ b/cdemocpproxy.sql @@ -0,0 +1,5 @@ +SET SERVEROUTPUT ON +CONNECT system/manager +CREATE USER appuser identified by apppassword; +GRANT CONNECT,RESOURCE,CREATE ANY DIRECTORY,DROP ANY DIRECTORY TO appuser; +ALTER USER scott GRANT CONNECT THROUGH appuser; diff --git a/cdemodp.c b/cdemodp.c new file mode 100644 index 0000000..6af78a9 --- /dev/null +++ b/cdemodp.c @@ -0,0 +1,2887 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemodp.c 28-feb-2005.11:23:54 eegolf Exp $ "; +#endif /* RCSID */ + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* Copyright (c) 1998, 2005, Oracle. All rights reserved. */ +/* */ +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* +** NAME: +** cdemodp.c - C Demo program for Direct Path api +** +** +** DESCRIPTION: +** - Direct Path Api driver program to demonstrate loading. +** +** NOTES: +** Demonstrates usage of the direct path API. +** +** -- cdemodp.c -- +** This is one of two C files needed to create a demo that loads +** data through direct path api. +** +** To build and run the demo, please read directions located in +** the header section of the cdemdp*.c modules. +** +** +** +** MODIFIED (MM/DD/YY) +** eegolf 02/28/05 - Conditionalize for OpenVMS +** eegolf 03/30/04 - Update simple_load routine to tkpidrv.c version +** rphillip 03/12/04 - Delete flush row and always load after cvt error +** cmlim 06/11/02 - do not core dump if a null tbl name is given +** msakayed 11/02/01 - Bug #2094292: add/set OCI_ATTR_DIRPATH_INPUT +** eegolf 03/04/01 - Updated for 9i +** cmlim 09/16/98 - Creation (abrumm 04/07/98) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef VMS +#include +#endif + +#ifndef bit +# define bit(x, y) ((x) & (y)) +#endif + +#ifndef OER +# define OER(x) (x) +#endif + +struct loadctl +{ + ub4 nrow_ctl; /* number of rows in column array */ + ub2 ncol_ctl; /* number of columns in column array */ + OCIEnv *envhp_ctl; /* environment handle */ + OCIServer *srvhp_ctl; /* server handle */ + OCIError *errhp_ctl; /* error handle */ + OCIError *errhp2_ctl; /* yet another error handle */ + OCISvcCtx *svchp_ctl; /* service context */ + OCISession *authp_ctl; /* authentication context */ + OCIParam *colLstDesc_ctl; /* column list parameter handle */ + OCIDirPathCtx *dpctx_ctl; /* direct path context */ + OCIDirPathColArray *dpca_ctl; /* direct path column array handle */ + OCIDirPathColArray *dpobjca_ctl; /* dp column array handle for obj*/ + OCIDirPathColArray *dpnestedobjca_ctl; /* dp col array hndl for nested obj*/ + OCIDirPathStream *dpstr_ctl; /* direct path stream handle */ + ub1 *buf_ctl; /* pre-alloc'd buffer for out-of-line data */ + ub4 bufsz_ctl; /* size of buf_ctl in bytes */ + ub4 bufoff_ctl; /* offset into buf_ctl */ + ub4 *otor_ctl; /* Offset to Recnum mapping */ + ub1 *inbuf_ctl; /* buffer for input records */ + struct pctx pctx_ctl; /* partial field context */ + boolean loadobjcol_ctl; /* load to obj col(s)? T/F */ +}; + +/* Forward references: */ + +STATICF void field_flush(/*_ struct loadctl *ctlp, ub4 rowoff _*/); + +STATICF sword field_set(/*_ struct loadctl *ctlp, struct tbl *tblp, + struct obj *objp, text *recp, ub4 rowoff, ub1 bufflg _*/); + +STATICF void init_obj_load(/*_ struct loadctl *ctlp, struct tbl *tblp, + struct obj *objp _*/); +STATICF void alloc_obj_ca(/*_ struct loadctl *ctlp, struct tbl *tblp, + struct obj *objp _*/); +STATICF void init_load(/*_ struct loadctl *ctl, struct tbl *table, + struct sess *session _*/); + +STATICF void simple_load(/*_ struct loadctl *ctlp, struct tbl *tblp, + struct sess *session, FILE *inputfp _*/); + +STATICF void finish_load(/*_ struct loadctl *ctl _*/); + +STATICF void errprint(/*_ dvoid *errhp, ub4 htype, sb4 *errcodep _*/); + +STATICF void checkerr(/*_ dvoid *errhp, ub4 htype, sword status, + text *note, sb4 state, text *file, sb4 line _*/); +STATICF void cleanup(/*_ struct loadctl *ctlp, sb4 ex_status _*/); +STATICF sword do_convert(/*_ struct loadctl *ctlp, ub4 startoff, ub4 rowcnt, + ub4 *cvtCntp, ub2 *badcoffp _*/); +STATICF sword do_load(/*_ struct loadctl *ctlp, ub4 *loadCntp _*/); +STATICF int main(/*_ int argc, char *argv[] _*/); +STATICF void free_obj_hndls(struct loadctl *ctlp, struct obj *objp); +STATICF void set_and_get_attributes(struct loadctl *ctlp, struct tbl *tblp); +STATICF void reset_obj_ca(/*_ struct loadctl *ctlp, struct tbl *tblp, struct obj *objp _*/); + + +/* OCI_CHECK(errhp, ub4 errhptype, sb4 status, struct loadctl *ctlp, + * OCIfunction()); + * errhp is typically a (OCIError *), and errhptype is OCI_HTYPE_ERROR. + * errhp in some cases may be an (OCIEnv *), and errhptype is OCI_HTYPE_ENV. + */ +#define OCI_CHECK(errhp, htype, status, ctlp, OCIfunc) \ +if (OCI_SUCCESS != ((status) = (OCIfunc))) \ +{ \ + checkerr((dvoid *)(errhp), (ub4)(htype), (sword)(status), (text *)0, \ + (sb4)0, (text *)__FILE__, (sb4)__LINE__); \ + if ((status) != OCI_SUCCESS_WITH_INFO) \ + cleanup((struct loadctl *)ctlp, (sb4)1); \ +} else + +#define CHECKERR(errhp, htype, status) \ + checkerr((dvoid *)errhp, (ub4)(htype), (sword)(status), (text *)0, \ + (sb4)0, (text *)__FILE__, (sb4)__LINE__); + +#define FATAL(note, state) \ +do \ +{ \ + checkerr((dvoid *)0, (ub4)OCI_HTYPE_ERROR, (sword)OCI_SUCCESS, \ + (text *)(note), (sb4)(state), (text *)__FILE__, (sb4)__LINE__); \ + cleanup((ctlp), (sb4)2); \ +} while (0) + +/* External references: */ +externref struct tbl table; +externref struct sess session; + +/* External definitions: */ +externdef FILE *output_fp; /* for error msgs */ + + + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* main */ +/* */ +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + + +int main(argc, argv) +int argc; +char *argv[]; +{ + sword ociret; + struct loadctl ctl; + struct loadctl *ctlp = &ctl; + + output_fp = (session.outfn_sess) ? fopen((char *)session.outfn_sess, "w") + : stderr; + + memset((dvoid *)ctlp, 0, sizeof(struct loadctl)); + + /* set up OCI environment and connect to the ORACLE server */ + + OCI_CHECK((dvoid *)0, (ub4)0, ociret, ctlp, + OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 )); + + OCI_CHECK(ctlp->envhp_ctl, OCI_HTYPE_ENV, ociret, ctlp, + OCIEnvInit((OCIEnv **)&ctlp->envhp_ctl, OCI_DEFAULT, (size_t)0, + (dvoid **)0)); + + /* allocate error handles */ + OCI_CHECK(ctlp->envhp_ctl, OCI_HTYPE_ENV, ociret, ctlp, + OCIHandleAlloc((dvoid *)ctlp->envhp_ctl, + (dvoid **)&ctlp->errhp_ctl, OCI_HTYPE_ERROR, + (size_t)0, (dvoid **)0)); + OCI_CHECK(ctlp->envhp_ctl, OCI_HTYPE_ENV, ociret, ctlp, + OCIHandleAlloc((dvoid *)ctlp->envhp_ctl, + (dvoid **)&ctlp->errhp2_ctl, OCI_HTYPE_ERROR, + (size_t)0, (dvoid **)0)); + + /* server contexts */ + OCI_CHECK(ctlp->envhp_ctl, OCI_HTYPE_ENV, ociret, ctlp, + OCIHandleAlloc((dvoid *)ctlp->envhp_ctl, + (dvoid **)&ctlp->srvhp_ctl, OCI_HTYPE_SERVER, + (size_t)0, (dvoid **)0)); + + OCI_CHECK(ctlp->envhp_ctl, OCI_HTYPE_ENV, ociret, ctlp, + OCIHandleAlloc((dvoid *)ctlp->envhp_ctl, + (dvoid **)&ctlp->svchp_ctl, OCI_HTYPE_SVCCTX, + (size_t)0, (dvoid **)0)); + + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIServerAttach(ctlp->srvhp_ctl, ctlp->errhp_ctl, + session.inst_sess, + (sb4)strlen((const char *)session.inst_sess), + OCI_DEFAULT)); + + /* set attribute server context in the service context */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)ctlp->svchp_ctl, OCI_HTYPE_SVCCTX, + (dvoid *)ctlp->srvhp_ctl, (ub4)0, OCI_ATTR_SERVER, + ctlp->errhp_ctl)); + + OCI_CHECK(ctlp->envhp_ctl, OCI_HTYPE_ENV, ociret, ctlp, + OCIHandleAlloc((dvoid *)ctlp->envhp_ctl, + (dvoid **)&ctlp->authp_ctl, (ub4)OCI_HTYPE_SESSION, + (size_t)0, (dvoid **)0)); + + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)ctlp->authp_ctl, (ub4)OCI_HTYPE_SESSION, + (dvoid *)session.username_sess, + (ub4)strlen((char *)session.username_sess), + (ub4)OCI_ATTR_USERNAME, ctlp->errhp_ctl)); + + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)ctlp->authp_ctl, (ub4)OCI_HTYPE_SESSION, + (dvoid *)session.password_sess, + (ub4)strlen((char *)session.password_sess), + (ub4)OCI_ATTR_PASSWORD, ctlp->errhp_ctl)); + + /* begin a session */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCISessionBegin(ctlp->svchp_ctl, ctlp->errhp_ctl, ctlp->authp_ctl, + OCI_CRED_RDBMS, (ub4)OCI_DEFAULT)); + + /* set authentication context into service context */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)ctlp->svchp_ctl, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)ctlp->authp_ctl, (ub4)0, (ub4)OCI_ATTR_SESSION, + ctlp->errhp_ctl)); + + init_load(ctlp, &table, &session); /* initialize the load */ + simple_load(ctlp, &table, &session, stdin); /* load data */ + finish_load(ctlp); /* finish the load */ + + cleanup(ctlp, (sb4)0); + /* NOTREACHED */ + +return 1; +} + + +/* +**++++++++++++++++++++++++++++++ alloc_obj_ca +++++++++++++++++++++++++++++++++ +** +** Description: +** +** Function allocates the column arrays for any objects or nested object columns. +** +** Assumptions: +** +** Parameters: +** +** ctlp load control structure pointer +** tblp table pointer +** objp object pointer +** +** Returns: +** +**------------------------------------------------------------------------- +*/ + +STATICF void alloc_obj_ca(ctlp, tblp, objp) +struct loadctl *ctlp; /* load control structure pointer */ +struct tbl *tblp; /* table pointer */ +struct obj *objp; /* object pointer */ +{ + struct col *colp; + sword ociret; /* return code from OCI calls*/ + ub2 i; + + /* + * Allocate a separate column array for the column object + */ + OCI_CHECK(ctlp->envhp_ctl, OCI_HTYPE_ENV, ociret, ctlp, + OCIHandleAlloc((dvoid *)(objp->ctx_obj), + (dvoid **)&(objp->ca_obj), + (ub4)OCI_HTYPE_DIRPATH_FN_COL_ARRAY, + (size_t)0, (dvoid **)0)); + + /* get number of rows in the column array just allocated */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)(objp->ca_obj), + OCI_HTYPE_DIRPATH_FN_COL_ARRAY, + (dvoid *)(&objp->nrows_obj), (ub4 *)0, + OCI_ATTR_NUM_ROWS, ctlp->errhp_ctl)); + + /* get number of columns in the column array just allocated */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)(objp->ca_obj), + OCI_HTYPE_DIRPATH_FN_COL_ARRAY, + (dvoid *)(&objp->ncol_obj), (ub4 *)0, + OCI_ATTR_NUM_COLS, ctlp->errhp_ctl)); + + /* + * If there are fewer rows in the object column array than in them top-level, + * one, only use as many rows in the other column array. This will happen + * when the object requires more space than all of the other columns inits + * parent table. This simplifies the loop for loading the column arrays + * so that we only have to worry about when we've filled the top-level + * column array. + */ + if (objp->nrows_obj < ctlp->nrow_ctl) + { + ctlp->nrow_ctl = objp->nrows_obj; + } + + /* check each column to see if it is an object, opaque or ref */ + /* and if so, recurse */ + for (i = 0, colp = objp->col_obj; i < objp->ncol_obj; i++, colp++) + { + if (colp->exttyp_col == SQLT_NTY || colp->exttyp_col == SQLT_REF) + { + alloc_obj_ca(ctlp, tblp, colp->obj_col); + } + } + +} + + +/* +**++++++++++++++++++++++++++++++ init_obj_load +++++++++++++++++++++++++++++++++ +** +** Description: +** +** Function which prepares the load of an object column. This should only +** be called from init_load or recursively. +** +** Assumptions: +** +** Parameters: +** +** ctlp load control structure pointer +** tblp table pointer +** objp object pointer +** +** Returns: +** +**------------------------------------------------------------------------- +*/ + +STATICF void init_obj_load(ctlp, tblp, objp) +struct loadctl *ctlp; +struct tbl *tblp; +struct obj *objp; +{ + struct col *colp; + struct fld *fldp; + sword ociret; /* return code from OCI calls*/ + ub2 i; + ub4 pos; + ub2 numCols; + ub4 len; + ub2 type; + ub1 exprtype; + ub1 parmtyp; + OCIParam *colDesc; /* column parameter descriptor*/ + OCIParam *objColLstDesc; /* obj col's list param handle*/ + + /* + * create a context for this object type and describe the attributes + * that will be loaded for this object. + */ + OCI_CHECK(ctlp->envhp_ctl, OCI_HTYPE_ENV, ociret, ctlp, + OCIHandleAlloc((dvoid *)ctlp->dpctx_ctl, + (dvoid **)&(objp->ctx_obj), + (ub4)OCI_HTYPE_DIRPATH_FN_CTX, + (size_t)0, (dvoid **)0)); + + /* If col is an obj, then its constructor is the type name. (req.) + * If col is an opaque/sql function, then use the expression given. (req.) + * If col is a ref, then can set a fixed tbl name. (optional) + */ + + if (objp->name_obj) /* if expression is available */ + { + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(objp->ctx_obj), + (ub4)OCI_HTYPE_DIRPATH_FN_CTX, + (dvoid *) objp->name_obj, + (ub4)strlen((const char *) objp->name_obj), + (ub4)OCI_ATTR_NAME, ctlp->errhp_ctl)); + + /* Set the expression type to obj constructor, opaque/sql function, or ref + * table name. + */ + if (bit(objp->flag_obj, OBJ_OBJ)) + exprtype = OCI_DIRPATH_EXPR_OBJ_CONSTR; /* expr is an obj constructor */ + else if (bit(objp->flag_obj, OBJ_OPQ)) + exprtype = OCI_DIRPATH_EXPR_SQL; /* expr is an opaque/sql func */ + else if (bit(objp->flag_obj, OBJ_REF)) + exprtype = OCI_DIRPATH_EXPR_REF_TBLNAME; /* expr is a ref table name */ + + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(objp->ctx_obj), + (ub4)OCI_HTYPE_DIRPATH_FN_CTX, + (dvoid *) &exprtype, + (ub4) 0, + (ub4)OCI_ATTR_DIRPATH_EXPR_TYPE, ctlp->errhp_ctl)); + } + + /* set number of columns to be loaded */ + numCols = objp->ncol_obj; + + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(objp->ctx_obj), + (ub4)OCI_HTYPE_DIRPATH_FN_CTX, + (dvoid *)&numCols, + (ub4)0, (ub4)OCI_ATTR_NUM_COLS, ctlp->errhp_ctl)); + + /* get the column parameter list */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((dvoid *)(objp->ctx_obj), + OCI_HTYPE_DIRPATH_FN_CTX, + (dvoid *)&objColLstDesc, (ub4 *)0, + OCI_ATTR_LIST_COLUMNS, ctlp->errhp_ctl)); + + /* get attributes of the column parameter list */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)objColLstDesc, + OCI_DTYPE_PARAM, + (dvoid *)&parmtyp, (ub4 *)0, + OCI_ATTR_PTYPE, ctlp->errhp_ctl)); + + if (parmtyp != OCI_PTYPE_LIST) + { + fprintf(output_fp, + "ERROR: expected parmtyp of OCI_PTYPE_LIST, got %d\n", + (int)parmtyp); + } + + /* Now set the attributes of each column by getting a parameter + * handle on each column, then setting attributes on the parameter + * handle for the column. + * Note that positions within a column list descriptor are 1-based. + */ + for (i = 0, pos = 1, colp = objp->col_obj, fldp = objp->fld_obj; + i < objp->ncol_obj; + i++, pos++, colp++, fldp++) + { + /* get parameter handle on the column */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIParamGet((CONST dvoid *)objColLstDesc, + (ub4)OCI_DTYPE_PARAM, ctlp->errhp_ctl, + (dvoid **)&colDesc, pos)); + + colp->id_col = i; /* position in column array*/ + + /* set external attributes on the column */ + + /* column name */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)colp->name_col, + (ub4)strlen((const char *)colp->name_col), + (ub4)OCI_ATTR_NAME, ctlp->errhp_ctl)); + + /* column type */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&colp->exttyp_col, (ub4)0, + (ub4)OCI_ATTR_DATA_TYPE, ctlp->errhp_ctl)); + + /* max data size */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&fldp->maxlen_fld, (ub4)0, + (ub4)OCI_ATTR_DATA_SIZE, ctlp->errhp_ctl)); + + /* If column is chrdate or date, set column (input field) date mask + * to trigger client library to check string for a valid date. + * Note: OCIAttrSet() may be called here w/ a null ptr or null string. + */ + if (colp->date_col) + { + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)colp->datemask_col, + (colp->datemask_col) ? + (ub4)strlen((const char *)colp->datemask_col) :0, + (ub4)OCI_ATTR_DATEFORMAT, ctlp->errhp_ctl)); + } + + if (colp->prec_col) + { + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&colp->prec_col, (ub4)0, + (ub4)OCI_ATTR_PRECISION, ctlp->errhp_ctl)); + } + + if (colp->scale_col) + { + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&colp->scale_col, (ub4)0, + (ub4)OCI_ATTR_SCALE, ctlp->errhp_ctl)); + } + + if (colp->csid_col) + { + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&colp->csid_col, (ub4)0, + (ub4)OCI_ATTR_CHARSET_ID, ctlp->errhp_ctl)); + } + + /* If this is an object, opaque or ref then recurse */ + if (colp->exttyp_col == SQLT_NTY || colp->exttyp_col == SQLT_REF) + { + init_obj_load(ctlp, tblp, colp->obj_col); + + /* set the object function context into the param handle */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)(colp->obj_col->ctx_obj), (ub4)0, + (ub4)OCI_ATTR_DIRPATH_FN_CTX, ctlp->errhp_ctl)); + } + + /* free the parameter handle to the column descriptor */ + OCI_CHECK((dvoid *)0, 0, ociret, ctlp, + OCIDescriptorFree((dvoid *)colDesc, OCI_DTYPE_PARAM)); + } + +} + + +/* +**++++++++++++++++++++++++++++++ init_load +++++++++++++++++++++++++++++++++ +** +** Description: +** +** Function which prepares for a direct path load using the direct +** path API on the table described by 'tblp'. +** +** Assumptions: +** +** The loadctl structure given by 'ctlp' has an appropriately initialized +** environment, and service context handles (already connected to +** the server) prior to calling this function. +** +** Parameters: +** +** ctlp load control structure pointer +** tblp table pointer +** sessp session pointer +** +** Returns: +** +**------------------------------------------------------------------------- +*/ + +STATICF void init_load(ctlp, tblp, sessp) +struct loadctl *ctlp; /* load control structure pointer */ +struct tbl *tblp; /* table pointer */ +struct sess *sessp; /* session pointer */ +{ + struct col *colp; + struct fld *fldp; + sword ociret; /* return code from OCI calls */ + OCIDirPathCtx *dpctx; /* direct path context */ + OCIParam *objAttrDesc; /* attribute parameter descriptor */ + OCIParam *colDesc; /* column parameter descriptor */ + ub1 parmtyp; + ub1 *timestamp = (ub1 *)0; + ub4 size; + ub2 i; + ub4 pos; + ub1 dirpathinput = OCI_DIRPATH_INPUT_TEXT; + + /* allocate and initialize a direct path context */ + OCI_CHECK(ctlp->envhp_ctl, OCI_HTYPE_ENV, ociret, ctlp, + OCIHandleAlloc((dvoid *)ctlp->envhp_ctl, + (dvoid **)&ctlp->dpctx_ctl, + (ub4)OCI_HTYPE_DIRPATH_CTX, + (size_t)0, (dvoid **)0)); + + dpctx = ctlp->dpctx_ctl; /* shorthand*/ + + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)dpctx, (ub4)OCI_HTYPE_DIRPATH_CTX, + (dvoid *)tblp->name_tbl, + (ub4)0, + (ub4)OCI_ATTR_NAME, ctlp->errhp_ctl)); + + if (tblp->subname_tbl && *tblp->subname_tbl) /* set (sub)partition name*/ + { + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)dpctx, (ub4)OCI_HTYPE_DIRPATH_CTX, + (dvoid *)tblp->subname_tbl, + (ub4)strlen((const char *)tblp->subname_tbl), + (ub4)OCI_ATTR_SUB_NAME, ctlp->errhp_ctl)); + } + + if (tblp->owner_tbl) /* set schema (owner) name*/ + { + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)dpctx, (ub4)OCI_HTYPE_DIRPATH_CTX, + (dvoid *)tblp->owner_tbl, + (ub4)strlen((const char *)tblp->owner_tbl), + (ub4)OCI_ATTR_SCHEMA_NAME, ctlp->errhp_ctl)); + } + + /* Note: setting tbl default datemask will not trigger client library + * to check strings for dates - only setting column datemask will. + */ + if (tblp->dfltdatemask_tbl) + { + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)dpctx, (ub4)OCI_HTYPE_DIRPATH_CTX, + (dvoid *)tblp->dfltdatemask_tbl, + (ub4)strlen((const char *)tblp->dfltdatemask_tbl), + (ub4)OCI_ATTR_DATEFORMAT, ctlp->errhp_ctl)); + } + + /* set the data input type to be text */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet ((dvoid *)dpctx, OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&dirpathinput, (ub4)0, + OCI_ATTR_DIRPATH_INPUT, ctlp->errhp_ctl)); + + if (tblp->parallel_tbl) /* set table level parallel option*/ + { + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)dpctx, (ub4)OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&tblp->parallel_tbl, + (ub4)0, (ub4)OCI_ATTR_DIRPATH_PARALLEL, + ctlp->errhp_ctl)); + } + + if (tblp->nolog_tbl) /* set table level nolog option*/ + { + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)dpctx, (ub4)OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&tblp->nolog_tbl, (ub4)0, + (ub4)OCI_ATTR_DIRPATH_NOLOG, ctlp->errhp_ctl)); + } + + if (tblp->objconstr_tbl) /* set obj type of tbl to load if exists */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)dpctx, + (ub4)OCI_HTYPE_DIRPATH_CTX, + (dvoid *) tblp->objconstr_tbl, + (ub4)strlen((const char *) tblp->objconstr_tbl), + (ub4)OCI_ATTR_DIRPATH_OBJ_CONSTR, ctlp->errhp_ctl)); + + /* set number of columns to be loaded */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)dpctx, (ub4)OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&tblp->ncol_tbl, + (ub4)0, (ub4)OCI_ATTR_NUM_COLS, ctlp->errhp_ctl)); + + /* get the column parameter list */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((dvoid *)dpctx, + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&ctlp->colLstDesc_ctl, (ub4 *)0, + OCI_ATTR_LIST_COLUMNS, ctlp->errhp_ctl)); + + /* get attributes of the column parameter list */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)ctlp->colLstDesc_ctl, + OCI_DTYPE_PARAM, + (dvoid *)&parmtyp, (ub4 *)0, + OCI_ATTR_PTYPE, ctlp->errhp_ctl)); + + if (parmtyp != OCI_PTYPE_LIST) + { + fprintf(output_fp, "ERROR: expected parmtyp of OCI_PTYPE_LIST, got%d\n", + (int)parmtyp); + } + + /* Now set the attributes of each column by getting a parameter + * handle on each column, then setting attributes on the parameter + * handle for the column. + * Note that positions within a column list descriptor are 1-based. + */ + for (i = 0, pos = 1, colp = tblp->col_tbl, fldp = tblp->fld_tbl; + i < tblp->ncol_tbl; + i++, pos++, colp++, fldp++) + { + /* get parameter handle on the column */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIParamGet((CONST dvoid *)ctlp->colLstDesc_ctl, + (ub4)OCI_DTYPE_PARAM, ctlp->errhp_ctl, + (dvoid **)&colDesc, pos)); + + colp->id_col = i; /* position in column array*/ + + /* set external attributes on the column */ + + /* column name */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)colp->name_col, + (ub4)strlen((const char *)colp->name_col), + (ub4)OCI_ATTR_NAME, ctlp->errhp_ctl)); + + /* column type */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&colp->exttyp_col, (ub4)0, + (ub4)OCI_ATTR_DATA_TYPE, ctlp->errhp_ctl)); + + /* max data size */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&fldp->maxlen_fld, (ub4)0, + (ub4)OCI_ATTR_DATA_SIZE, ctlp->errhp_ctl)); + + /* If column is chrdate or date, set column (input field) date mask + * to trigger client library to check string for a valid date. + * Note: OCIAttrSet() may be called here w/ a null ptr or null string. + */ + if (colp->date_col) + { + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)colp->datemask_col, + (colp->datemask_col) ? + (ub4)strlen((const char *)colp->datemask_col) :0, + (ub4)OCI_ATTR_DATEFORMAT, ctlp->errhp_ctl)); + } + + if (colp->prec_col) + { + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&colp->prec_col, (ub4)0, + (ub4)OCI_ATTR_PRECISION, ctlp->errhp_ctl)); + } + + if (colp->scale_col) + { + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&colp->scale_col, (ub4)0, + (ub4)OCI_ATTR_SCALE, ctlp->errhp_ctl)); + } + + if (colp->csid_col) + { + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&colp->csid_col, (ub4)0, + (ub4)OCI_ATTR_CHARSET_ID, ctlp->errhp_ctl)); + } + + if (bit(colp->flag_col, COL_OID)) + { + ub1 flg = 1; + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&flg, (ub4)0, + (ub4)OCI_ATTR_DIRPATH_OID, ctlp->errhp_ctl)); + } + + /* If this is an object, opaque or ref then call init_obj_load */ + /* to handle it. */ + if (colp->exttyp_col == SQLT_NTY || colp->exttyp_col == SQLT_REF) + { + init_obj_load(ctlp, tblp, colp->obj_col); + + /* set the object function context into the param handle */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)colDesc, (ub4)OCI_DTYPE_PARAM, + (dvoid *)(colp->obj_col->ctx_obj), (ub4)0, + (ub4)OCI_ATTR_DIRPATH_FN_CTX, ctlp->errhp_ctl)); + + } + + + /* free the parameter handle to the column descriptor */ + OCI_CHECK((dvoid *)0, 0, ociret, ctlp, + OCIDescriptorFree((dvoid *)colDesc, OCI_DTYPE_PARAM)); + } + + /* read back some of the attributes for purpose of illustration */ + for (i = 0, pos = 1, colp = tblp->col_tbl, fldp = tblp->fld_tbl; + i < tblp->ncol_tbl; + i++, pos++, colp++, fldp++) + { + text *s; + ub4 slen; + ub4 maxdsz; + ub2 dty; + + /* get parameter handle on the column */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIParamGet((CONST dvoid *)ctlp->colLstDesc_ctl, + (ub4)OCI_DTYPE_PARAM, ctlp->errhp_ctl, + (dvoid **)&colDesc, pos)); + + + /* get column name */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((dvoid *)colDesc, + OCI_DTYPE_PARAM, + (dvoid *)&s, (ub4 *)&slen, + OCI_ATTR_NAME, ctlp->errhp_ctl)); + + /* check string length */ + if (slen != (ub4)strlen((const char *)colp->name_col)) + { + fprintf(output_fp, + "*** ERROR *** bad col name len in column parameter\n"); + fprintf(output_fp, "\texpected %d, got %d\n", + (int)strlen((const char *)colp->name_col), (int)slen); + } + + if (strncmp((const char *)s, (const char *)colp->name_col, (size_t)slen)) + { + fprintf(output_fp,"*** ERROR *** bad column name in column parameter\n"); + fprintf(output_fp, "\texpected %s, got %s\n", + (char *)colp->name_col, (char *)s); + } + + /* get column type */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((dvoid *)colDesc, + OCI_DTYPE_PARAM, + (dvoid *)&dty, (ub4 *)0, + OCI_ATTR_DATA_TYPE, ctlp->errhp_ctl)); + if (dty != colp->exttyp_col) + { + fprintf(output_fp, "*** ERROR *** bad OCI_ATTR_DATA_TYPE in col param\n"); + fprintf(output_fp, "\tColumn name %s\n", colp->name_col); + fprintf(output_fp, "\t\texpected %d, got %d\n", + (int)colp->exttyp_col, (int)dty); + } + + /* get the max data size */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((dvoid *)colDesc, + OCI_DTYPE_PARAM, + (dvoid *)&maxdsz, (ub4 *)0, + OCI_ATTR_DATA_SIZE, ctlp->errhp_ctl)); + if (maxdsz != fldp->maxlen_fld) + { + fprintf(output_fp, "*** ERROR *** bad OCI_ATTR_DATA_SIZE in col param\n"); + fprintf(output_fp, "\tColumn name %s\n", colp->name_col); + fprintf(output_fp, "\t\texpected %d, got %d\n", + (int)fldp->maxlen_fld, (int)maxdsz); + } + + /* free the parameter handle to the column descriptor */ + OCI_CHECK((dvoid *)0, 0, ociret, ctlp, + OCIDescriptorFree((dvoid *)colDesc, OCI_DTYPE_PARAM)); + } + + { + char *vbuf; + + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)dpctx, (ub4)OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&tblp->xfrsz_tbl, + (ub4)0, (ub4)OCI_ATTR_BUF_SIZE, ctlp->errhp_ctl)); + + /* minimize read system calls */ + vbuf = (char *)malloc((size_t)tblp->xfrsz_tbl); + if (vbuf != (char *)0) + (void)setvbuf(stdin, vbuf, _IOFBF, (size_t)tblp->xfrsz_tbl); + } + + /* prepare the load */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIDirPathPrepare(dpctx, ctlp->svchp_ctl, ctlp->errhp_ctl)); + + /* Allocate column array and stream handles. + * Note that for the column array and stream handles + * the parent handle is the direct path context. + * Also note that Oracle errors are returned via the + * environment handle associated with the direct path context. + */ + OCI_CHECK(ctlp->envhp_ctl, OCI_HTYPE_ENV, ociret, ctlp, + OCIHandleAlloc((dvoid *)ctlp->dpctx_ctl, (dvoid**)&ctlp->dpca_ctl, + (ub4)OCI_HTYPE_DIRPATH_COLUMN_ARRAY, + (size_t)0, (dvoid **)0)); + + OCI_CHECK(ctlp->envhp_ctl, OCI_HTYPE_ENV, ociret, ctlp, + OCIHandleAlloc((dvoid *)ctlp->dpctx_ctl,(dvoid**)&ctlp->dpstr_ctl, + (ub4)OCI_HTYPE_DIRPATH_STREAM, + (size_t)0, (dvoid **)0)); + + /* get number of rows in the column array just allocated */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpca_ctl), + OCI_HTYPE_DIRPATH_COLUMN_ARRAY, + (dvoid *)(&ctlp->nrow_ctl), (ub4 *)0, + OCI_ATTR_NUM_ROWS, ctlp->errhp_ctl)); + + /* get number of columns in the column array just allocated */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpca_ctl), + OCI_HTYPE_DIRPATH_COLUMN_ARRAY, + (dvoid *)(&ctlp->ncol_ctl), (ub4 *)0, + OCI_ATTR_NUM_COLS, ctlp->errhp_ctl)); + + /* allocate the column arrays for any column objects, opaques or refs */ + for (i = 0, colp = tblp->col_tbl; i < tblp->ncol_tbl; i++, colp++) + { + if (colp->exttyp_col == SQLT_NTY || colp->exttyp_col == SQLT_REF) + { + alloc_obj_ca(ctlp, tblp, colp->obj_col); + } + } + + /* allocate buffer for input records */ + ctlp->inbuf_ctl = (ub1 *)malloc(ctlp->nrow_ctl * sessp->maxreclen_sess); + if (ctlp->inbuf_ctl == (ub1 *)0) + { + perror("malloc"); + FATAL("init_load:malloc:inbuf_ctl alloc failure", + ctlp->nrow_ctl * sessp->maxreclen_sess); + } + + /* allocate Offset-TO-Record number mapping array */ + ctlp->otor_ctl = (ub4 *)malloc(ctlp->nrow_ctl * sizeof(ub4)); + if (ctlp->otor_ctl == (ub4 *)0) + { + perror("malloc"); + FATAL("init_load:malloc:otor_ctl alloc failure", + ctlp->nrow_ctl * sizeof(ub4)); + } + + CLEAR_PCTX(ctlp->pctx_ctl); /* initialize partial context*/ + +/* + fprintf(output_fp, "init_load: %ld column array rows\n", + (long)ctlp->nrow_ctl);*/ + + return; + +} + + +/* +**++++++++++++++++++++++++++++++ simple_load +++++++++++++++++++++++++++++++++ +** +** Description: +** +** This function reads input records from 'inputfp', parses the input +** records into fields according to the field description given by +** tblp->fld_tbl, and loads the data into the database. +** +** LOBs can be loaded with this function in a piecewise manner. This +** function is written as a state machine, which cycles through the +** following states: +** RESET, GET_RECORD, FIELD_SET, DO_CONVERT, DO_LOAD, END_OF_INPUT +** +** The normal case of all scalar data, where multiple records fit +** entirely in memory, cycles through the following states: +** RESET, [[GET_RECORD, FIELD_SET]+, DO_CONVERT, DO_LOAD]+, RESET +** +** The case of loading one or more LOB columns, which do not fit entirely +** in memory, has the following state transitions: +** RESET, GET_RECORD, [FIELD_SET, DO_CONVERT, DO_LOAD]+, RESET +** Note: The second and subsequent transitions to the FIELD_SET +** state have a partial record context. +** +** A mapping of column array offset to input record number (otor_ctl[]) +** is maintained by this function for error reporting and recovery. +** +** Assumptions: +** +** Parameters: +** +** ctlp load control structure pointer +** tblp table pointer +** sessp session pointer +** inputfp input file pointer +** +** Returns: +** +**------------------------------------------------------------------------- +*/ + +STATICF void simple_load(ctlp, tblp, sessp, inputfp) +struct loadctl *ctlp; /* load control structure pointer */ +struct tbl *tblp; /* table pointer */ +struct sess *sessp; /* session pointer */ +FILE *inputfp; /* input file pointer */ +{ + sword fsetrv; /* return value from field_set */ + sword cvtrv; /* return value from do_convert */ + sword ldrv; /* return value from do_load */ + ub4 startoff; /* starting row offset for conversion */ + ub4 nxtLoadOff; /* column array offset to be loaded next */ + ub4 rowCnt; /* count of rows populated in column array */ + ub4 cvtCnt; /* count of rows converted */ + ub4 lastoff; /* last row offset used in column array */ + sword state; /* current state machine state */ + sword done; /* set to TRUE when load is complete */ + ub4 input_recnum; /* current input record number */ + ub4 load_recnum; /* record number corresponding to last record loaded */ + ub4 err_recnum; /* record number corresponding to error */ + text *recp; + ub4 cvtcontcnt; /* # of times CONVERT_CONTINUE returned */ + sword ociResetErr; /* stream reset return status */ + sword cvtErrorRowNeedsLoad; /* row had conversion error, needs load */ + + /* set initial state */ + input_recnum = 0; + load_recnum = UB4MAXVAL; + err_recnum = 0; + state = RESET; + fsetrv = FIELD_SET_COMPLETE; + cvtrv = CONVERT_SUCCESS; + ldrv = LOAD_SUCCESS; + done = FALSE; + cvtcontcnt = 0; + cvtErrorRowNeedsLoad = FALSE; + + while (!done) + { + switch (state) + { + case RESET: /* Reset column array and direct stream state to be empty*/ + { + ub2 i; + struct col *colp; + startoff = 0; /* reset starting offset into column array*/ + lastoff = 0; /* last entry set of column array*/ + rowCnt = 0; /* count of rows partial and complete*/ + cvtCnt = 0; /* count of converted rows*/ + nxtLoadOff = 0; + + /* Reset column array state in case a previous conversion needed + * to be continued, or a row is expecting more data. + */ + (void) OCIDirPathColArrayReset(ctlp->dpca_ctl, ctlp->errhp_ctl); + /* reset the column arrays for any column objects, opaques or refs */ + for (i = 0, colp = tblp->col_tbl; i < tblp->ncol_tbl; i++, colp++) + { + if (colp->exttyp_col == SQLT_NTY || colp->exttyp_col == SQLT_REF) + { + reset_obj_ca(ctlp, tblp, colp->obj_col); + } + } + + /* Reset the stream state since we are starting a new stream + * (i.e. don't want to append to existing data in the stream.) + */ + ociResetErr = OCIDirPathStreamReset(ctlp->dpstr_ctl, ctlp->errhp_ctl); + if (ociResetErr != OCI_SUCCESS) + FATAL("OCIDirPathStreamReset failed", ociResetErr); + state = GET_RECORD; /* get some more input records*/ + /* FALLTHROUGH */ + } + + case GET_RECORD: + { + assert(lastoff < ctlp->nrow_ctl); /* array bounds check*/ + + recp = (text *)(ctlp->inbuf_ctl + (lastoff * sessp->maxreclen_sess)); + + if (fgets((char *)recp, (int)sessp->maxreclen_sess, inputfp) + != (char *)NULL) + { + /* set column array offset to input record number map */ + ctlp->otor_ctl[lastoff] = ++input_recnum; + /* if ((input_recnum % 10000) == 0) + fprintf(output_fp, "record number: %d\n", (int)input_recnum); */ + state = FIELD_SET; + /* FALLTHROUGH */ + } + else + { + if (lastoff) + lastoff--; + state = END_OF_INPUT; + break; + } + } + + case FIELD_SET: + { + /* map input data fields to DB columns, set column array entries */ + fsetrv = field_set(ctlp, tblp, (struct obj *) 0, recp, lastoff, 0); + rowCnt = lastoff + 1; + + if (rowCnt == ctlp->nrow_ctl || fsetrv != FIELD_SET_COMPLETE) + { + /* array is full, or have a large partial column, or the + * secondary buffer is in use by an OUTOFLINE field. + */ + state = DO_CONVERT; + /* FALLTHROUGH */ + } + else + { + lastoff++; /* use next column array slot*/ + state = GET_RECORD; /* get next record*/ + break; + } + } + + case DO_CONVERT: + { + /* Either one of the following is true: + * - the column array is full + * - there is a large partial column + * - the secondary buffer used by field_set() is in use + * - previous conversion returned CONVERT_CONTINUE and + * now the conversion is being resumed. + * + * In any case, convert and load the data. + */ + ub4 cvtBadRoff; /* bad row offset from conversion*/ + ub2 cvtBadCoff; /* bad column offset from conversion*/ + + while (startoff <= lastoff) + { + ub4 cvtCntPerCall = 0; /* rows converted in one call to do_convert*/ + + /* note that each call to do_convert() will convert all contiguousrows + * in the colarray until it hit a row in error while converting. + */ + cvtrv = do_convert(ctlp, startoff, rowCnt, &cvtCntPerCall, + &cvtBadCoff); + cvtCnt += cvtCntPerCall; /* sum of rows converted so far in colarray*/ + if (cvtrv == CONVERT_SUCCESS) + { + /* One or more rows converted successfully, break + * out of the conversion loop and load the rows. + */ + assert(cvtCntPerCall > 0); + state = DO_LOAD; + break; + } + else if (cvtrv == CONVERT_ERROR) + { + /* Conversion error. Reject the bad record and + * continue on with the next record (if any). + * cvtBadRoff is the 0-based index of the bad row in + * the column array. cvtBadCoff is the 0-based index + * of the bad column (of the bad row) in the column + * array. + */ + /* This assert was used in the 10.1.0.4.0 version but removed for + * 10.2 because compiler warning for pointless comparison of unsigned + * interger */ + /* assert(cvtCntPerCall >= (ub4)0); */ + + cvtBadRoff = startoff + cvtCntPerCall; + err_recnum = ctlp->otor_ctl[cvtBadRoff]; /* map to input_recnum*/ + fprintf(output_fp, "Conversion Error on record %d, column %d\n", + (int)err_recnum, (int)cvtBadCoff + 1); + + /* print err msg txt */ + errprint((dvoid *)(ctlp->errhp_ctl), OCI_HTYPE_ERROR, + (sb4 *)0); + + /* Always need to load a stream after a conversion error */ + cvtErrorRowNeedsLoad = TRUE; + + if (cvtBadRoff == lastoff) + { + /* Conversion error occurred on the last populated slot + * of the column array. + * Flush the input stream of any data for this row, + * and re-use this slot for another input record. + */ + field_flush(ctlp, lastoff); + state = GET_RECORD; + startoff = cvtBadRoff; /* only convert the last row*/ + rowCnt = 0; /* already tried converting all rows in col array*/ + assert(startoff <= lastoff); + break; + } + else + { + /* Skip over bad row and continue conversion with next row. + * We don't attempt to fill in this slot with another record. + */ + startoff = cvtBadRoff + 1; + assert(startoff <= lastoff); + continue; + } + } + else if (cvtrv == CONVERT_NEED_DATA) /* partial col encountered*/ + { + /* Partial (large) column encountered, load the piece + * and loop back up to field_set to get the rest of + * the partial column. + * startoff is set to the offset into the column array where + * we need to resume conversion from, which should be the + * last entry that we set (lastoff). + */ + state = DO_LOAD; + + /* Set our row position in column array to resume + * conversion at when DO_LOAD transitions to DO_CONVERT. + */ + /* This assert was used in the 10.1.0.4.0 version but removed for + * 10.2 because compiler warning for pointless comparison of unsigned + * interger */ + /* assert(cvtCntPerCall >= (ub4)0); */ + startoff = startoff + cvtCntPerCall; + /* assert(startoff == lastoff); */ + break; + } + else if (cvtrv == CONVERT_CONTINUE) + { + /* The stream buffer is full and there is more data in + * the column array which needs to be converted. + * Load the stream (DO_LOAD) and transition back to + * DO_CONVERT to convert the remainder of the column array, + * without calling the field setting function in between. + * The sequence {DO_CONVERT, DO_LOAD} may occur many times + * for a long row or column. + * Note that startoff becomes the offset into the column array + * where we need to resume conversion from. + */ + cvtcontcnt++; + state = DO_LOAD; + + /* Set our row position in column array (startoff) to + * resume conversion at when we transition from the + * DO_LOAD state back to DO_CONVERT. + */ + /* This assert was used in the 10.1.0.4.0 version but removed for + * 10.2 because compiler warning for pointless comparison of unsigned + * interger */ + /* assert(cvtCntPerCall >= (ub4)0); */ + startoff = startoff + cvtCntPerCall; + assert(startoff <= lastoff); + + break; + } + } /* end while*/ + break; + } + + case DO_LOAD: + { + ub4 loadCnt; /* count of rows loaded by do_load*/ + + ldrv = do_load(ctlp, &loadCnt); + nxtLoadOff = nxtLoadOff + loadCnt; + cvtErrorRowNeedsLoad = FALSE; + + switch (ldrv) + { + case LOAD_SUCCESS: + { + /* The stream has been loaded successfully. What we do next + * depends on the result of the previous conversion step. + */ + load_recnum = ctlp->otor_ctl[nxtLoadOff - 1]; + if (cvtrv == CONVERT_SUCCESS || cvtrv == CONVERT_ERROR) + { + /* The column array was successfully converted (or the + * last row was in error). + * Fill up another array with more input records. + */ + state = RESET; + } + else if (cvtrv == CONVERT_CONTINUE) + { + /* There is more data in column array to convert and load. */ + state = DO_CONVERT; + + /* Note that when do_convert returns CONVERT_CONTINUE that + * startoff was set to the row offset into the column array + * of where to resume conversion. The loadCnt returned by + * OCIDirPathLoadStream is the number of rows successfully + * loaded. + * Do a sanity check on the attributes here. + */ + if (startoff != nxtLoadOff) /* sanity*/ + fprintf(output_fp, "LOAD_SUCCESS/CONVERT_CONTINUE: %ld:%ld\n", + (long)nxtLoadOff, startoff); + + /* Reset the direct stream state so conversion starts at + * the beginning of the stream. + */ + ociResetErr = OCIDirPathStreamReset(ctlp->dpstr_ctl,ctlp->errhp_ctl); + if (ociResetErr != OCI_SUCCESS) + FATAL("OCIDirPathStreamReset failed", ociResetErr); + } + else + { + /* Note that if the previous conversion step returned + * CONVERT_NEED_DATA then the load step would have returned + * LOAD_NEED_DATA too (not LOAD_SUCCESS). + */ + FATAL("DO_LOAD:LOAD_SUCCESS: unexpected cvtrv", cvtrv); + } + break; + } + + case LOAD_ERROR: + { + sb4 oraerr; + ub4 badRowOff; + + badRowOff = nxtLoadOff; + nxtLoadOff += 1; /* account for bad row*/ + err_recnum = ctlp->otor_ctl[badRowOff]; /* map to input_recnum*/ + fprintf(output_fp, "Error on record %ld\n", (long)err_recnum); + + /* print err msg txt */ + errprint((dvoid *)(ctlp->errhp_ctl), OCI_HTYPE_ERROR, &oraerr); + + /* On a load error, all rows up to the row in error are loaded. + * account for that here by setting load_recnum only when some + * rows have been loaded. + */ + if (loadCnt != 0) + load_recnum = err_recnum - 1; + + if (oraerr == OER(600)) + FATAL("DO_LOAD:LOAD_ERROR: server internal error", oraerr); + + if (err_recnum == input_recnum) + { + /* Error occurred on last input row, which may or may not + * be in a partial state. Flush any remaining input for + * the bad row. + */ + field_flush(ctlp, badRowOff); + } + + /* Continue loading this stream until no errors. Note that + * the stream positions itself to the next row on error. + */ + state = DO_LOAD; + + break; + } + + case LOAD_NEED_DATA: + { + load_recnum = ctlp->otor_ctl[nxtLoadOff]; + if (cvtrv == CONVERT_NEED_DATA) + state = FIELD_SET; /* need more input data*/ + else if (cvtrv == CONVERT_CONTINUE) + state = DO_CONVERT; /* have input data, continue with conversion*/ + else + FATAL("DO_LOAD:LOAD_NEED_DATA: unexpected cvtrv", cvtrv); + + /* Reset the direct stream state so conversion starts at + * the beginning of the stream. + */ + ociResetErr = OCIDirPathStreamReset(ctlp->dpstr_ctl, ctlp->errhp_ctl); + if (ociResetErr != OCI_SUCCESS) + FATAL("OCIDirPathStreamReset failed", ociResetErr); + break; + } + + case LOAD_NO_DATA: + { + /* Attempt to either load an empty stream, or a stream + * which has been completely processed. + */ + if (cvtrv == CONVERT_CONTINUE) + { + /* Reset stream state so we convert into an empty stream buffer.*/ + ociResetErr = OCIDirPathStreamReset(ctlp->dpstr_ctl,ctlp->errhp_ctl); + if (ociResetErr != OCI_SUCCESS) + FATAL("OCIDirPathStreamReset failed", ociResetErr); + state = DO_CONVERT; /* convert remainder of column array*/ + } + else + state = RESET; /* get some more input records*/ + break; + } + + default: + FATAL("DO_LOAD: unexpected return value", ldrv); + break; + } + break; + } + + case END_OF_INPUT: + { + if (cvtCnt || cvtErrorRowNeedsLoad) + state = DO_LOAD; /* deal with data already converted, but not loaded*/ + else if (rowCnt) + state = DO_CONVERT; /* deal with a partially populated column array*/ + else + done = TRUE; + break; + } + + default: + FATAL("SIMPLE_LOAD: unexpected state", state); + break; + } /* end switch (state)*/ + } + +/* + fprintf(output_fp, "do_convert returned CONVERT_CONTINUE %ld times\n", + (long)cvtcontcnt);*/ + + fprintf(output_fp, "Number of input records processed = %ld\n", + (long)input_recnum); + +} + + +/* +**++++++++++++++++++++++++++++++ finish_load +++++++++++++++++++++++++++++++++ +** +** Description: +** +** Completes the loading procedure. +** +** Assumptions: +** +** Does not free server data structures related to the load. +** +** Parameters: +** +** ctlp load control structure pointer +** +** Returns: +** +**------------------------------------------------------------------------- +*/ + +STATICF void finish_load(ctlp) +struct loadctl *ctlp; /* load control structure pointer */ +{ + sword ociret; /* return code from OCI call */ + + /* Execute load finishing logic without freeing server data structures + * related to the load. + */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIDirPathDataSave(ctlp->dpctx_ctl, ctlp->errhp_ctl, + (ub4)OCI_DIRPATH_DATASAVE_FINISH)); + + /* free up server data structures for the load. */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIDirPathFinish(ctlp->dpctx_ctl, ctlp->errhp_ctl)); +} + + +/* +**++++++++++++++++++++++++++++++ do_convert +++++++++++++++++++++++++++++++++ +** +** Description: +** +** Convert the data in the column array to stream format. +** +** Assumptions: +** +** +** Parameters: +** +** ctlp pointer to control structure (IN/OUT) +** rowcnt number of rows in column array (IN) +** startoff starting row offset into column array (IN) +** cvtCntp count of rows successfully converted (OUT) +** badcoffp column offset into col array of bad col (OUT) +** +** Returns: +** +** CONVERT_SUCCESS: +** All data in the column array has been successfully converted. +** *cvtCntp is the number of rows successfully converted. +** CONVERT_ERROR: +** Conversion error occurred on the row after the last successfully +** converted row. +** Client Action: +** Continue converting the column array by calling this function +** again with startoff adjusted to skip over the row in error. +** CONVERT_NEED_DATA: +** All data in the column array has been converted, but the last +** column processed was marked as a partial. +** CONVERT_CONTINUE: +** Not all of the data in the column array has been converted due to +** lack of space in the stream buffer. +** Client Action: +** Load the converted stream data, reset the stream, and call this +** function again without modifying the column array and setting +** startoff to the appropriate position in the array. +** +**------------------------------------------------------------------------- +*/ + +sword do_convert(ctlp, startoff, rowcnt, cvtCntp, badcoffp) +struct loadctl *ctlp; /* pointer to control structure (IN/OUT) */ +ub4 rowcnt; /* number of rows in column array (IN) */ +ub4 startoff; /* starting row offset into column array (IN) */ +ub4 *cvtCntp; /* count of rows successfully converted (OUT) */ +ub2 *badcoffp; /* column offset into col array of bad col (OUT) */ +{ + sword retval = CONVERT_SUCCESS; + sword ocierr, ocierr2; + ub2 badcol = 0; + + *cvtCntp = 0; + + if (startoff >= rowcnt) + FATAL("DO_CONVERT: bad startoff", startoff); + + if (rowcnt) + { + /* convert array to stream, filter out bad records */ + ocierr = OCIDirPathColArrayToStream(ctlp->dpca_ctl, ctlp->dpctx_ctl, + ctlp->dpstr_ctl, ctlp->errhp_ctl, + rowcnt, startoff); + switch (ocierr) + { + case OCI_SUCCESS: /* everything succesfully converted to stream */ + retval = CONVERT_SUCCESS; + break; + + case OCI_ERROR: /* some error, most likely a conversion error */ + /* Tell the caller that a conversion error occurred along + * with the number of rows successfully converted (*cvtCntp). + * Note that the caller is responsible for adjusting startoff + * accordingly and calling us again to resume conversion of + * the remaining rows. + */ + retval = CONVERT_ERROR; /* conversion error */ + break; + + case OCI_CONTINUE: /* stream buffer is full */ + /* The stream buffer could not contain all of the data in + * the column array. + * The client should load the converted data, and loop + * back to convert the remaining data in the column array. + */ + retval = CONVERT_CONTINUE; + break; + + case OCI_NEED_DATA: /* partial column encountered */ + /* Everything converted, but have a partial column. + * Load this stream, and return to caller for next piece. + */ + retval = CONVERT_NEED_DATA; + break; + + default: /* unexpected OCI return value! */ + FATAL("do_convert:OCIDirPathColArrayToStream:Unexpected OCI return code", + ocierr); + /* NOTREACHED */ + break; + } + + OCI_CHECK(ctlp->errhp2_ctl, OCI_HTYPE_ERROR, ocierr2, ctlp, + OCIAttrGet((CONST dvoid *)ctlp->dpca_ctl, + OCI_HTYPE_DIRPATH_COLUMN_ARRAY, + (dvoid *)(cvtCntp), (ub4 *)0, + OCI_ATTR_ROW_COUNT, ctlp->errhp2_ctl)); + + OCI_CHECK(ctlp->errhp2_ctl, OCI_HTYPE_ERROR, ocierr2, ctlp, + OCIAttrGet((CONST dvoid *)ctlp->dpca_ctl, + OCI_HTYPE_DIRPATH_COLUMN_ARRAY, + (dvoid *)(&badcol), (ub4 *)0, + OCI_ATTR_COL_COUNT, ctlp->errhp2_ctl)); + } + + *badcoffp = badcol; + + return retval; +} + + +/* +**++++++++++++++++++++++++++++++ do_load +++++++++++++++++++++++++++++++++ +** +** Description: +** +** Load a direct path stream. +** +** Assumptions: +** +** errhp_ctl contains error information when an error is returned +** from this function. +** +** Parameters: +** +** ctlp: Pointer to control structure. +** loadCntp: Count of rows loaded on this call. +** +** Returns: +** +** LOAD_SUCCESS: +** All data loaded succesfully. +** Client Action: +** Supply another stream and call again, or finish the load. +** +** LOAD_ERROR: +** Error while loading occured. *loadCntp is the number of +** rows successfully loaded this call. +** Client Action: +** Use *loadCntp to compute current column array position and +** map the column array position to the input record and reject +** the record. +** +** if (this is a continuation of a row) +** { +** /o server has data for this row buffered o/ +** flush the row data +** } +** +** if (end-of-stream has not been reached) +** { +** call this function again, +** stream loading will resume with the next row in the stream. +** } +** else if (end-of-stream has been reached) +** { +** build another stream and call this function again, +** or finish the load. +** } +** +** LOAD_NEED_DATA: +** Last row was not complete. +** Client Action: +** Caller needs to supply more data for the row (a column is +** being pieced.) Note that the row offset can be determined +** by either the cvtCnt returned from do_convert, or from the +** loadCntp returned by do_load. The column offset for the +** column being pieced is available as an attribute of +** the column array. +** +**------------------------------------------------------------------------- +*/ + +sword do_load(ctlp, loadCntp) +struct loadctl *ctlp; /* pointer to control structure (IN/OUT) */ +ub4 *loadCntp; /* number of rows loaded (OUT) */ +{ + sword ocierr; /* OCI return value */ + sword retval; /* return value from this function */ + sword getRowCnt = FALSE; /* return row count if TRUE */ + + if (loadCntp != (ub4 *)0) + { + *loadCntp = 0; + getRowCnt = TRUE; + } + + /* Load the stream. + * Note that the position in the stream is maintained internally to + * the stream handle, along with offset information for the column + * array which produced the stream. When the conversion to stream + * format is done, the data is appended to the stream. It is the + * responsibility of the caller to reset the stream when appropriate. + * On errors, the position is moved to the next row, or the end of + * the stream if the error occurs on the last row. The next LoadStream + * call will start on the next row, if any. + * If a LoadStream call is made, and end of stream has been reached, + * OCI_NO_DATA is returned. + */ + +#if 1 + ocierr = OCIDirPathLoadStream(ctlp->dpctx_ctl, ctlp->dpstr_ctl, + ctlp->errhp_ctl); +#else + { + ub1 *bufaddr; + ub4 buflen; + + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ocierr, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpstr_ctl), + OCI_HTYPE_DIRPATH_STREAM, + (dvoid *)&bufaddr, (ub4 *)0, + OCI_ATTR_BUF_ADDR, ctlp->errhp_ctl)); + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ocierr, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpstr_ctl), + OCI_HTYPE_DIRPATH_STREAM, + (dvoid *)&buflen, (ub4 *)0, + OCI_ATTR_BUF_SIZE, ctlp->errhp_ctl)); + write(1, (char *)bufaddr, (int)buflen); + fprintf(output_fp, "Wrote %d bytes from stream\n", (int)buflen); + getRowCnt = FALSE; + } +#endif + + switch (ocierr) + { + case OCI_SUCCESS: + /* all data succcesfully loaded */ + retval = LOAD_SUCCESS; + break; + + case OCI_ERROR: + /* Error occurred while loading: could be a partition mapping + * error, null constraint violation, or an out of space + * condition. In any case, we return the number of rows + * processed (successfully loaded). + */ + retval = LOAD_ERROR; + break; + + case OCI_NEED_DATA: + /* Last row was not complete. + * The caller needs to supply another piece. + */ + retval = LOAD_NEED_DATA; + break; + + case OCI_NO_DATA: + /* the stream was empty */ + retval = LOAD_NO_DATA; + break; + + default: + FATAL("do_load:OCIDirPathLoadStream:Unexpected OCI return code", ocierr); + /* NOTREACHED */ + break; + } + + if (getRowCnt) + { + sword ocierr2; + + OCI_CHECK(ctlp->errhp2_ctl, OCI_HTYPE_ERROR, ocierr2, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpstr_ctl), + OCI_HTYPE_DIRPATH_STREAM, + (dvoid *)loadCntp, (ub4 *)0, + OCI_ATTR_ROW_COUNT, ctlp->errhp2_ctl)); + } + + return retval; +} + + +/* +**++++++++++++++++++++++++++++++ field_flush +++++++++++++++++++++++++++++++++ +** +** Description: +** +** Helper function which cleans up the partial context state, and clears it. +** +** Assumptions: +** +** Parameters: +** +** ctlp load control structure pointer +** rowoff column array row offset +** +** Returns: +** +**------------------------------------------------------------------------- +*/ + +STATICF void field_flush(ctlp, rowoff) +struct loadctl *ctlp; /* load control structure pointer */ +ub4 rowoff; /* column array row offset */ +{ + if (ctlp->pctx_ctl.valid_pctx) + { + /* Partial context is valid; make sure the request is + * for the context corresponding to the current row. + */ + assert(rowoff == ctlp->pctx_ctl.row_pctx); + (void) close(ctlp->pctx_ctl.fd_pctx); + free((void *)ctlp->pctx_ctl.fnm_pctx); + } + CLEAR_PCTX(ctlp->pctx_ctl); +} + + +/* +**++++++++++++++++++++++++++++++ field_set +++++++++++++++++++++++++++++++++ +** +** Description: +** +** Sets the input data fields to their corresponding data columns. +** +** Simple field setting. +** Computes address and length of fields in the input record, +** and sets the corresponding column array entry for each input field. +** +** This function only deals with positional fields. +** +** Leading white space is trimmed from the field if FLD_STRIP_LEAD_BLANK +** is set. +** +** Trailing white space is trimmed from the field if FLD_STRIP_TRAIL_BLANK +** is set. +** +** Fields which consist of all spaces are loaded as null columns. +** +** Fields which are marked as FLD_OUTOFLINE are interpreted +** as being file names which can be passed directly to an +** open system call. +** +** NOTES: Discuss how partials are handled. +** +** Assumptions: +** +** Parameters: +** +** ctlp load control structure +** tblp table descriptor +** recp input record +** rowoff column array row offset +** bufflg buffer in use flag +** +** Returns: +** +** FIELD_SET_COMPLETE: +** All fields are complete, the partial context is not valid. +** +** FIELD_SET_BUF +** All fields are complete, the partial context is not valid, but +** data is buffered in a secondary buffer and the column array has +** one or more pointers into the secondary buffer. The caller +** must convert the column array to stream format before calling +** this function again. +** +** FIELD_SET_PARTIAL: +** A field is in the partial state, the partial context is valid +** and is required to continue processing the field. Note that +** when a field is partial, the row which contains the column +** corresponding to the field is partial also. +** +** FIELD_SET_ERROR: +** A read error occured on a secondary (out-of-line) data file. +** +**------------------------------------------------------------------------- +*/ + +/* Deal with WIN32 CR-LF weirdness */ +#if defined(WIN32COMMON) || defined(WIN32) || defined(_WIN32) +#define TKPIDRV_OPEN_MODE (O_RDONLY | O_BINARY) +#else +#define TKPIDRV_OPEN_MODE (O_RDONLY) +#endif + +STATICF sword field_set(ctlp, tblp, objp, recp, rowoff, bufflg) +struct loadctl *ctlp; /* load control structure */ +struct tbl *tblp; /* table descriptor */ +struct obj *objp; /* object descriptor */ +text *recp; /* input record */ +ub4 rowoff; /* column array row offset */ +ub1 bufflg; /* buffer in use flag */ +{ + ub1 *cval; + ub4 ncols; + ub4 thiscol; + ub4 clen, j; /* column length */ + ub1 cflg; + sword ociret; + sword done = FALSE; + int fd; /* file descriptor for out-of-line data */ + char *filename; /* filename for out-of-line data */ + sword partial; + static int count = 0; + struct col *cols; + struct fld *flds; + OCIDirPathColArray * ca; + ub4 recsz = 0; /* Current size of record read in */ + ub1 prntflg = 0; /* Print warning message flag */ + ub4 i = 0; + + /* recsz = strlen ((const char *)recp); */ + /* strlen won't work for binary numbers in record. */ + while (!done) + { + for (i = 0; recp[i] != '\n' ; i++) + { + recsz = recsz + 1; + } + done = TRUE; + } + /* Reset the buffer offset if not recursing */ + if (!bufflg) + ctlp->bufoff_ctl = 0; + + if ((partial = (sword)ctlp->pctx_ctl.valid_pctx) == TRUE) + { + /* partial context is valid; resume where we left off */ + assert(rowoff == ctlp->pctx_ctl.row_pctx); + thiscol = ctlp->pctx_ctl.col_pctx; + } + else + thiscol = 0; + + if (objp != 0) + { + cols = objp->col_obj; + flds = objp->fld_obj; + ncols = objp->ncol_obj; + ca = objp->ca_obj; + } + else + { + cols = tblp->col_tbl; + flds = tblp->fld_tbl; + ncols = tblp->ncol_tbl; + ca = ctlp->dpca_ctl; + } + + for (/* empty */; thiscol < ncols; thiscol++) + { + struct col *colp = &cols[thiscol]; + struct fld *fldp = &flds[thiscol]; + + if (partial) + { + /* partials are always from a secondary file */ + fd = ctlp->pctx_ctl.fd_pctx; + filename = ctlp->pctx_ctl.fnm_pctx; + } + else /* !partial*/ + { + fd = -1; + filename = (char *)0; + cval = (ub1 *)recp + fldp->begpos_fld - 1; + + /* + ** Check the field length is not longer than the current record length. + ** If it is, issue a warning and set the clen to the record length - + ** the beginning field position. + */ + if (fldp->endpos_fld > recsz ) + { + if (!prntflg) + { + fprintf(output_fp, + "Warning: Max field length, %d for record %d, is greater than the current record size %d.\n", + fldp->endpos_fld, (rowoff+1), recsz); + prntflg = 1; + } + clen = recsz - fldp->begpos_fld + 1; + } + else + clen = fldp->endpos_fld - fldp->begpos_fld + 1; + + j = 0; + if (bit(fldp->flag_fld, FLD_STRIP_LEAD_BLANK)) + { + /* trim leading white space */ + for (/*empty*/; j < clen; j++) + if (!isspace((int)cval[j])) + break; + } + + if (j >= clen) + clen = 0; /* null column, handled below*/ + else + { + if (bit(fldp->flag_fld, FLD_STRIP_TRAIL_BLANK)) + { + /* trim trailing white space or new line char within field length. */ + while ((clen && isspace((int)cval[clen - 1]))|| + (clen && ((int)cval[clen - 1]== '\n'))) + clen--; + } + cval = cval + j; + clen = clen - j; + } + + if (colp->exttyp_col == SQLT_NTY || colp->exttyp_col == SQLT_REF) + goto obj; + + if (clen) + { + if (bit(fldp->flag_fld, FLD_INLINE)) + { + cflg = OCI_DIRPATH_COL_COMPLETE; + } + else if (bit(fldp->flag_fld, FLD_OUTOFLINE)) + { + filename = (char *)malloc((size_t)clen+1); + if (!filename) + { + perror("malloc"); + FATAL("field_set: cannot malloc buf for filename", (clen + 1)); + } + (void) memcpy((dvoid *)filename, (dvoid *)cval, (size_t)clen); + filename[clen] = 0; + fd = open(filename, TKPIDRV_OPEN_MODE); + SET_PCTX(ctlp->pctx_ctl, rowoff, thiscol, (ub4)0, fd, filename); + LEN_PCTX(ctlp->pctx_ctl) = 0; + } + else + { + FATAL("field_set: unknown field type", fldp->flag_fld); + } + } + else + { + cflg = OCI_DIRPATH_COL_NULL; /* all spaces become null*/ + cval = (ub1 *)0; + } + } + + if (bit(fldp->flag_fld, FLD_OUTOFLINE)) + { + char *buf; + ub4 bufsz; + int cnt; + + if (!ctlp->buf_ctl) + { + ctlp->buf_ctl = (ub1 *)malloc((size_t)SECONDARY_BUF_SIZE); + ctlp->bufsz_ctl = SECONDARY_BUF_SIZE; + } + + if ((ctlp->bufsz_ctl - ctlp->bufoff_ctl) > SECONDARY_BUF_SLOP) + { + buf = (char *)ctlp->buf_ctl + ctlp->bufoff_ctl; /* buffer pointer*/ + bufsz = (int)ctlp->bufsz_ctl - ctlp->bufoff_ctl; /* buffer size*/ + + if (fd == -1) + cnt = 0; + else + cnt = read(fd, buf, bufsz); + + if (cnt != -1) + { + cval = (ub1 *)buf; + clen = (ub4)cnt; + + if (cnt < bufsz) /* all file data has been read*/ + { + /* mark column as null or complete */ + if (cnt == 0 && LEN_PCTX(ctlp->pctx_ctl) == 0) + cflg = OCI_DIRPATH_COL_NULL; + else + cflg = OCI_DIRPATH_COL_COMPLETE; + + field_flush(ctlp, rowoff); /* close file, free filename*/ + + /* adjust offset into buffer for use by next field */ + ctlp->bufoff_ctl += cnt; + } + else + cflg = OCI_DIRPATH_COL_PARTIAL; + } + else + { + /* XXX: do something on read failure, like return an error context*/ + field_flush(ctlp, rowoff); /* close file, free filename*/ + return FIELD_SET_ERROR; + } + } + else + { + /* no room in secondary buffer, return a 0 length partial + * and pick it up next time. + */ + cflg = OCI_DIRPATH_COL_PARTIAL; + clen = 0; + cval = (ub1 *)NULL; + } + } + + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIDirPathColArrayEntrySet(ca, ctlp->errhp_ctl, + rowoff, colp->id_col, + cval, clen, cflg)); + + if (cflg == OCI_DIRPATH_COL_PARTIAL) + { + /* Partials only occur for OutOfLine data + * remember the row offset, column offset, + * total length of the column so far, + * and file descriptor to get data from on + * subsequent calls to this function. + */ + LEN_PCTX(ctlp->pctx_ctl) += clen; + return FIELD_SET_PARTIAL; + } + +obj: + if (colp->exttyp_col == SQLT_NTY || colp->exttyp_col == SQLT_REF) + { + /* check for NULL for the whole object. If clen is not empty, then the + * object is not null. + */ + + objp = colp->obj_col; + if (clen) + { + field_set(ctlp, tblp, colp->obj_col, recp, objp->rowoff_obj, 1); + objp->rowoff_obj++; + + /* Set the entry in the parent column array to be the column array + * for the object/ + */ + cflg = OCI_DIRPATH_COL_COMPLETE; + clen = sizeof(objp->ca_obj); + cval = (ub1 *) objp->ca_obj; + + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIDirPathColArrayEntrySet(ca, ctlp->errhp_ctl, + rowoff, colp->id_col, + cval, clen, cflg)); + + } + else + { + /* set the entry in the column array to be NULL flag */ + cflg = OCI_DIRPATH_COL_NULL; + clen = 0; + cval = (ub1 *)NULL; + + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIDirPathColArrayEntrySet(ca, ctlp->errhp_ctl, + rowoff, colp->id_col, + cval, clen, cflg)); + } + + } + + } /* end of setting attr values in col array */ + + CLEAR_PCTX(ctlp->pctx_ctl); + if (ctlp->bufoff_ctl) /* data in secondary buffer for this row*/ + return FIELD_SET_BUF; + else + return FIELD_SET_COMPLETE; + +} + + +/* +**++++++++++++++++++++++++++++++ errprint +++++++++++++++++++++++++++++++++ +** +** Description: +** +** Assumptions: +** +** Parameters: +** +** errhp +** htype +** errcodep +** +** Returns: +** +**------------------------------------------------------------------------- +*/ + +STATICF void errprint(errhp, htype, errcodep) +dvoid *errhp; +ub4 htype; +sb4 *errcodep; +{ + text errbuf[512]; + + if (errhp) + { + sb4 errcode; + + if (errcodep == (sb4 *)0) + errcodep = &errcode; + + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, errcodep, + errbuf, (ub4) sizeof(errbuf), htype); + (void) fprintf(output_fp, "Error - %.*s\n", 512, errbuf); + } +} + + +/* +**++++++++++++++++++++++++++++++ checkerr +++++++++++++++++++++++++++++++++ +** +** Description: +** +** Assumptions: +** +** Parameters: +** +** errhp +** htype +** status +** note +** code +** file +** line +** +** Returns: +** +**------------------------------------------------------------------------- +*/ + +STATICF void checkerr(errhp, htype, status, note, code, file, line) +dvoid *errhp; +ub4 htype; +sword status; +text *note; +sb4 code; +text *file; +sb4 line; +{ + sb4 errcode = 0; + + if ((status != OCI_SUCCESS)) + (void) fprintf(output_fp, "OCI Error %ld occurred at File %s:%ld\n", + (long)status, (char *)file, (long)line); + + if (note) + (void) fprintf(output_fp, "File %s:%ld (code=%ld) %s\n", + (char *)file, (long)line, (long)code, (char *)note); + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) fprintf(output_fp, "Error - OCI_SUCCESS_WITH_INFO\n"); + errprint(errhp, htype, &errcode); + break; + case OCI_NEED_DATA: + (void) fprintf(output_fp, "Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) fprintf(output_fp, "Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + errprint(errhp, htype, &errcode); + break; + case OCI_INVALID_HANDLE: + (void) fprintf(output_fp, "Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) fprintf(output_fp, "Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) fprintf(output_fp, "Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} + + +/* +**++++++++++++++++++++++++++++++ cleanup +++++++++++++++++++++++++++++++++ +** +** Description: +** +** Frees up handles and exit with the supplied exit status code. +** +** Assumptions: +** +** Parameters: +** +** ctlp load control structure pointer +** ex_status +** +** Returns: +** ex_status +** +**------------------------------------------------------------------------- +*/ + +STATICF void cleanup(ctlp, ex_status) +struct loadctl *ctlp; /* load control structure pointer */ +sb4 ex_status; +{ + sword ociret; + + /* Free the column array and stream handles if they have been + * allocated. We don't need to do this since freeing the direct + * path context will free the heap which these child handles have + * been allocated from. I'm doing this just to exercise the code + * path to free these handles. + */ + if (ctlp->dpca_ctl) + { + ociret = OCIHandleFree((dvoid *)ctlp->dpca_ctl, + OCI_HTYPE_DIRPATH_COLUMN_ARRAY); + if (ociret != OCI_SUCCESS) + CHECKERR(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret); + } + + if (ctlp->dpstr_ctl) + { + ociret = OCIHandleFree((dvoid *)ctlp->dpstr_ctl, + OCI_HTYPE_DIRPATH_STREAM); + if (ociret != OCI_SUCCESS) + CHECKERR(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret); + } + + /* free object-related dpapi handles if loading to obj/opq/ref cols */ + if (ctlp->loadobjcol_ctl) + { + ub2 i; + struct col *colp; + struct tbl *tblp = &table; + + for (i = 0, colp = tblp->col_tbl; i < tblp->ncol_tbl; i++, colp++) + { + if (colp->exttyp_col == SQLT_NTY || colp->exttyp_col == SQLT_REF) + { + free_obj_hndls(ctlp, colp->obj_col); + + if (colp->obj_col->ca_obj) + { + ociret = OCIHandleFree((dvoid *)(colp->obj_col->ca_obj), + OCI_HTYPE_DIRPATH_FN_COL_ARRAY); + if (ociret != OCI_SUCCESS) + CHECKERR(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret); + } + + if (colp->obj_col->ctx_obj) + { + ociret = OCIHandleFree((dvoid *)(colp->obj_col->ctx_obj), + OCI_HTYPE_DIRPATH_FN_CTX); + if (ociret != OCI_SUCCESS) + CHECKERR(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret); + } + } + } + } + + if (ctlp->dpctx_ctl) + { + ociret = OCIHandleFree((dvoid *)ctlp->dpctx_ctl, OCI_HTYPE_DIRPATH_CTX); + if (ociret != OCI_SUCCESS) + CHECKERR(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret); + } + + if (ctlp->errhp_ctl && ctlp->srvhp_ctl) + { + (void) OCIServerDetach(ctlp->srvhp_ctl, ctlp->errhp_ctl, OCI_DEFAULT ); + ociret = OCIHandleFree((dvoid *)ctlp->srvhp_ctl, OCI_HTYPE_SERVER); + if (ociret != OCI_SUCCESS) + CHECKERR(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret); + } + + if (ctlp->svchp_ctl) + (void) OCIHandleFree((dvoid *) ctlp->svchp_ctl, OCI_HTYPE_SVCCTX); + if (ctlp->errhp_ctl) + (void) OCIHandleFree((dvoid *) ctlp->errhp_ctl, OCI_HTYPE_ERROR); + + if ((output_fp != stdout) && (output_fp != stderr)) + fclose(output_fp); + + exit((int)ex_status); +} + + +/* +**++++++++++++++++++++++++++++ free_obj_hndls +++++++++++++++++++++++++++++++++ +** +** Description: +** +** Frees up dpapi object handles (function column array & function context). +** +** Assumptions: +** +** Parameters: +** +** ctlp load control structure pointer +** objp object structure pointer +** +** Returns: +** Nothing. +** +**------------------------------------------------------------------------- +*/ +STATICF void free_obj_hndls(ctlp, objp) +struct loadctl *ctlp; +struct obj *objp; +{ + ub2 i; + struct col *colp; /* column pointer */ + sword ociret; + + for (i = 0, colp = objp->col_obj; i < objp->ncol_obj; i++, colp++) + { + if (colp->exttyp_col == SQLT_NTY || colp->exttyp_col == SQLT_REF) + { + free_obj_hndls(ctlp, colp->obj_col); + + if (colp->obj_col->ca_obj) + { + ociret = OCIHandleFree((dvoid *)(colp->obj_col->ca_obj), + OCI_HTYPE_DIRPATH_FN_COL_ARRAY); + if (ociret != OCI_SUCCESS) + CHECKERR(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret); + } + + if (colp->obj_col->ctx_obj) + { + ociret = OCIHandleFree((dvoid *)(colp->obj_col->ctx_obj), + OCI_HTYPE_DIRPATH_FN_CTX); + if (ociret != OCI_SUCCESS) + CHECKERR(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret); + } + } + } +} + +/* +**+++++++++++++++++++++++++set_and_get_attributes++++++++++++++++++++++++++++ +** +** Description: +** This routine has been provided to improve code coverage of +** setting and retrieving direct path attributes via OCI. It +** sets and gets the direct path attributes that are not exercised +** in any other regression test. +** +** Assumptions: +** None +** Parameters: +** ctlp load control structure pointer +** +** Returns: +** Nothing +**------------------------------------------------------------------------- +*/ + +STATICF void set_and_get_attributes(struct loadctl *ctlp, struct tbl *tblp) +{ + sword ociret; + ub1 parallel_opt, nolog_opt, bad_value=100; + ub1 parallel_enabled=0, nolog_enabled=0; + ub1 mode, load_mode = OCI_DIRPATH_LOAD; + ub1 input_type = OCI_DIRPATH_INPUT_TEXT; + ub1 lock_wait, convert_value=1; + ub1 skip_index_maint=OCI_DIRPATH_INDEX_MAINT_SKIP_ALL; + ub2 charsetid=OCI_UTF16ID, ret_charsetid; + ub4 rows_loaded=0, scn_base=0, scn_wrap=0; + ub4 version_text=1, parallel_extent = 100000; + ub4 ret_version, ret_stream_version; + ub4 stream_version = OCI_DIRPATH_STREAM_VERSION_1; + ub4 out_stream_version, stream_offset; + ub4 attr_nam_len=3; + ub4 dcache_size=0, ret_obj_constr_len; + ub8 granule_size=0, granule_offset=512; + text attr_nam[3]={'b','u','y'},obj_constr[3]={'h','i','\0'}; + text *attrp_nam = attr_nam; + text *obj_constr_ptr = obj_constr; + text *ret_obj_constr_ptr; + text fileinfo[16]="doesnt_exist.dat"; + + /* Improve code coverage in the routines, kpusattr and kpugattr, which + * are the routines behind the OCI routines, OCIAttrSet and OCIAttrGet. + */ + + /*********************************************************************** + * This next section of code will SET the following direct path + * attributes: + * dirpath_mode - mode of direct path context (load, convert) + * version - user assigned version + * stream version - version of stream supported + * storage_initial - initial extent size + * storage_next - next extent size + * file - DB file to load into + * charset_id - character set id + * version (associated with direct path stream handle) + * attr_name - attribute name + * obj_constr - object constructor name + * skip_index_maint- index maintenance method + * convert_value - set to 1 to indicate conversion needed + * granule_offset - offset to last granule + */ + + /* Set the dirpath mode to load */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&load_mode, 0, + OCI_ATTR_DIRPATH_MODE, ctlp->errhp_ctl)); + + /* Set the dirpath version to 1 */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&version_text, 0, + OCI_ATTR_VERSION, ctlp->errhp_ctl)); + + /* Set the dirpath stream version to 100 */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&stream_version, 0, + OCI_ATTR_DIRPATH_STREAM_VERSION, ctlp->errhp_ctl)); + + /* Set the storage for the first parallel extent to 100,000 */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)¶llel_extent, 0, + OCI_ATTR_DIRPATH_STORAGE_INITIAL, ctlp->errhp_ctl)); + + /* Set the storage for subsequent parallel extents to 100,000 */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)¶llel_extent, 0, + OCI_ATTR_DIRPATH_STORAGE_NEXT, ctlp->errhp_ctl)); + + /* Initialize parallel file name to dummy name */ + /* Note: The following code to set the parallel file name + * twice is intentional. The 2nd setting of this + * name is to exercise a path where a file name has + * been set and the memory buffer containing this + * name is freed before processing this new input + * file name. + */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&fileinfo, sizeof(fileinfo), + OCI_ATTR_DIRPATH_FILE, ctlp->errhp_ctl)); + + /* Initialize parallel file name to dummy name */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&fileinfo, sizeof(fileinfo), + OCI_ATTR_DIRPATH_FILE, ctlp->errhp_ctl)); + + /* Set the character set id to UTF16*/ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&charsetid, 0, + OCI_ATTR_CHARSET_ID, ctlp->errhp_ctl)); + + /* Set client interface version. */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(ctlp->dpstr_ctl), + OCI_HTYPE_DIRPATH_STREAM, + (dvoid *)&stream_version, 0, + OCI_ATTR_VERSION, ctlp->errhp_ctl)); + + /* Set the attribute name to a dummy name. This name attribute is + initialized/set in existing code. This setting here is to exercise + the path where the name has already been set and this is the second + time. */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid **)&attrp_nam, attr_nam_len, + OCI_ATTR_NAME, ctlp->errhp_ctl)); + + /* Set the object constructor name to a dummy name. This name attribute is + initialized/set in existing code. This setting here is to exercise + the path where the name has already been set and this is the second + time. */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + (ub4)OCI_HTYPE_DIRPATH_CTX, + (dvoid *)obj_constr_ptr, 0, + OCI_ATTR_DIRPATH_OBJ_CONSTR, ctlp->errhp_ctl)); + + /* Set the attribute, dirpath_index_maint_method, to skip all */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + (ub4)OCI_HTYPE_DIRPATH_CTX, + &skip_index_maint, 0, + OCI_ATTR_DIRPATH_INDEX_MAINT_METHOD, + ctlp->errhp_ctl)); + + /* Set the attribute, dirpath_convert, to 1 (meaning conversion needed) */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + (ub4)OCI_HTYPE_DIRPATH_CTX, + &convert_value, 0, + OCI_ATTR_DIRPATH_CONVERT, ctlp->errhp_ctl)); + + /* Set the size of the granule offset to 512 */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + (ub4)OCI_HTYPE_DIRPATH_CTX, + &granule_offset, 0, + OCI_ATTR_DIRPATH_GRANULE_OFFSET, ctlp->errhp_ctl)); + + /* Exercise several error paths. The OCI_CHECK macro is not used + * since an error is expected as the return status. The attributes + * given are not valid for the specified handle. + */ + + ociret = OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + (ub4)OCI_HTYPE_DIRPATH_CTX, + (dvoid **) &obj_constr_ptr, + (ub4)strlen((const char *)obj_constr_ptr), + OCI_ATTR_ENV, ctlp->errhp_ctl); + + ociret = OCIAttrSet((dvoid *)(ctlp->dpstr_ctl), + (ub4)OCI_HTYPE_DIRPATH_STREAM, + (dvoid **) &obj_constr_ptr, + (ub4)strlen((const char *)obj_constr_ptr), + OCI_ATTR_ENV, ctlp->errhp_ctl); + + ociret = OCIAttrGet((CONST dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&mode,(ub4 *)0, + OCI_ATTR_ENV, ctlp->errhp_ctl); + + + /*******************************************************************/ + /* Now this section will retrieve (GET) the direct path attributes */ + /*******************************************************************/ + /* Using the direct path context handle, fetch the following + * 15 items: + * direct path mode + * number of rows loaded + * attribute name + * character set id + * nolog + * parallel + * stream version + * version + * dcache_size + * obj_constr + * scn base value + * scn wrap value + * dirpath input format + * granule size for unload + * dirpath value for whether the dpapi should wait for lock + */ + + /* Get the dirpath mode */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&mode,(ub4 *)0, + OCI_ATTR_DIRPATH_MODE, ctlp->errhp_ctl)); + + /* Verify the mode. */ + if (mode != load_mode) + { + fprintf(output_fp, + "ERROR: expected direct path load mode of %d, got %d\n", + load_mode, mode); + } + + /* Get the number of rows loaded */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + &rows_loaded,(ub4 *)0, + OCI_ATTR_NUM_ROWS, ctlp->errhp_ctl)); + + /* Then write this value back to the attribute - expect error on return*/ + + ociret = OCIAttrSet((dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + &rows_loaded, (ub4)0, + OCI_ATTR_NUM_ROWS, ctlp->errhp_ctl); + + /* Get the attribute name */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid **)&attrp_nam, &attr_nam_len, + OCI_ATTR_NAME, ctlp->errhp_ctl)); + + + /* Get the character set id */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&ret_charsetid,(ub4 *)0, + OCI_ATTR_CHARSET_ID, ctlp->errhp_ctl)); + + /* Verify the character set id. */ + if (charsetid != ret_charsetid) + { + fprintf(output_fp, + "ERROR: expected character set id of %d, got %d\n", + charsetid, ret_charsetid); + } + + /* Is parallelism enabled? */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((dvoid *)(ctlp->dpctx_ctl), (ub4)OCI_HTYPE_DIRPATH_CTX, + (dvoid *)¶llel_opt, + (ub4 *)0, (ub4)OCI_ATTR_DIRPATH_PARALLEL, + ctlp->errhp_ctl)); + + if (tblp->parallel_tbl) parallel_enabled = TRUE; + + /* Verify that the correct setting for parallel was returned. */ + if (parallel_opt != parallel_enabled) + { + fprintf(output_fp, + "ERROR: expected parallel value of %d, got %d\n", + parallel_enabled, parallel_opt); + } + + /* Logging enabled? */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((dvoid *)(ctlp->dpctx_ctl), (ub4)OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&nolog_opt, (ub4 *)0, + (ub4)OCI_ATTR_DIRPATH_NOLOG, ctlp->errhp_ctl)); + + if (tblp->nolog_tbl) nolog_enabled = TRUE; + + /* Verify that the correct value for nolog was returned. */ + if (nolog_opt != nolog_enabled) + { + fprintf(output_fp, + "ERROR: expected value of nolog to be %d, got %d\n", + nolog_enabled, nolog_opt); + } + + /* Get the version of the server interface for dirpath */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&ret_version,(ub4 *)0, + OCI_ATTR_VERSION, ctlp->errhp_ctl)); + + + /* Get the dirpath stream version */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&ret_stream_version,(ub4 *)0, + OCI_ATTR_DIRPATH_STREAM_VERSION, ctlp->errhp_ctl)); + + /* Verify the stream version number. */ + if (stream_version != ret_stream_version) + { + fprintf(output_fp, + "ERROR: expected direct path stream version of %d, got %d\n", + stream_version, ret_stream_version); + } + + /* Get the object constructor name */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((dvoid *)(ctlp->dpctx_ctl), + (ub4)OCI_HTYPE_DIRPATH_CTX, + (dvoid **) &ret_obj_constr_ptr, &ret_obj_constr_len, + (ub4)OCI_ATTR_DIRPATH_OBJ_CONSTR, ctlp->errhp_ctl)); + + /* Verify the object constructor name. First check string length. */ + if (ret_obj_constr_len != strlen((const char *)obj_constr_ptr)) + { + fprintf(output_fp, "ERROR: bad object constructor name len\n"); + fprintf(output_fp, "\texpected %d, got %d\n", + strlen((const char *)obj_constr_ptr), ret_obj_constr_len); + } + + if (strncmp((const char *)obj_constr_ptr, + (const char *)ret_obj_constr_ptr, (size_t)ret_obj_constr_len)) + { + fprintf(output_fp,"*** ERROR *** bad object constructor name\n"); + fprintf(output_fp, "\texpected %s, got %s\n", + (char *)obj_constr_ptr, (char *)ret_obj_constr_ptr); + } + + /* Get the max. size of date cache */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + (dvoid *)&dcache_size, (ub4 *)0, + OCI_ATTR_DIRPATH_DCACHE_SIZE, ctlp->errhp_ctl)); + + /* Retrieve the SCN base and wrap values */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + &scn_base, (ub4 *)0, + OCI_ATTR_SCN_BASE, ctlp->errhp_ctl)); + + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + &scn_wrap, (ub4 *)0, + OCI_ATTR_SCN_WRAP, ctlp->errhp_ctl)); + + /* Get the format of the input data (stream or text) */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + &input_type, (ub4 *)0, + OCI_ATTR_DIRPATH_INPUT, ctlp->errhp_ctl)); + + /* Was it the size of a granule for an unload operation? */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + &granule_size, (ub4 *)0, + OCI_ATTR_DIRPATH_GRANULE_SIZE, ctlp->errhp_ctl)); + + /* Is the dpapi going to wait to acquire a lock that is held? */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpctx_ctl), + OCI_HTYPE_DIRPATH_CTX, + &lock_wait, (ub4 *)0, + OCI_ATTR_DIRPATH_LOCK_WAIT, ctlp->errhp_ctl)); + + /*******************************************************************/ + /* Using the direct path stream handle, fetch the stream version and + * offset + */ + + /* First, the stream version */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpstr_ctl), + OCI_HTYPE_DIRPATH_STREAM, + &out_stream_version, (ub4 *)0, + OCI_ATTR_VERSION, ctlp->errhp_ctl)); + + /* Verify the stream version number. */ + if (stream_version != out_stream_version) + { + fprintf(output_fp, + "ERROR: expected (using stream handle) a stream version of %d, got %d\n", + stream_version, out_stream_version); + } + + /* Now the stream offset */ + OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp, + OCIAttrGet((CONST dvoid *)(ctlp->dpstr_ctl), + OCI_HTYPE_DIRPATH_STREAM, + &stream_offset, (ub4 *)0, + OCI_ATTR_STREAM_OFFSET, ctlp->errhp_ctl)); + + + /* Now the default case - generates an error since the attribute + type is not valid for this handle. */ + + ociret = OCIAttrGet((CONST dvoid *)(ctlp->dpstr_ctl), + OCI_HTYPE_DIRPATH_STREAM, + &stream_offset, (ub4 *)0, + OCI_ATTR_DATEFORMAT, ctlp->errhp_ctl); + + +} + + +/* +**++++++++++++++++++++++++++++++ reset_obj_ca +++++++++++++++++++++++++++++++++ +** +** Description: +** +** Function resets the column arrays for any objects or nested object columns. +** +** Assumptions: +** +** Parameters: +** +** ctlp load control structure pointer +** tblp table pointer +** objp object pointer +** +** Returns: +** +**------------------------------------------------------------------------- +*/ + +STATICF void reset_obj_ca(ctlp, tblp, objp) +struct loadctl *ctlp; /* load control structure */ +struct tbl *tblp; /* table descriptor */ +struct obj *objp; /* object descriptor */ +{ + struct col *colp; + ub2 i; + + (void) OCIDirPathColArrayReset(objp->ca_obj, ctlp->errhp_ctl); + + objp->rowoff_obj = 0; + + /* check each column to see if it is an object, opaque or ref */ + /* and if so, recurse */ + for (i = 0, colp = objp->col_obj; i < objp->ncol_obj; i++, colp++) + { + if (colp->exttyp_col == SQLT_NTY || colp->exttyp_col == SQLT_REF) + { + reset_obj_ca(ctlp, tblp, colp->obj_col); + } + } + +} + +/* end of file cdemodp.c */ diff --git a/cdemodp.h b/cdemodp.h new file mode 100644 index 0000000..a934b0d --- /dev/null +++ b/cdemodp.h @@ -0,0 +1,114 @@ +/* + * $Header: cdemodp.h 16-feb-2004.10:53:40 eegolf Exp $ + */ + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* Copyright (c) 2004, 20001, Oracle Corporation. All rights reserved. */ +/* All Rights Reserved. */ +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + +/* +** NAME: +** cdemodp.h - C Demo prog for Direct Path api +** +** DESCRIPTION: +** - Common header file for cdemodp driver and client progs. +** +** NOTES: +** +** +** MODIFIED (MM/DD/YY) +** eegolf 02/16/04 - Fix for bug 3441006, change "table" variable name +** cmlim 04/03/01 - remove flag_tbl field +** +** eegolf 02/21/01 - added new 9i items +** cmlim 09/16/98 - Creation +** +*/ + + +#ifndef cdemodp_ORACLE +# define cdemodp_ORACLE + +# include + +# ifndef externdef +# define externdef +# endif + +/* External column attributes */ +struct col +{ + text *name_col; /* column name */ + ub2 id_col; /* column load id */ + ub2 exttyp_col; /* external type */ + text *datemask_col; /* datemask, if applicable */ + ub1 prec_col; /* precision, if applicable */ + sb1 scale_col; /* scale, if applicable */ + ub2 csid_col; /* character set id */ + ub1 date_col; /* is column a chrdate or date? 1=TRUE. 0=FALSE */ + struct obj * obj_col; /* description of object, if applicable */ +#define COL_OID 0x1 /* col is an OID */ + ub4 flag_col; +}; + +/* Input field descriptor + * For this example (and simplicity), + * fields are strictly positional. + */ +struct fld +{ + ub4 begpos_fld; /* 1-based beginning position */ + ub4 endpos_fld; /* 1-based ending position */ + ub4 maxlen_fld; /* max length for out of line field */ + ub4 flag_fld; +#define FLD_INLINE 0x1 +#define FLD_OUTOFLINE 0x2 +#define FLD_STRIP_LEAD_BLANK 0x4 +#define FLD_STRIP_TRAIL_BLANK 0x8 +}; + +struct obj +{ + text *name_obj; /* type name*/ + ub2 ncol_obj; /* number of columns in col_obj*/ + struct col *col_obj; /* column attributes*/ + struct fld *fld_obj; /* field descriptor*/ + ub4 rowoff_obj; /* current row offset in the column array*/ + ub4 nrows_obj; /* number of rows in col array*/ + OCIDirPathFuncCtx *ctx_obj; /* Function context for this obj column*/ + OCIDirPathColArray *ca_obj; /* column array for this obj column*/ + ub4 flag_obj; /* type of obj */ +#define OBJ_OBJ 0x1 /* obj col */ +#define OBJ_OPQ 0x2 /* opaque/sql str col */ +#define OBJ_REF 0x4 /* ref col */ +}; + +struct tbl +{ + text *owner_tbl; /* table owner */ + text *name_tbl; /* table name */ + text *subname_tbl; /* subname, if applicable */ + ub2 ncol_tbl; /* number of columns in col_tbl */ + text *dfltdatemask_tbl; /* table level default date mask */ + struct col *col_tbl; /* column attributes */ + struct fld *fld_tbl; /* field descriptor */ + ub1 parallel_tbl; /* parallel: 1 for true */ + ub1 nolog_tbl; /* no logging: 1 for true */ + ub4 xfrsz_tbl; /* transfer buffer size in bytes */ + text *objconstr_tbl; /* obj constr/type if loading a derived obj */ +}; + +struct sess /* options for a direct path load session */ +{ + text *username_sess; /* user */ + text *password_sess; /* password */ + text *inst_sess; /* remote instance name */ + text *outfn_sess; /* output filename */ + ub4 maxreclen_sess; /* max size of input record in bytes */ +}; + + +#define table table1 /* Bug 3441006 can't use "table" */ + /* for compile on HP Tru64 unix */ +#endif /* cdemodp_ORACLE */ diff --git a/cdemodp0.h b/cdemodp0.h new file mode 100644 index 0000000..db7efec --- /dev/null +++ b/cdemodp0.h @@ -0,0 +1,109 @@ +/* + * $Header: cdemodp0.h 14-jul-99.12:43:24 mjaeger Exp $ + */ + +/* Copyright (c) 1998, 1999, Oracle Corporation. All rights reserved. +*/ + +/* + NAME + cdemodp0.h - C Demo program for Direct Path api + + DESCRIPTION + - Internal data structs, macros, & defines for cdemodp driver. + + NOTES + Structures, macros, constants used only by cdemodp.c. + + MODIFIED (MM/DD/YY) + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + abrumm 12/22/98 - lint + cmlim 11/17/98 - take away hardcoded MAX_RECLEN; now a session parm + cmlim 10/06/98 - correct typo + cmlim 10/02/98 - added externref + cmlim 09/16/98 - internal data structs, macros, & defines for cdemodp + cmlim 09/16/98 - Creation (abrumm 04/07/98) + +*/ + + +#ifndef cdemodp0_ORACLE +# define cdemodp0_ORACLE + +# include +# include + +/* partial field context structure, maintained by field setting function */ +struct pctx +{ + ub1 valid_pctx; /* partial context is valid */ + ub4 pieceCnt_pctx; /* count of partial pieces */ + ub4 row_pctx; /* which row in column array */ + ub4 col_pctx; /* which column in column array */ + ub4 len_pctx; /* length of this column so far */ + int fd_pctx; /* open file descriptor data is coming from */ + char *fnm_pctx; /* filename for data source */ +}; + +/* CLEAR_PCTX(struct pctx pctx) + * Macro to clear the partial context state + */ +#define CLEAR_PCTX(pctx) \ + ((pctx).valid_pctx = FALSE, (pctx).pieceCnt_pctx = 0, \ + (pctx).row_pctx = UB4MAXVAL, (pctx).col_pctx = UB4MAXVAL, \ + (pctx).len_pctx = 0, (pctx).fd_pctx = -1, \ + (pctx).fnm_pctx = (char *)0) + +#define SET_PCTX(pctx, rowoff, coloff, clen, fd, fnm) \ + ((pctx).valid_pctx = TRUE, (pctx).pieceCnt_pctx++, \ + (pctx).row_pctx = (rowoff), (pctx).col_pctx = (coloff), \ + (pctx).len_pctx += (ub4)(clen), (pctx).fd_pctx = (fd), \ + (pctx).fnm_pctx = (fnm)) + +#define LEN_PCTX(pctx) ((pctx).len_pctx) + +/* Does the input record correspond to the first piece of a row? + * Note that a row which is not pieced is a first piece too. + */ +#define FIRST_PIECE(pctx) \ +( (pctx).valid_pctx == FALSE || \ + ((pctx).valid_pctx == TRUE && ((pctx).pieceCnt_pctx == 1))) + +/* return values from field_set() */ +#define FIELD_SET_COMPLETE 0 +#define FIELD_SET_ERROR 1 +#define FIELD_SET_BUF 2 +#define FIELD_SET_PARTIAL 3 + +/* return values from do_convert() */ +#define CONVERT_SUCCESS 0 +#define CONVERT_ERROR 1 +#define CONVERT_NEED_DATA 2 +#define CONVERT_CONTINUE 3 + +/* return values from do_load() */ +#define LOAD_SUCCESS 0 +#define LOAD_ERROR 1 +#define LOAD_NEED_DATA 2 +#define LOAD_NO_DATA 3 + +/* state values for simple_load() */ +#define RESET 1 /* initial state, reset data structures to empty */ +#define GET_RECORD 2 /* get input records */ +#define FIELD_SET 3 /* assign fields of input records to columns */ +#define DO_CONVERT 4 /* convert column array input to stream format */ +#define DO_LOAD 5 /* load the direct stream */ +#define END_OF_INPUT 6 /* no more input data */ + +/* Secondary buffer sizes for OUTOFLINE fields; no science here, just a WAG */ +#define SECONDARY_BUF_SIZE (1024*1024) /* size of secondary buffer */ +#define SECONDARY_BUF_SLOP (8*1024) /* get another field if this much avail */ + +#define STATICF + +#ifndef externref +# define externref extern +#endif + + +#endif /* cdemodp0_ORACLE */ diff --git a/cdemodp_lip.c b/cdemodp_lip.c new file mode 100644 index 0000000..e3f9eee --- /dev/null +++ b/cdemodp_lip.c @@ -0,0 +1,171 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemodp_lip.c 15-aug-2006.09:24:35 jkaloger Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1998, 2006, Oracle. All rights reserved. +*/ + +/* + * -- cdemodp_lip.c -- + * An example program that loads data via direct path api. + * + * Directions: + * 1. make -f demo_rdbms.mk build_dp EXE=cdemodp_lip OBJS=cdemodp_lip.o + * <== make cdemodp_lip executable + * 2. sqlplus scott/tiger @cdemodp_lip.sql <== create lineitem_dp tbl + * 3. cdemodp_lip < cdemodp_lip.dat <== run executable + * 4. to retrieve data, select from "lineitem_dp" as "scott/tiger" + * + */ + +/* + NAME + cdemodp_lip.c - C Demo for Direct Path api for LineItem Partitioned + table. + + DESCRIPTION + - A client module describing lineitem partition table. + To be used with cdemodp driver prog. + + NOTES + Loads the lineitem1 partition of the lineitem table. + + MODIFIED (MM/DD/YY) + jkaloger 08/15/06 - Lowercase passwords for secure verifiers project + msakayed 04/07/03 - fix max_len for l_shipinstruct + cmlim 09/11/01 - fix lint + svedala 01/07/00 - use "DD-MON-RR" mask for date fields + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + cmlim 06/07/99 - set date_col to indicate if col is chrdate or date + abrumm 12/22/98 - account for change to sess structure + cmlim 11/17/98 - add attributes and session options + cmlim 10/11/98 - add directions for running demo program + abrumm 10/14/98 - only table needs to be extern + cmlim 10/02/98 - remove sn.h + cmlim 09/16/98 - a client module (lineitem partition tbl) for cdemodp + cmlim 09/16/98 - Creation + */ +#include +#include +#include + +externdef struct col column[] = +{ + { + (text *)"l_orderkey", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_partkey", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_suppkey", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_linenumber", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_quantity", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_extendedprice", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_discount", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_tax", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_returnflag", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_linestatus", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_shipdate", 0, SQLT_CHR, (text *) "DD-MON-RR", + (sword)0, (sword)0, (ub2)0, (ub1)1 + }, + { + (text *)"l_commitdate", 0, SQLT_CHR, (text *) "DD-MON-RR", + (sword)0, (sword)0, (ub2)0, (ub1)1 + }, + { + (text *)"l_receiptdate", 0, SQLT_CHR, (text *) "DD-MON-RR", + (sword)0, (sword)0, (ub2)0, (ub1)1 + }, + { + (text *)"l_shipinstruct", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_shipmode", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + }, + { + (text *)"l_comment", 0, SQLT_CHR, (text *)0, + (sword)0, (sword)0, (ub2)0, (ub1)0 + } +}; + +/* Field descriptor which maps one-to-one with the column descriptor. + * For this simple example, fields are strictly positional within + * an input record. + */ +externdef struct fld field[] = +{ + { 1, 6, 6, FLD_INLINE }, /* l_orderkey */ + { 7, 11, 5, FLD_INLINE }, /* l_partkey */ + { 12, 15, 4, FLD_INLINE }, /* l_suppkey */ + { 16, 16, 1, FLD_INLINE }, /* l_linenumber */ + { 17, 18, 2, FLD_INLINE }, /* l_quantity */ + { 19, 26, 8, FLD_INLINE }, /* l_extendedprice */ + { 27, 29, 3, FLD_INLINE }, /* l_discount */ + { 30, 32, 3, FLD_INLINE }, /* l_tax */ + { 33, 33, 1, FLD_INLINE }, /* l_returnflag */ + { 34, 34, 1, FLD_INLINE }, /* l_linestatus */ + { 35, 43, 9, FLD_INLINE }, /* l_shipdate */ + { 44, 52, 9, FLD_INLINE }, /* l_commitdate */ + { 53, 61, 9, FLD_INLINE }, /* l_receiptdate */ + { 62, 78, 17, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* l_shipinstruct */ + { 79, 85, 7, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* l_shipmode */ + { 86,128, 43, FLD_INLINE|FLD_STRIP_TRAIL_BLANK }, /* l_comment */ +}; + +/* Note setting of subname field */ +externdef struct tbl table = +{ + (text *)"scott", /* table owner */ + (text *)"lineitem_dp", /* table name */ + (text *)"lineitem1", /* subname (partition, subpartition) */ + (ub2)(sizeof(column) / sizeof(struct col)), /* number of columns */ + (text *)"DD-MON-YY", /* default date format */ + (struct col *)(&column[0]), /* column descriptors */ + (struct fld *)(&field[0]), /* field descriptors */ + (ub1)0, /* parallel */ + (ub1)0, /* nolog */ + (ub4)(64 * 1024) /* transfer buffer size */ +}; + +externdef struct sess session = +{ + (text *)"scott", /* user */ + (text *)"tiger", /* passwd */ + (text *)"", /* instance name */ + (text *)0, /* output file name; NULL implies stderr */ + (ub4)130 /* max input record length */ +}; + + +/* end of file cdemodp_lip.c */ + diff --git a/cdemodr1.c b/cdemodr1.c new file mode 100644 index 0000000..1fe09f7 --- /dev/null +++ b/cdemodr1.c @@ -0,0 +1,1318 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemodr1.c 14-jul-99.13:07:43 mjaeger Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1997, 1999, Oracle Corporation. All rights reserved. +*/ + +/* + + NAME + cdemord1.c - C DEMO program for DML with RETURNING clause - #1. + + DESCRIPTION + This Demo program demonstrates the use of INSERT/UPDATE/DELETE + statements with a RETURNING clause in it. + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + + + NOTES + Adopted from tkp8rv1.c; need to run cdemodr1.sql before running + this demo program. + + MODIFIED (MM/DD/YY) + svedala 10/18/99 - + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 09/09/98 - lines longer than 79 chars reformatted - bug 722491 + azhao 08/19/97 - remove explicit bindhp allocation + echen 07/30/97 - fix bug 516406 + azhao 05/30/97 - Creation + +*/ + +#include + +/*------------------------ Global Variables -------------------------------*/ + +static boolean logged_on = FALSE; + +/* TAB1 columns */ +static int in1[MAXITER]; /* for INTEGER */ +static text in2[MAXITER][40]; /* for CHAR(40) */ +static text in3[MAXITER][40]; /* for VARCHAR2(40) */ +static float in4[MAXITER]; /* for FLOAT */ +static int in5[MAXITER]; /* for DECIMAL */ +static float in6[MAXITER]; /* for DECIMAL(8,3) */ +static int in7[MAXITER]; /* for NUMERIC */ +static float in8[MAXITER]; /* for NUMERIC(7,2) */ +static ub1 in9[MAXITER][7]; /* for DATE */ +static ub1 in10[MAXITER][40]; /* for RAW(40) */ + +/* output buffers */ +static int *p1[MAXITER]; /* for INTEGER */ +static text *p2[MAXITER]; /* for CHAR(40) */ +static text *p3[MAXITER]; /* for VARCHAR2(40) */ +static float *p4[MAXITER]; /* for FLOAT */ +static int *p5[MAXITER]; /* for DECIMAL */ +static float *p6[MAXITER]; /* for DECIMAL(8,3) */ +static int *p7[MAXITER]; /* for NUMERIC */ +static float *p8[MAXITER]; /* for NUMERIC(7,2) */ +static ub1 *p9[MAXITER]; /* for DATE */ +static ub1 *p10[MAXITER]; /* for RAW(40) */ + +static short *ind[MAXCOLS][MAXITER]; /* indicators */ +static ub2 *rc[MAXCOLS][MAXITER]; /* return codes */ +static ub4 *rl[MAXCOLS][MAXITER]; /* return lengths */ + +/* skip values for binding TAB1 */ +static ub4 s1 = (ub4) sizeof(in1[0]); +static ub4 s2 = (ub4) sizeof(in2[0]); +static ub4 s3 = (ub4) sizeof(in3[0]); +static ub4 s4 = (ub4) sizeof(in4[0]); +static ub4 s5 = (ub4) sizeof(in5[0]); +static ub4 s6 = (ub4) sizeof(in6[0]); +static ub4 s7 = (ub4) sizeof(in7[0]); +static ub4 s8 = (ub4) sizeof(in8[0]); +static ub4 s9 = (ub4) sizeof(in9[0]); +static ub4 s10= (ub4) sizeof(in10[0]); + +/* Rows returned in each iteration */ +static ub2 rowsret[MAXITER]; + +/* indicator skips */ +static ub4 indsk[MAXCOLS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +/* return length skips */ +static ub4 rlsk[MAXCOLS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +/* return code skips */ +static ub4 rcsk[MAXCOLS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +static int lowc1[MAXITER], highc1[MAXITER]; + +static ub4 pos[MAXCOLS]; + +static OCIError *errhp; + +/*------------------------end of Global variables--------------------*/ + + +/*========================== UTILITY FUNCTIONS ======================*/ +/* + * These functions are generic functions that can be used in any + * OCI program. + */ + +/* ----------------------------------------------------------------- */ +/* Initialize environment, allocate handles */ +/* ----------------------------------------------------------------- */ +sword init_handles(envhp, svchp, errhp, srvhp, authp, init_mode) +OCIEnv **envhp; +OCISvcCtx **svchp; +OCIError **errhp; +OCIServer **srvhp; +OCISession **authp; +ub4 init_mode; +{ + (void) printf("Environment setup ....\n"); + + /* Initialize the OCI Process */ + if (OCIInitialize(init_mode, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 )) + { + (void) printf("FAILED: OCIInitialize()\n"); + return OCI_ERROR; + } + + /* Inititialize the OCI Environment */ + if (OCIEnvInit((OCIEnv **) envhp, (ub4) OCI_DEFAULT, + (size_t) 0, (dvoid **) 0 )) + { + (void) printf("FAILED: OCIEnvInit()\n"); + return OCI_ERROR; + } + + /* Allocate a service handle */ + if (OCIHandleAlloc((dvoid *) *envhp, (dvoid **) svchp, + (ub4) OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc() on svchp\n"); + return OCI_ERROR; + } + + /* Allocate an error handle */ + if (OCIHandleAlloc((dvoid *) *envhp, (dvoid **) errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc() on errhp\n"); + return OCI_ERROR; + } + + /* Allocate a server handle */ + if (OCIHandleAlloc((dvoid *) *envhp, (dvoid **) srvhp, + (ub4) OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc() on srvhp\n"); + return OCI_ERROR; + } + + /* Allocate a authentication handle */ + if (OCIHandleAlloc((dvoid *) *envhp, (dvoid **) authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc() on authp\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + +/* ----------------------------------------------------------------- */ +/* Attach to server with a given mode. */ +/* ----------------------------------------------------------------- */ +sword attach_server(mode, srvhp, errhp, svchp) +ub4 mode; +OCIServer *srvhp; +OCIError *errhp; +OCISvcCtx *svchp; +{ + text *cstring = (text *)""; + + if (OCIServerAttach(srvhp, errhp, (text *) cstring, + (sb4) strlen((char *)cstring), (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIServerAttach()\n"); + return OCI_ERROR; + } + + /* Set the server handle in the service handle */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, (ub4) OCI_ATTR_SERVER, errhp)) + { + (void) printf("FAILED: OCIAttrSet() server attribute\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} +/* ----------------------------------------------------------------- */ +/* Logon to the database using given username, password & credentials*/ +/* ----------------------------------------------------------------- */ +sword log_on(authp, errhp, svchp, uid, pwd, credt, mode) +OCISession *authp; +OCIError *errhp; +OCISvcCtx *svchp; +text *uid; +text *pwd; +ub4 credt; +ub4 mode; +{ + /* Set attributes in the authentication handle */ + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) uid, (ub4) strlen((char *) uid), + (ub4) OCI_ATTR_USERNAME, errhp)) + { + (void) printf("FAILED: OCIAttrSet() userid\n"); + return OCI_ERROR; + } + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) pwd, (ub4) strlen((char *) pwd), + (ub4) OCI_ATTR_PASSWORD, errhp)) + { + (void) printf("FAILED: OCIAttrSet() passwd\n"); + return OCI_ERROR; + } + + (void) printf("Logging on as %s ....\n", uid); + + if (OCISessionBegin(svchp, errhp, authp, credt, mode)) + { + (void) printf("FAILED: OCIAttrSet() passwd\n"); + return OCI_ERROR; + } + + (void) printf("%s logged on.\n", uid); + + /* Set the authentication handle in the Service handle */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) authp, (ub4) 0, (ub4) OCI_ATTR_SESSION, errhp)) + { + (void) printf("FAILED: OCIAttrSet() session\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + +/*---------------------------------------------------------------------*/ +/* Allocate all required bind handles */ +/*---------------------------------------------------------------------*/ + +sword init_bind_handle(stmthp, bndhp, nbinds) +OCIStmt *stmthp; +OCIBind *bndhp[]; +int nbinds; +{ + int i; + /* + * This function init the specified number of bind handles + * from the given statement handle. + */ + for (i = 0; i < nbinds; i++) + bndhp[i] = (OCIBind *) 0; + + return OCI_SUCCESS; +} + +/* ----------------------------------------------------------------- */ +/* Print the returned raw data. */ +/* ----------------------------------------------------------------- */ +void print_raw(raw, rawlen) +ub1 *raw; +ub4 rawlen; +{ + ub4 i; + ub4 lim; + ub4 clen = 0; + + if (rawlen > 120) + { + ub4 llen = rawlen; + + while (llen > 120) + { + lim = clen + 120; + for(i = clen; i < lim; ++i) + (void) printf("%02.2x", (ub4) raw[i] & 0xFF); + + (void) printf("\n"); + llen -= 120; + clen += 120; + } + lim = clen + llen; + } + else + lim = rawlen; + + for(i = clen; i < lim; ++i) + (void) printf("%02.2x", (ub4) raw[i] & 0xFF); + + (void) printf("\n"); + + return; +} + +/* ----------------------------------------------------------------- */ +/* Free the specified handles */ +/* ----------------------------------------------------------------- */ +void free_handles(envhp, svchp, srvhp, errhp, authp, stmthp) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIServer *srvhp; +OCIError *errhp; +OCISession *authp; +OCIStmt *stmthp; +{ + (void) printf("Freeing handles ...\n"); + + if (srvhp) + (void) OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER); + if (svchp) + (void) OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX); + if (errhp) + (void) OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR); + if (authp) + (void) OCIHandleFree((dvoid *) authp, (ub4) OCI_HTYPE_SESSION); + if (stmthp) + (void) OCIHandleFree((dvoid *) stmthp, (ub4) OCI_HTYPE_STMT); + if (envhp) + (void) OCIHandleFree((dvoid *) envhp, (ub4) OCI_HTYPE_ENV); + + return; +} + +/* ----------------------------------------------------------------- */ +/* Print the error message */ +/* ----------------------------------------------------------------- */ +void report_error(errhp) +OCIError *errhp; +{ + text msgbuf[512]; + sb4 errcode = 0; + + (void) OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + (void) printf("ERROR CODE = %d\n", errcode); + (void) printf("%.*s\n", 512, msgbuf); + return; +} + +/*-------------------------------------------------------------------*/ +/* Logout and detach from the server */ +/*-------------------------------------------------------------------*/ +void logout_detach_server(svchp, srvhp, errhp, authp, userid) +OCISvcCtx *svchp; +OCIServer *srvhp; +OCIError *errhp; +OCISession *authp; +text *userid; +{ + if (OCISessionEnd(svchp, errhp, authp, (ub4) 0)) + { + (void) printf("FAILED: OCISessionEnd()\n"); + report_error(errhp); + } + + (void) printf("%s Logged off.\n", userid); + + if (OCIServerDetach(srvhp, errhp, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCISessionEnd()\n"); + report_error(errhp); + } + + (void) printf("Detached from server.\n"); + + return; +} + +/*---------------------------------------------------------------------*/ +/* Finish demo and clean up */ +/*---------------------------------------------------------------------*/ +sword finish_demo(loggedon, envhp, svchp, srvhp, errhp, authp, stmthp, userid) +boolean loggedon; +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIServer *srvhp; +OCIError *errhp; +OCISession *authp; +OCIStmt *stmthp; +text *userid; +{ + + if (loggedon) + logout_detach_server(svchp, srvhp, errhp, authp, userid); + + free_handles(envhp, svchp, srvhp, errhp, authp, stmthp); + + return OCI_SUCCESS; +} + +/*===================== END OF UTILITY FUNCTIONS ======================*/ + +/*========================= MAIN ======================================*/ +int main(argc, argv) +int argc; +char *argv[]; +{ + text *username = (text *)"scott"; + text *password = (text *)"tiger"; + + OCIEnv *envhp; + OCIServer *srvhp; + OCISvcCtx *svchp; + OCISession *authp; + OCIStmt *stmthp = (OCIStmt *) NULL; + OCIBind *bndhp[MAXBINDS]; + int i; + + + /* Initialize the Environment and allocate handles */ + if (init_handles(&envhp, &svchp, &errhp, &srvhp, &authp, (ub4)OCI_DEFAULT)) + { + (void) printf("FAILED: init_handles()\n"); + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); + } + + /* Attach to the database server */ + if (attach_server((ub4) OCI_DEFAULT, srvhp, errhp, svchp)) + { + (void) printf("FAILED: attach_server()\n"); + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); + } + + /* Logon to the server and begin a session */ + if (log_on(authp, errhp, svchp, username, password, + (ub4) OCI_CRED_RDBMS, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: log_on()\n"); + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); + } + logged_on = TRUE; + + /* Allocate a statement handle */ + if (OCIHandleAlloc((dvoid *)envhp, (dvoid **) &stmthp, + (ub4)OCI_HTYPE_STMT, (CONST size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: alloc statement handle\n"); + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); + } + + /* bind handles will be implicitly allocated in the bind calls */ + /* need to initialize them to null prior to first usage in bind calls */ + + for (i = 0; i < MAXBINDS; i++) + bndhp[i] = (OCIBind *) 0; + + /* Demonstrate INSERT with RETURNING clause */ + if (demo_insert(svchp, stmthp, bndhp, errhp)) + (void) printf("FAILED: demo_insert()\n"); + else + (void) printf("SUCCESS: demo_insert()\n"); + + /* Demonstrate UPDATE with RETURNING clause */ + if (demo_update(svchp, stmthp, bndhp, errhp)) + (void) printf("FAILED: demo_update()\n"); + else + (void) printf("SUCCESS: demo_update()\n"); + + /* Demonstrate DELETE with RETURNING clause */ + if (demo_delete(svchp, stmthp, bndhp, errhp)) + (void) printf("FAILED: demo_delete()\n"); + else + (void) printf("SUCCESS: demo_delete()\n"); + + /* clean up */ + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); +} + +/* =================== End Main =====================================*/ + +/* ===================== Local Functions ============================*/ +/* ----------------------------------------------------------------- */ +/* bind all the columns of TAB1 by positions. */ +/* ----------------------------------------------------------------- */ +static sword bind_pos(OCIStmt *stmthp, OCIBind *bndhp[], OCIError *errhp) +{ + + if (OCIBindByPos(stmthp, &bndhp[0], errhp, (ub4) 1, + (dvoid *) &in1[0], (sb4) sizeof(in1[0]), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) + || OCIBindByPos(stmthp, &bndhp[1], errhp, (ub4) 2, + (dvoid *) in2[0], (sb4) sizeof(in2[0]), SQLT_AFC, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) + || OCIBindByPos(stmthp, &bndhp[2], errhp, (ub4) 3, + (dvoid *) in3[0], (sb4) sizeof(in3[0]), SQLT_CHR, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) + || OCIBindByPos(stmthp, &bndhp[3], errhp, (ub4) 4, + (dvoid *) &in4[0], (sb4) sizeof(in4[0]), SQLT_FLT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) + || OCIBindByPos(stmthp, &bndhp[4], errhp, (ub4) 5, + (dvoid *) &in5[0], (sb4) sizeof(in5[0]), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) + || OCIBindByPos(stmthp, &bndhp[5], errhp, (ub4) 6, + (dvoid *) &in6[0], (sb4) sizeof(in6[0]), SQLT_FLT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) + || OCIBindByPos(stmthp, &bndhp[6], errhp, (ub4) 7, + (dvoid *) &in7[0], (sb4) sizeof(in7[0]), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) + || OCIBindByPos(stmthp, &bndhp[7], errhp, (ub4) 8, + (dvoid *) &in8[0], (sb4) sizeof(in8[0]), SQLT_FLT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) + || OCIBindByPos(stmthp, &bndhp[8], errhp, (ub4) 9, + (dvoid *) in9[0], (sb4) sizeof(in9[0]), SQLT_DAT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) + || OCIBindByPos(stmthp, &bndhp[9], errhp, (ub4) 10, + (dvoid *) in10[0], (sb4) sizeof(in10[0]), SQLT_BIN, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIBindByPos()\n"); + report_error(errhp); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/* ----------------------------------------------------------------- */ +/* bind all the columns of TAB1 by name. */ +/* ----------------------------------------------------------------- */ +static sword bind_name(OCIStmt *stmthp, OCIBind *bndhp[], OCIError *errhp) +{ + + if (OCIBindByName(stmthp, &bndhp[10], errhp, + (text *) ":out1", (sb4) strlen((char *) ":out1"), + (dvoid *) 0, (sb4) sizeof(int), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC) + || OCIBindByName(stmthp, &bndhp[11], errhp, + (text *) ":out2", (sb4) strlen((char *) ":out2"), + (dvoid *) 0, (sb4) MAXCOLLEN, SQLT_AFC, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC) + || OCIBindByName(stmthp, &bndhp[12], errhp, + (text *) ":out3", (sb4) strlen((char *) ":out3"), + (dvoid *) 0, (sb4) MAXCOLLEN, SQLT_CHR, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC) + || OCIBindByName(stmthp, &bndhp[13], errhp, + (text *) ":out4", (sb4) strlen((char *) ":out4"), + (dvoid *) 0, (sb4) sizeof(float), SQLT_FLT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC) + || OCIBindByName(stmthp, &bndhp[14], errhp, + (text *) ":out5", (sb4) strlen((char *) ":out5"), + (dvoid *) 0, (sb4) sizeof(int), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC) + || OCIBindByName(stmthp, &bndhp[15], errhp, + (text *) ":out6", (sb4) strlen((char *) ":out6"), + (dvoid *) 0, (sb4) sizeof(float), SQLT_FLT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC) + || OCIBindByName(stmthp, &bndhp[16], errhp, + (text *) ":out7", (sb4) strlen((char *) ":out7"), + (dvoid *) 0, (sb4) sizeof(int), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC) + || OCIBindByName(stmthp, &bndhp[17], errhp, + (text *) ":out8", (sb4) strlen((char *) ":out8"), + (dvoid *) 0, (sb4) sizeof(float), SQLT_FLT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC) + || OCIBindByName(stmthp, &bndhp[18], errhp, + (text *) ":out9", (sb4) strlen((char *) ":out9"), + (dvoid *) 0, (sb4) DATBUFLEN, SQLT_DAT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC) + || OCIBindByName(stmthp, &bndhp[19], errhp, + (text *) ":out10", (sb4) strlen((char *) ":out10"), + (dvoid *) 0, (sb4) MAXCOLLEN, SQLT_BIN, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC)) + { + (void) printf("FAILED: OCIBindByName()\n"); + report_error(errhp); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/* ----------------------------------------------------------------- */ +/* bind array structs for TAB1 columns. */ +/* ----------------------------------------------------------------- */ +static sword bind_array(OCIBind *bndhp[], OCIError *errhp) +{ + if (OCIBindArrayOfStruct(bndhp[0], errhp, s1, indsk[0], rlsk[0], rcsk[0]) + || OCIBindArrayOfStruct(bndhp[1], errhp, s2, indsk[1], rlsk[1], rcsk[1]) + || OCIBindArrayOfStruct(bndhp[2], errhp, s3, indsk[2], rlsk[2], rcsk[2]) + || OCIBindArrayOfStruct(bndhp[3], errhp, s4, indsk[3], rlsk[3], rcsk[3]) + || OCIBindArrayOfStruct(bndhp[4], errhp, s5, indsk[4], rlsk[4], rcsk[4]) + || OCIBindArrayOfStruct(bndhp[5], errhp, s6, indsk[5], rlsk[5], rcsk[5]) + || OCIBindArrayOfStruct(bndhp[6], errhp, s7, indsk[6], rlsk[6], rcsk[6]) + || OCIBindArrayOfStruct(bndhp[7], errhp, s8, indsk[7], rlsk[7], rcsk[7]) + || OCIBindArrayOfStruct(bndhp[8], errhp, s9, indsk[8], rlsk[8], rcsk[8]) + || OCIBindArrayOfStruct(bndhp[9], errhp, s10, indsk[9], rlsk[9], rcsk[9])) + { + (void) printf("FAILED: OCIBindArrayOfStruct()\n"); + report_error(errhp); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/* ----------------------------------------------------------------- */ +/* bind dynamic for returning TAB1 columns. */ +/* ----------------------------------------------------------------- */ +static sword bind_dynamic(OCIBind *bndhp[], OCIError *errhp) +{ + /* + * Note here that both IN & OUT BIND callback functions have to be + * provided. However, since the bind variables in the RETURNING + * clause are pure OUT Binds the IN callback fuctions (cbf_no_data) + * is essentially a "do-nothing" function. + * + * Also note here that although in this demonstration the IN and OUT + * callback functions are same, in practice you can have a different + * callback function for each bind handle. + */ + + ub4 i; + + for (i = 0; i < MAXCOLS; i++) + pos[i] = i; + + if (OCIBindDynamic(bndhp[10], errhp, (dvoid *) &pos[0], cbf_no_data, + (dvoid *) &pos[0], cbf_get_data) + || OCIBindDynamic(bndhp[11], errhp, (dvoid *) &pos[1], cbf_no_data, + (dvoid *) &pos[1], cbf_get_data) + || OCIBindDynamic(bndhp[12], errhp, (dvoid *) &pos[2], cbf_no_data, + (dvoid *) &pos[2], cbf_get_data) + || OCIBindDynamic(bndhp[13], errhp, (dvoid *) &pos[3], cbf_no_data, + (dvoid *) &pos[3], cbf_get_data) + || OCIBindDynamic(bndhp[14], errhp, (dvoid *) &pos[4], cbf_no_data, + (dvoid *) &pos[4], cbf_get_data) + || OCIBindDynamic(bndhp[15], errhp, (dvoid *) &pos[5], cbf_no_data, + (dvoid *) &pos[5], cbf_get_data) + || OCIBindDynamic(bndhp[16], errhp, (dvoid *) &pos[6], cbf_no_data, + (dvoid *) &pos[6], cbf_get_data) + || OCIBindDynamic(bndhp[17], errhp, (dvoid *) &pos[7], cbf_no_data, + (dvoid *) &pos[7], cbf_get_data) + || OCIBindDynamic(bndhp[18], errhp, (dvoid *) &pos[8], cbf_no_data, + (dvoid *) &pos[8], cbf_get_data) + || OCIBindDynamic(bndhp[19], errhp, (dvoid *) &pos[9], cbf_no_data, + (dvoid *) &pos[9], cbf_get_data)) + { + (void) printf("FAILED: OCIBindDynamic()\n"); + report_error(errhp); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + + +/* ----------------------------------------------------------------- */ +/* bind input variables. */ +/* ----------------------------------------------------------------- */ +static sword bind_input(OCIStmt *stmthp, OCIBind *bndhp[], OCIError *errhp) +{ + /* bind the input data by positions */ + if (bind_pos(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* bind input array attributes*/ + return (bind_array(bndhp, errhp)); +} + + + +/* ----------------------------------------------------------------- */ +/* bind output variables. */ +/* ----------------------------------------------------------------- */ +static sword bind_output(OCIStmt *stmthp, OCIBind *bndhp[], OCIError *errhp) +{ + + /* bind the returning bind buffers by names */ + if (bind_name(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* bind the returning bind buffers dynamically */ + return (bind_dynamic(bndhp, errhp)); +} + + +/* ----------------------------------------------------------------- */ +/* bind row indicator variables. */ +/* ----------------------------------------------------------------- */ +static sword bind_low_high(OCIStmt *stmthp, OCIBind *bndhp[], OCIError *errhp) +{ + if (OCIBindByName(stmthp, &bndhp[23], errhp, + (text *) ":low", (sb4) strlen((char *) ":low"), + (dvoid *) &lowc1[0], (sb4) sizeof(lowc1[0]), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) + || OCIBindByName(stmthp, &bndhp[24], errhp, + (text *) ":high", (sb4) strlen((char *) ":high"), + (dvoid *) &highc1[0], (sb4) sizeof(highc1[0]), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIBindByName()\n"); + report_error(errhp); + return OCI_ERROR; + } + + if (OCIBindArrayOfStruct(bndhp[23], errhp, s1, indsk[0], rlsk[0], rcsk[0]) + || OCIBindArrayOfStruct(bndhp[24], errhp, s1, indsk[0], rlsk[0], rcsk[0])) + { + (void) printf("FAILED: OCIBindArrayOfStruct()\n"); + report_error(errhp); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/* ----------------------------------------------------------------- */ +/* Demontrate INSERT with RETURNING clause. */ +/* ----------------------------------------------------------------- */ +static sword demo_insert(OCISvcCtx *svchp, OCIStmt *stmthp, + OCIBind *bndhp[], OCIError *errhp) +{ + int i, j; + + /* + * This function inserts values for 10 columns in table TAB1 and + * uses the RETURN clause to get back the inserted column values. + * It inserts MAXITER (10) such rows. Thus it expects MAXITER values + * for each column to be returned. + */ + /* The Insert Statement with RETURNING clause */ + text *sqlstmt = (text *) + "INSERT INTO TAB1 VALUES (:1, :2, :3, :4, :5, :6, :7, :8, :9, :10) \ + RETURNING C1, C2, C3, C4, C5, C6, C7, C8, C9, C10 \ + INTO :out1, :out2, :out3, :out4, :out5, :out6, \ + :out7, :out8, :out9, :out10"; + + /* Prepare the statement */ + if (OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4)strlen((char *)sqlstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() insert\n"); + report_error(errhp); + return OCI_ERROR; + } + + + /* Initialise the buffers for update */ + for (i = 0; i < MAXITER; i++) + { + in1[i] = i + 1; + memset((void *)in2[i], (int) 'A'+i%26, (size_t) 40); + memset((void *)in3[i], (int) 'a'+i%26, (size_t) 40); + in4[i] = 400.555 + (float) i; + in5[i] = 500 + i; + in6[i] = 600.250 + (float) i; + in7[i] = 700 + i; + in8[i] = 800.350 + (float) i; + in9[i][0] = 119; + in9[i][1] = 185 + (ub1)i%10; + in9[i][2] = (ub1)i%12 + 1; + in9[i][3] = (ub1)i%25 + 1; + in9[i][4] = 0; + in9[i][5] = 0; + in9[i][6] = 0; + for (j = 0; j < 40; j++) + in10[i][j] = (ub1) (i%0x10); + + rowsret[i] = 0; + } + + /* Bind all the input buffers to place holders (:1, :2. :3, etc ) */ + if (bind_input(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* Bind all the output buffers to place holders (:out1, :out2 etc */ + if (bind_output(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* Execute the Insert statement */ + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) MAXITER, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() insert\n"); + report_error(errhp); + return OCI_ERROR; + } + + /* Commit the changes */ + (void) OCITransCommit(svchp, errhp, (ub4) 0); + + /* Print out the values in the return rows */ + (void) printf("\n\n DEMONSTRATING INSERT....RETURNING \n"); + (void) print_return_data((int)MAXITER); + + return OCI_SUCCESS; +} + + + +/* ----------------------------------------------------------------- */ +/* Demonstrate UPDATE with RETURNING clause. */ +/* ----------------------------------------------------------------- */ +static sword demo_update(OCISvcCtx *svchp, OCIStmt *stmthp, + OCIBind *bndhp[], OCIError *errhp) +{ + int i, j; + int range_size = 3; /* iterations */ + + + /* + * This function updates columns in table TAB1, for certain rows + * depending on the values of the :low and :high values in + * in the WHERE clause. It executes this statement 3 times, (3 iterations) + * each time with a different set of values for :low and :high + * Thus for each iteration, multiple rows are returned depending + * on the number of rows that matched the WHERE clause. + * + * The rows it updates here are the rows that were inserted by the + * cdemodr1.sql script. + */ + + /* The Update Statement with RETURNING clause */ + text *sqlstmt = (text *) + "UPDATE TAB1 SET C1 = C1 + :1, C2 = :2, C3 = :3, \ + C4 = C4 + :4, C5 = C5 + :5, C6 = C6 + :6, \ + C7 = C7 + :7, C8 = C8 + :8, C9 = :9, C10 = :10 \ + WHERE C1 >= :low AND C1 <= :high \ + RETURNING C1, C2, C3, C4, C5, C6, C7, C8, C9, C10 \ + INTO :out1, :out2, :out3, :out4, :out5, :out6, \ + :out7, :out8, :out9, :out10"; + + /* Prepare the statement */ + if (OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4)strlen((char *)sqlstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() update\n"); + report_error(errhp); + return OCI_ERROR; + } + + /* Initialise the buffers for insertion */ + for (i = 0; i < MAXITER; i++) + { + in1[i] = 300 + i; + memset((void *)in2[i], (int) 'a'+i%26, (size_t) 40); + memset((void *)in3[i], (int) 'A'+i%26, (size_t) 40); + in4[i] = 400.555 + (float)i; + in5[i] = 500 + i; + in6[i] = 600.280 + (float)i; + in7[i] = 700 + i; + in8[i] = 800.620 + (float)i; + in9[i][0] = 119; + in9[i][1] = 185 - (ub1)i%10; + in9[i][2] = (ub1)i%12 + 1; + in9[i][3] = (ub1)i%25 + 1; + in9[i][4] = 0; + in9[i][5] = 0; + in9[i][6] = 0; + for (j = 0; j < 40; j++) + in10[i][j] = (ub1) (i%0x08); + + rowsret[i] =0; + } + + /* Bind all the input buffers to place holders (:1, :2. :3, etc ) */ + if (bind_input(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* Bind all the output buffers to place holders (:out1, :out2 etc */ + if (bind_output(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* bind row indicator low, high */ + if (bind_low_high(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* update rows + between 101 and 103; -- expecting 3 rows returned (update 3 rows) + between 105 and 106; -- expecting 2 rows returned (update 2 rows) + between 109 and 113; -- expecting 5 rows returned (update 5 rows) + */ + lowc1[0] = 101; + highc1[0] = 103; + + lowc1[1] = 105; + highc1[1] = 106; + + lowc1[2] = 109; + highc1[2] = 113; + + (void) printf("\n\n DEMONSTRATING UPDATE....RETURNING \n"); + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) range_size, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() update\n"); + report_error(errhp); + return OCI_ERROR; + } + + /* Commit the changes */ + (void) OCITransCommit(svchp, errhp, (ub4) 0); + + /* Print out the values in the return rows */ + (void) print_return_data(range_size); + + return OCI_SUCCESS; +} + + + +/* ----------------------------------------------------------------- */ +/* Demonstrate DELETE with RETURNING clause. */ +/* ----------------------------------------------------------------- */ +static sword demo_delete(OCISvcCtx *svchp, OCIStmt *stmthp, + OCIBind *bndhp[], OCIError *errhp) +{ + int i, range_size = 3; /* iterations */ + sword retval; + + /* + * This function deletes certain rows from table TAB1 + * depending on the values of the :low and :high values in + * the WHERE clause. It executes this statement 3 times, (3 iterations) + * each time with a different set of values for :low and :high + * Thus for each iteration, multiples rows are returned depending + * on the number of rows that matched the WHERE clause. + * + * The rows it deletes here are the rows that were inserted by the + * cdemodr1.sql script. + */ + + /* The Delete Statement with RETURNING clause */ + text *sqlstmt = (text *) + "DELETE FROM TAB1 WHERE C1 >= :low AND C1 <= :high \ + RETURNING C1, C2, C3, C4, C5, C6, C7, C8, C9, C10 \ + INTO :out1, :out2, :out3, :out4, :out5, :out6, \ + :out7, :out8, :out9, :out10"; + + /* Prepare the statement */ + if (OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4)strlen((char *)sqlstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() delete\n"); + report_error(errhp); + return OCI_ERROR; + } + + /* Bind all the output buffers to place holders (:out1, :out2 etc */ + if (bind_output(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* bind row indicator low, high */ + if (bind_low_high(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* delete rows + between 201 and 203; -- expecting 3 rows returned (3 rows deleted) + between 205 and 209; -- expecting 5 rows returned (2 rows deleted) + between 211 and 213; -- expecting 3 rows returned (5 rows deleted) + */ + lowc1[0] = 201; + highc1[0] = 203; + + lowc1[1] = 205; + highc1[1] = 209; + + lowc1[2] = 211; + highc1[2] = 213; + + + for (i=0; i + + PRIVATE FUNCTION(S) + + + EXAMPLES + + NOTES + + + MODIFIED (MM/DD/YY) + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 10/01/98 - include stdlib.h - bug 714175 + svedala 09/09/98 - lines longer than 79 chars reformatted - bug 722491 + echen 07/30/97 - fix bug 516406 + azhao 05/30/97 - Creation + +*/ + +/*------------------------------------------------------------------------ + * Include Files + */ + +#include +#include +#include +#include +/* +#include +*/ + +/*------------------------------------------------------------------------ + * Define Constants + */ + +#define MAXBINDS 25 +#define MAXROWS 5 /* max no of rows returned per iter */ +#define MAXCOLS 10 +#define MAXITER 10 /* max no of iters in execute */ +#define MAXCOLLEN 40 /* if changed, update cdemodr1.sql */ +#define DATBUFLEN 7 + +int main(/*_ int argc, char *argv[] _*/); +static sword init_handles(/*_ OCIEnv **envhp, OCISvcCtx **svchp, + OCIError **errhp, OCIServer **svrhp, + OCISession **authp, ub4 mode _*/); + +static sword attach_server(/*_ ub4 mode, OCIServer *srvhp, + OCIError *errhp, OCISvcCtx *svchp _*/); +static sword log_on(/*_ OCISession *authp, OCIError *errhp, OCISvcCtx *svchp, + text *uid, text *pwd, ub4 credt, ub4 mode _*/); +static sword init_bind_handle(/*_ OCIStmt *stmthp, OCIBind *bndhp[], + int nbinds _*/); +static void print_raw(/*_ ub1 *raw, ub4 rawlen _*/); + +static void free_handles(/*_ OCIEnv *envhp, OCISvcCtx *svchp, OCIServer *srvhp, + OCIError *errhp, OCISession *authp, OCIStmt *stmthp _*/); +void report_error(/*_ OCIError *errhp _*/); +void logout_detach_server(/*_ OCISvcCtx *svchp, OCIServer *srvhp, + OCIError *errhp, OCISession *authp, + text *userid _*/); +sword finish_demo(/*_ boolean loggedon, OCIEnv *envhp, OCISvcCtx *svchp, + OCIServer *srvhp, OCIError *errhp, OCISession *authp, + OCIStmt *stmthp, text *userid _*/); +static sword demo_insert(/*_ OCISvcCtx *svchp, OCIStmt *stmthp, + OCIBind *bndhp[], OCIError *errhp _*/); +static sword demo_update(/*_ OCISvcCtx *svchp, OCIStmt *stmthp, + OCIBind *bndhp[], OCIError *errhp _*/); +static sword demo_delete(/*_ OCISvcCtx *svchp, OCIStmt *stmthp, + OCIBind *bndhp[], OCIError *errhp _*/); +static sword bind_name(/*_ OCIStmt *stmthp, OCIBind *bndhp[], + OCIError *errhp _*/); +static sword bind_pos(/*_ OCIStmt *stmthp, OCIBind *bndhp[], + OCIError *errhp _*/); +static sword bind_input(/*_ OCIStmt *stmthp, OCIBind *bndhp[], + OCIError *errhp _*/); +static sword bind_output(/*_ OCIStmt *stmthp, OCIBind *bndhp[], + OCIError *errhp _*/); +static sword bind_array(/*_ OCIBind *bndhp[], OCIError *errhp _*/); +static sword bind_dynamic(/*_ OCIBind *bndhp[], OCIError *errhp _*/); +static sb4 cbf_no_data(/*_ dvoid *ctxp, OCIBind *bindp, ub4 iter, ub4 index, + dvoid **bufpp, ub4 *alenpp, ub1 *piecep, dvoid **indpp _*/); +static sb4 cbf_get_data(/*_ dvoid *ctxp, OCIBind *bindp, ub4 iter, ub4 index, + dvoid **bufpp, ub4 **alenpp, ub1 *piecep, + dvoid **indpp, ub2 **rcodepp _*/); +static sword alloc_buffer(/*_ ub4 pos, ub4 iter, ub4 rows _*/); +static sword print_return_data(/*_ int iter _*/); + diff --git a/cdemodr1.sql b/cdemodr1.sql new file mode 100644 index 0000000..c267f58 --- /dev/null +++ b/cdemodr1.sql @@ -0,0 +1,132 @@ +rem +rem $Header: cdemodr1.sql 14-jul-99.13:49:48 mjaeger Exp $ +rem +rem cdemodr1.sql +rem +rem Copyright (c) 1997, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem cdemodr1.sql - +rem +rem DESCRIPTION +rem +rem +rem NOTES +rem +rem +rem MODIFIED (MM/DD/YY) +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem azhao 05/30/97 - Created +rem + +connect scott/tiger +drop table tab1; + +create table tab1 (c1 integer, c2 char(40), c3 varchar2(40), c4 float, + c5 decimal, c6 decimal(8,3), c7 numeric, c8 numeric(7,2), + C9 date, C10 raw(40)); + +rem +rem Insert some data for UPDATE +rem + +insert into tab1 values (101, 'To be updated, row 101', 'varchar2, row 101', + 201.520, 301, 401.450, 501, 601.550, '01-JAN-85', + '123456789012345678901234567890'); +insert into tab1 values (102, 'To be updated, row 102', 'varchar2, row 102', + 202.520, 302, 402.450, 502, 602.550, '02-FEB-86', + '234567890123456789012345678901'); +insert into tab1 values (103, 'To be updated, row 103', 'varchar2, row 103', + 203.520, 303, 403.450, 503, 603.550, '03-MAR-87', + '345678901234567890123456789012'); +insert into tab1 values (104, 'To be updated, row 104', 'varchar2, row 104', + 204.520, 304, 404.450, 504, 604.550, '04-APR-88', + '456789012345678901234567890123'); +insert into tab1 values (105, 'To be updated, row 105', 'varchar2, row 105', + 205.520, 305, 405.450, 505, 605.550, '05-MAY-89', + '567890123456789012345678901234'); +insert into tab1 values (106, 'To be updated, row 106', 'varchar2, row 106', + 206.520, 306, 406.450, 506, 606.550, '06-JUN-90', + '678901234567890123456789012345'); +insert into tab1 values (107, 'To be updated, row 107', 'varchar2, row 107', + 207.520, 307, 407.450, 507, 607.550, '07-JUL-91', + '789012345678901234567890123456'); +insert into tab1 values (108, 'To be updated, row 108', 'varchar2, row 108', + 208.520, 308, 408.450, 508, 608.550, '08-AUG-92', + '890123456789012345678901234567'); +insert into tab1 values (109, 'To be updated, row 109', 'varchar2, row 109', + 209.520, 309, 409.450, 509, 609.550, '09-SEP-93', + '901234567890123456789012345678'); +insert into tab1 values (110, 'To be updated, row 110', 'varchar2, row 110', + 210.520, 310, 410.450, 510, 610.550, '10-OCT-94', + '012345678901234567890123456789'); +insert into tab1 values (111, 'To be updated, row 111', 'varchar2, row 111', + 211.520, 311, 411.450, 511, 611.550, '11-NOV-95', + '123456789012345678901234567890'); +insert into tab1 values (112, 'To be updated, row 112', 'varchar2, row 112', + 212.520, 312, 412.450, 512, 612.550, '12-DEC-96', + '234567890123456789012345678901'); +insert into tab1 values (113, 'To be updated, row 113', 'varchar2, row 113', + 213.520, 313, 413.450, 513, 613.550, '13-JAN-97', + '345678901234567890123456789012'); +insert into tab1 values (114, 'To be updated, row 114', 'varchar2, row 114', + 214.520, 314, 414.450, 514, 614.550, '14-FEB-98', + '456789012345678901234567890123'); +insert into tab1 values (115, 'To be updated, row 115', 'varchar2, row 115', + 215.520, 315, 415.450, 515, 615.550, '15-MAR-99', + '567890123456789012345678901234'); + +rem +rem Insert some data for DELETE +rem + +insert into tab1 values (201, null, 'varchar2, row 201', + 2001.520, 3001, 4001.4500, 5001, 6001.550, '01-JAN-95', + '123456789012345678901234567890'); +insert into tab1 values (202, 'To be deleted, row 202', null, + 2002.520, 3002, 4002.4500, 5002, 6002.550, '02-FEB-94', + '234567890123456789012345678901'); +insert into tab1 values (203, 'To be deleted, row 203', 'varchar2, row 203', + null, 3003, 4003.4500, 5003, 6003.550, '03-MAR-93', + '345678901234567890123456789012'); +insert into tab1 values (204, 'To be deleted, row 204', 'varchar2, row 204', + 2004.520, 3004, 4004.4500, 5004, 6004.550, '04-APR-92', + '456789012345678901234567890123'); +insert into tab1 values (205, 'To be deleted, row 205', 'varchar2, row 205', + 2005.520, null, 4005.4500, 5005, 6005.550, '05-MAY-91', + '567890123456789012345678901234'); +insert into tab1 values (206, 'To be deleted, row 206', 'varchar2, row 206', + 2006.520, 3006, null, 5006, 6006.550, '06-JUN-90', + '678901234567890123456789012345'); +insert into tab1 values (207, 'To be deleted, row 207', 'varchar2, row 207', + 2007.520, 3007, 4007.4500, null, 6007.550, '07-JUL-89', + '789012345678901234567890123456'); +insert into tab1 values (208, 'To be deleted, row 208', 'varchar2, row 208', + 2008.520, 3008, 4008.4500, 5008, null, '08-AUG-88', + '890123456789012345678901234567'); +insert into tab1 values (209, 'To be deleted, row 209', 'varchar2, row 209', + 2009.520, 3009, 4009.4500, 5009, 6009.550, '09-SEP-87', + '901234567890123456789012345678'); +insert into tab1 values (210, 'To be deleted, row 210', 'varchar2, row 210', + 2010.520, 3010, 4010.4500, 5010, 6010.550, '10-OCT-86', + '012345678901234567890123456789'); +insert into tab1 values (211, 'To be deleted, row 211', 'varchar2, row 211', + 2011.520, 3011, 4011.4500, 5011, 6011.550, null, + '123456789012345678901234567890'); +insert into tab1 values (212, 'To be deleted, row 212', 'varchar2, row 212', + 2012.520, 3012, 4012.4500, 5012, 6012.550, '12-DEC-84', + null); +insert into tab1 values (213, 'To be deleted, row 213', 'varchar2, row 213', + 2013.520, 3013, 4013.4500, 5013, 6013.550, '13-JAN-83', + '345678901234567890123456789012'); +insert into tab1 values (214, 'To be deleted, row 214', 'varchar2, row 214', + 2014.520, 3014, 4014.4500, 5014, 6014.550, '14-FEB-82', + '456789012345678901234567890123'); +insert into tab1 values (215, 'To be deleted, row 215', 'varchar2, row 215', + 2015.520, 3015, 4015.4500, 5015, 6015.550, '15-MAR-81', + '567890123456789012345678901234'); + +commit; + +quit + diff --git a/cdemodr2.c b/cdemodr2.c new file mode 100644 index 0000000..9425436 --- /dev/null +++ b/cdemodr2.c @@ -0,0 +1,1283 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemodr2.c 10-oct-2006.14:39:58 azhao Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1997, 2006, Oracle. All rights reserved. +*/ + +/* + + NAME + cdemodr2.c - DML Returning LOBs. + + DESCRIPTION + Demonstrate INSERT/UPDATE/DELETE statements RETURNING LOBS + + demo table: TAB2 (C1 INTEGER, C2 BLOB, C3 CLOB) + + Before running cdemodr2, run cdemodr2.sql to create and populate + TAB2 with some initial data. + + demo_insert() -- inserts 10 rows (with C1 = 1, 2, 3, ..., 10) + in null BLOBs, CLOBs for C2, C3, respectively. + The returned lob locators corresponding to these + BLOBs, CLOBs are then used for lob read/write. + + select_locator() -- shows that the locators returned from the INSERT + statement in demo_insert() are valid. + + demo_update() -- updates the rows within 3 ranges of C1. The + lob locators used for updating C2, C3 have been + returned from demo_insert(), used by select_locator() + to select the BLOBs, CLOBs from a different range of C1. + + demo_delete() -- deletes the rows within 3 ranges of C1. The returned + lob locators can be read but not written because those + rows associated with the returned locators have be deleted. + + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + + + NOTES + + + MODIFIED (MM/DD/YY) + azhao 10/10/06 - case-senstive password change + svedala 10/18/99 - + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + azhao 08/19/97 - replace OCIStmtBindByName with OCIBindByName + azhao 06/03/97 - Creation + +*/ + +/*------------------------Inclusions-------------------------------*/ + +#include + +static boolean logged_on = FALSE; + +/* TAB2 columns */ +static int in1[MAXITER]; /* for INTEGER */ +static OCILobLocator *in2[MAXITER]; /* for BLOB */ +static OCILobLocator *in3[MAXITER]; /* for CLOB */ + +/* output buffers */ +static int *p1[MAXITER]; /* for INTEGER */ +static OCILobLocator **p2[MAXITER]; /* for BLOB */ +static OCILobLocator **p3[MAXITER]; /* for CLOB */ + +static short *ind[MAXCOLS][MAXITER]; /* indicators */ +static ub2 *rc[MAXCOLS][MAXITER]; /* return codes */ +static ub4 *rl[MAXCOLS][MAXITER]; /* return lengths */ + +/* skip values for binding TAB2 */ +static ub4 s1 = (ub4) sizeof(in1[0]); +static ub4 s2 = (ub4) sizeof(in2[0]); +static ub4 s3 = (ub4) sizeof(in3[0]); + +/* Rows returned in each iteration */ +static ub2 rowsret[MAXITER]; + +/* indicator skips */ +static ub4 indsk[MAXCOLS] = { 0, 0, 0 }; +/* return length skips */ +static ub4 rlsk[MAXCOLS] = { 0, 0, 0 }; +/* return code skips */ +static ub4 rcsk[MAXCOLS] = { 0, 0, 0 }; + +static int lowc1[MAXITER], highc1[MAXITER]; + +static ub4 pos[MAXCOLS]; + +static OCIEnv *envhp; +static OCIError *errhp; + +static sb2 null_ind = -1; + + +/*------------------------end of Global variables--------------------*/ + + +/*========================== UTILITY FUNCTIONS ======================*/ +/* + * These functions are generic functions that can be used in any + * OCI program. + */ +/* ----------------------------------------------------------------- */ +/* Initialize environment, allocate handles */ +/* ----------------------------------------------------------------- */ +sword init_handles(envhp, svchp, errhp, srvhp, authp, init_mode) +OCIEnv **envhp; +OCISvcCtx **svchp; +OCIError **errhp; +OCIServer **srvhp; +OCISession **authp; +ub4 init_mode; +{ + (void) printf("Environment setup ....\n"); + + /* Initialize the OCI Process */ + if (OCIInitialize(init_mode, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 )) + { + (void) printf("FAILED: OCIInitialize()\n"); + return OCI_ERROR; + } + + /* Inititialize the OCI Environment */ + if (OCIEnvInit((OCIEnv **) envhp, (ub4) OCI_DEFAULT, + (size_t) 0, (dvoid **) 0 )) + { + (void) printf("FAILED: OCIEnvInit()\n"); + return OCI_ERROR; + } + + /* Allocate a service handle */ + if (OCIHandleAlloc((dvoid *) *envhp, (dvoid **) svchp, + (ub4) OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc() on svchp\n"); + return OCI_ERROR; + } + + /* Allocate an error handle */ + if (OCIHandleAlloc((dvoid *) *envhp, (dvoid **) errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc() on errhp\n"); + return OCI_ERROR; + } + + /* Allocate a server handle */ + if (OCIHandleAlloc((dvoid *) *envhp, (dvoid **) srvhp, + (ub4) OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc() on srvhp\n"); + return OCI_ERROR; + } + + /* Allocate a authentication handle */ + if (OCIHandleAlloc((dvoid *) *envhp, (dvoid **) authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc() on authp\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + +/* ----------------------------------------------------------------- */ +/* Attach to server with a given mode. */ +/* ----------------------------------------------------------------- */ +sword attach_server(mode, srvhp, errhp, svchp) +ub4 mode; +OCIServer *srvhp; +OCIError *errhp; +OCISvcCtx *svchp; +{ + text *cstring = (text *)""; + + if (OCIServerAttach(srvhp, errhp, (text *) cstring, + (sb4) strlen((char *)cstring), (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIServerAttach()\n"); + return OCI_ERROR; + } + + /* Set the server handle in the service handle */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, (ub4) OCI_ATTR_SERVER, errhp)) + { + (void) printf("FAILED: OCIAttrSet() server attribute\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} +/* ----------------------------------------------------------------- */ +/* Logon to the database using given username, password & credentials*/ +/* ----------------------------------------------------------------- */ +sword log_on(authp, errhp, svchp, uid, pwd, credt, mode) +OCISession *authp; +OCIError *errhp; +OCISvcCtx *svchp; +text *uid; +text *pwd; +ub4 credt; +ub4 mode; +{ + /* Set attributes in the authentication handle */ + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) uid, (ub4) strlen((char *) uid), + (ub4) OCI_ATTR_USERNAME, errhp)) + { + (void) printf("FAILED: OCIAttrSet() userid\n"); + return OCI_ERROR; + } + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) pwd, (ub4) strlen((char *) pwd), + (ub4) OCI_ATTR_PASSWORD, errhp)) + { + (void) printf("FAILED: OCIAttrSet() passwd\n"); + return OCI_ERROR; + } + + (void) printf("Logging on as %s ....\n", uid); + + if (OCISessionBegin(svchp, errhp, authp, credt, mode)) + { + (void) printf("FAILED: OCIAttrSet() passwd\n"); + return OCI_ERROR; + } + + (void) printf("%s logged on.\n", uid); + + /* Set the authentication handle in the Service handle */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) authp, (ub4) 0, (ub4) OCI_ATTR_SESSION, errhp)) + { + (void) printf("FAILED: OCIAttrSet() session\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + +/*---------------------------------------------------------------------*/ +/* Allocate all required bind handles */ +/*---------------------------------------------------------------------*/ + +sword alloc_bind_handle(stmthp, bndhp, nbinds) +OCIStmt *stmthp; +OCIBind *bndhp[]; +int nbinds; +{ + int i; + /* + * This function allocates the specified number of bind handles + * from the given statement handle. + */ + for (i = 0; i < nbinds; i++) + if (OCIHandleAlloc((dvoid *)stmthp, (dvoid **)&bndhp[i], + (ub4)OCI_HTYPE_BIND, (CONST size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc() bind handle\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + +/* ----------------------------------------------------------------- */ +/* Print the returned raw data. */ +/* ----------------------------------------------------------------- */ +void print_raw(raw, rawlen) +ub1 *raw; +ub4 rawlen; +{ + ub4 i; + ub4 lim; + ub4 clen = 0; + + if (rawlen > 120) + { + ub4 llen = rawlen; + + while (llen > 120) + { + lim = clen + 120; + for(i = clen; i < lim; ++i) + (void) printf("%02.2x", (ub4) raw[i] & 0xFF); + + (void) printf("\n"); + llen -= 120; + clen += 120; + } + lim = clen + llen; + } + else + lim = rawlen; + + for(i = clen; i < lim; ++i) + (void) printf("%02.2x", (ub4) raw[i] & 0xFF); + + (void) printf("\n"); + + return; +} + +/* ----------------------------------------------------------------- */ +/* Free the specified handles */ +/* ----------------------------------------------------------------- */ +void free_handles(envhp, svchp, srvhp, errhp, authp, stmthp) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIServer *srvhp; +OCIError *errhp; +OCISession *authp; +OCIStmt *stmthp; +{ + (void) printf("Freeing handles ...\n"); + + if (srvhp) + (void) OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER); + if (svchp) + (void) OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX); + if (errhp) + (void) OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR); + if (authp) + (void) OCIHandleFree((dvoid *) authp, (ub4) OCI_HTYPE_SESSION); + if (stmthp) + (void) OCIHandleFree((dvoid *) stmthp, (ub4) OCI_HTYPE_STMT); + if (envhp) + (void) OCIHandleFree((dvoid *) envhp, (ub4) OCI_HTYPE_ENV); + + return; +} + +/* ----------------------------------------------------------------- */ +/* Print the error message */ +/* ----------------------------------------------------------------- */ +void report_error(errhp) +OCIError *errhp; +{ + text msgbuf[512]; + sb4 errcode = 0; + + (void) OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + (void) printf("ERROR CODE = %d\n", errcode); + (void) printf("%.*s\n", 512, msgbuf); + return; +} + +/*-------------------------------------------------------------------*/ +/* Logout and detach from the server */ +/*-------------------------------------------------------------------*/ +void logout_detach_server(svchp, srvhp, errhp, authp, userid) +OCISvcCtx *svchp; +OCIServer *srvhp; +OCIError *errhp; +OCISession *authp; +text *userid; +{ + if (OCISessionEnd(svchp, errhp, authp, (ub4) 0)) + { + (void) printf("FAILED: OCISessionEnd()\n"); + report_error(errhp); + } + + (void) printf("%s Logged off.\n", userid); + + if (OCIServerDetach(srvhp, errhp, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCISessionEnd()\n"); + report_error(errhp); + } + + (void) printf("Detached from server.\n"); + + return; +} + +/*---------------------------------------------------------------------*/ +/* Finish demo and clean up */ +/*---------------------------------------------------------------------*/ +sword finish_demo(loggedon, envhp, svchp, srvhp, errhp, authp, stmthp, userid) +boolean loggedon; +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIServer *srvhp; +OCIError *errhp; +OCISession *authp; +OCIStmt *stmthp; +text *userid; +{ + + if (loggedon) + logout_detach_server(svchp, srvhp, errhp, authp, userid); + + free_handles(envhp, svchp, srvhp, errhp, authp, stmthp); + + return OCI_SUCCESS; +} + +/*===================== END OF UTILITY FUNCTIONS ======================*/ + + +int main(argc, argv) +int argc; +char *argv[]; +{ + text *username = (text *)"SCOTT"; + text *password = (text *)"tiger"; + + OCIServer *srvhp; + OCISvcCtx *svchp; + OCISession *authp; + OCIStmt *stmthp = (OCIStmt *) NULL; + OCIBind *bndhp[MAXBINDS]; + int i; + + if (init_handles(&envhp, &svchp, &errhp, &srvhp, &authp, (ub4)OCI_DEFAULT)) + { + (void) printf("FAILED: init_handles()\n"); + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); + } + + if (attach_server((ub4) OCI_DEFAULT, srvhp, errhp, svchp)) + { + (void) printf("FAILED: attach_server()\n"); + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); + } + + if (log_on(authp, errhp, svchp, username, password, + (ub4) OCI_CRED_RDBMS, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: log_on()\n"); + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); + } + + logged_on = TRUE; + + if (OCIHandleAlloc((dvoid *)envhp, (dvoid **) &stmthp, + (ub4)OCI_HTYPE_STMT, (CONST size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: alloc statement handle\n"); + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); + } + + /* bind handles will be implicitly allocated in the bind calls */ + /* need to initialize them to null prior to first usage in bind calls */ + + for (i = 0; i < MAXBINDS; i++) + bndhp[i] = (OCIBind *) 0; + + + if (demo_insert(svchp, stmthp, bndhp, errhp)) + (void) printf("FAILED: demo_insert()\n"); + else + (void) printf("SUCCESS: demo_insert()\n"); + + if (select_locator(svchp, stmthp, bndhp, errhp)) + (void) printf("FAILED: select_locator()\n"); + else + (void) printf("SUCCESS: select_locator()\n"); + + if (demo_update(svchp, stmthp, bndhp, errhp)) + (void) printf("FAILED: demo_update()\n"); + else + (void) printf("SUCCESS: demo_update()\n"); + + + if (demo_delete(svchp, stmthp, bndhp, errhp)) + (void) printf("FAILED: demo_delete()\n"); + else + (void) printf("SUCCESS: demo_delete()\n"); + + locator_free(in2, MAXITER); + locator_free(in3, MAXITER); + + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); +} + + + + +/* ----------------------------------------------------------------- */ +/* bind all the columns of TAB2 by positions. */ +/* ----------------------------------------------------------------- */ +sword bind_in_name(stmthp, bndhp, errhp) +OCIStmt *stmthp; +OCIBind *bndhp[]; +OCIError *errhp; +{ + + if (OCIBindByName(stmthp, &bndhp[0], errhp, + (text *) ":c1", (sb4) strlen((char *) ":c1"), + (dvoid *) &in1[0], (sb4) sizeof(in1[0]), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) + || OCIBindByName(stmthp, &bndhp[1], errhp, + (text *) ":c2", (sb4) strlen((char *) ":c2"), + (dvoid *) &in2[0], (sb4) -1, SQLT_BLOB, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) + || OCIBindByName(stmthp, &bndhp[2], errhp, + (text *) ":c3", (sb4) strlen((char *) ":c3"), + (dvoid *) &in3[0], (sb4) -1, SQLT_CLOB, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIBindByName()\n"); + report_error(errhp); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/* ----------------------------------------------------------------- */ +/* bind all the columns of TAB2 by name. */ +/* ----------------------------------------------------------------- */ +sword bind_name(stmthp, bndhp, errhp) +OCIStmt *stmthp; +OCIBind *bndhp[]; +OCIError *errhp; +{ + + if (OCIBindByName(stmthp, &bndhp[10], errhp, + (text *) ":out1", (sb4) strlen((char *) ":out1"), + (dvoid *) 0, (sb4) sizeof(int), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC) + || OCIBindByName(stmthp, &bndhp[11], errhp, + (text *) ":out2", (sb4) strlen((char *) ":out2"), + (dvoid *) 0, (sb4) -1, SQLT_BLOB, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC) + || OCIBindByName(stmthp, &bndhp[12], errhp, + (text *) ":out3", (sb4) strlen((char *) ":out3"), + (dvoid *) 0, (sb4) -1, SQLT_CLOB, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC)) + { + (void) printf("FAILED: OCIBindByName()\n"); + report_error(errhp); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/* ----------------------------------------------------------------- */ +/* bind array structs for TAB2 columns. */ +/* ----------------------------------------------------------------- */ +sword bind_array(bndhp, errhp) +OCIBind *bndhp[]; +OCIError *errhp; +{ + if (OCIBindArrayOfStruct(bndhp[0], errhp, s1, indsk[0], rlsk[0], rcsk[0]) + || OCIBindArrayOfStruct(bndhp[1], errhp, s2, indsk[1], rlsk[1], rcsk[1]) + || OCIBindArrayOfStruct(bndhp[2], errhp, s3, indsk[2], rlsk[2], rcsk[2])) + { + (void) printf("FAILED: OCIBindArrayOfStruct()\n"); + report_error(errhp); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/* ----------------------------------------------------------------- */ +/* bind dynamic for returning TAB2 columns. */ +/* ----------------------------------------------------------------- */ +sword bind_dynamic(bndhp, errhp) +OCIBind *bndhp[]; +OCIError *errhp; +{ + int i; + + for (i = 0; i < MAXCOLS; i++) + pos[i] = i; + + if (OCIBindDynamic(bndhp[10], errhp, (dvoid *)&pos[0], cbf_no_data, + (dvoid *)&pos[0], cbf_get_data) + || OCIBindDynamic(bndhp[11], errhp, (dvoid *)&pos[1], cbf_no_data, + (dvoid *)&pos[1], cbf_get_data) + || OCIBindDynamic(bndhp[12], errhp, (dvoid *)&pos[2], cbf_no_data, + (dvoid *)&pos[2], cbf_get_data)) + { + (void) printf("FAILED: OCIBindDynamic()\n"); + report_error(errhp); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + + +/* ----------------------------------------------------------------- */ +/* bind input variables. */ +/* ----------------------------------------------------------------- */ +sword bind_input(stmthp, bndhp, errhp) +OCIStmt *stmthp; +OCIBind *bndhp[]; +OCIError *errhp; +{ + /* by the input data by names */ + if (bind_in_name(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* by input array */ + return (bind_array(bndhp, errhp)); +} + + + +/* ----------------------------------------------------------------- */ +/* bind output variables. */ +/* ----------------------------------------------------------------- */ +sword bind_output(stmthp, bndhp, errhp) +OCIStmt *stmthp; +OCIBind *bndhp[]; +OCIError *errhp; +{ + + /* by the returning data by names */ + if (bind_name(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* by dynamic of returning data by names */ + return (bind_dynamic(bndhp, errhp)); +} + + + +/* ----------------------------------------------------------------- */ +/* bind row indicator variables. */ +/* ----------------------------------------------------------------- */ +sword bind_low_high(stmthp, bndhp, errhp) +OCIStmt *stmthp; +OCIBind *bndhp[]; +OCIError *errhp; +{ + if (OCIBindByName(stmthp, &bndhp[23], errhp, + (text *) ":low", (sb4) strlen((char *) ":low"), + (dvoid *) &lowc1[0], (sb4) sizeof(lowc1[0]), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) + || OCIBindByName(stmthp, &bndhp[24], errhp, + (text *) ":high", (sb4) strlen((char *) ":high"), + (dvoid *) &highc1[0], (sb4) sizeof(highc1[0]), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIBindByName()\n"); + report_error(errhp); + return OCI_ERROR; + } + + if (OCIBindArrayOfStruct(bndhp[23], errhp, s1, indsk[0], rlsk[0], rcsk[0]) + || OCIBindArrayOfStruct(bndhp[24], errhp, s1, indsk[0], rlsk[0], rcsk[0])) + { + (void) printf("FAILED: OCIBindArrayOfStruct()\n"); + report_error(errhp); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + + + +/* ----------------------------------------------------------------- */ +/* test for INSERT with RETURNING clause. */ +/* ----------------------------------------------------------------- */ +sword demo_insert(svchp, stmthp, bndhp, errhp) +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIBind *bndhp[]; +OCIError *errhp; +{ + int i, j; + int num[MAXITER]; + text *sqlstmt =(text *)"INSERT INTO TAB2(C1,C2,C3) VALUES \ + (:c1, empty_blob(), empty_clob()) \ + RETURNING C1, C2, C3 INTO \ + :out1, :out2, :out3"; + + (void) printf("\n\n========== TESTING INSERT....RETURNING \n"); + for (i = 0; i < MAXITER; i++) + num[i] = i; + + for (i = 0; i < 1; i++) + { + if (OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4)strlen((char *)sqlstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() insert\n"); + report_error(errhp); + return OCI_ERROR; + } + + if (OCIBindByName(stmthp, &bndhp[0], errhp, + (text *) ":c1", (sb4) strlen((char *) ":c1"), + (dvoid *) &num[0], (sb4) sizeof(num[0]), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) ) + { + (void) printf("FAILED: OCIStmtPrepare() insert\n"); + report_error(errhp); + return OCI_ERROR; + } + + if (OCIBindArrayOfStruct(bndhp[0], errhp, s1, indsk[0], rlsk[0], rcsk[0])) + { + (void) printf("FAILED: OCIStmtPrepare() insert\n"); + report_error(errhp); + return OCI_ERROR; + } + + if (bind_output(stmthp, bndhp, errhp)) + return OCI_ERROR; + + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) MAXITER, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() insert\n"); + report_error(errhp); + return OCI_ERROR; + } + } + + (void) check_lob((int)MAXITER, svchp); + + return OCI_SUCCESS; +} + + + +/* ----------------------------------------------------------------- */ +/* test for UPDATE with RETURNING clause. */ +/* ----------------------------------------------------------------- */ +sword demo_update(svchp, stmthp, bndhp, errhp) +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIBind *bndhp[]; +OCIError *errhp; +{ + int i, j; + int range_size = 3; + + text *sqlstmt = (text *) + "UPDATE TAB2 SET C1 = C1 + :c1, C2 = :c2, C3 = :c3 \ + WHERE C1 >= :low AND C1 <= :high \ + RETURNING C1, C2, C3 INTO :out1, :out2, :out3"; + + (void) printf("\n\n========== TESTING UPDATE....RETURNING \n"); + + if (OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4)strlen((char *)sqlstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() update\n"); + report_error(errhp); + return OCI_ERROR; + } + + + for (i = 0; i < MAXITER; i++) + { + in1[i] = 301 + i; + + /* in2[], in3[] have been loaded in select_locator() */ + + rowsret[i] =0; + } + + /* bind input */ + if (bind_input(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* bind output */ + if (bind_output(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* bind row indicator low, high */ + if (bind_low_high(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* update rows + between 101 and 103; -- expecting 3 rows returned. + between 105 and 106; -- expecting 2 rows returned. + between 108 and 110; -- expecting 3 rows returned. + */ + + lowc1[0] = 101; + highc1[0] = 103; + + lowc1[1] = 105; + highc1[1] = 106; + + lowc1[2] = 109; + highc1[2] = 113; + + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) range_size, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() update\n"); + report_error(errhp); + return OCI_ERROR; + } + + (void) check_lob(range_size, svchp); + + return OCI_SUCCESS; +} + + + + +/* ----------------------------------------------------------------- */ +/* test for DELETE with RETURNING clause. */ +/* ----------------------------------------------------------------- */ +sword demo_delete(svchp, stmthp, bndhp, errhp) +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIBind *bndhp[]; +OCIError *errhp; +{ + int i, range_size = 3; + sword retval; + + text *sqlstmt = (text *) + "DELETE FROM TAB2 WHERE C1 >= :low AND C1 <= :high \ + RETURNING C1, C2, C3 INTO :out1, :out2, :out3"; + + (void) printf("\n\n========== TESTING DELETE....RETURNING \n"); + + if (OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4)strlen((char *)sqlstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() delete\n"); + report_error(errhp); + return OCI_ERROR; + } + + /* bind output */ + if (bind_output(stmthp, bndhp, errhp)) + return OCI_ERROR; + + /* bind row indicator low, high */ + if (bind_low_high(stmthp, bndhp, errhp)) + return OCI_ERROR; + + + /* delete rows + between 201 and 202; -- expecting 2 rows returned. + between 204 and 206; -- expecting 3 rows returned. + between 208 and 209; -- expecting 2 rows returned. + */ + + lowc1[0] = 201; + highc1[0] = 202; + + lowc1[1] = 204; + highc1[1] = 206; + + lowc1[2] = 208; + highc1[2] = 209; + + + for (i=0; i + + PRIVATE FUNCTION(S) + + + EXAMPLES + + NOTES + + + MODIFIED (MM/DD/YY) + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 10/01/98 - include stdlib.h - bug 714175 + azhao 06/03/97 - new file + azhao 06/03/97 - Creation + +*/ + +#include +#include +#include +#include + + +#define MAXBINDS 25 +#define MAXROWS 5 /* max no of rows returned per iter */ +#define MAXCOLS 4 +#define MAXITER 10 /* max no of iters in execute */ +#define MAXBUFLEN 40 + +int main(/*_ int argc, char *argv[] _*/); +sword init_handles(/*_ OCIEnv **envhp, OCISvcCtx **svchp, + OCIError **errhp, OCIServer **svrhp, + OCISession **authp, ub4 mode _*/); + +sword attach_server(/*_ ub4 mode, OCIServer *srvhp, + OCIError *errhp, OCISvcCtx *svchp _*/); +sword log_on(/*_ OCISession *authp, OCIError *errhp, OCISvcCtx *svchp, + text *uid, text *pwd, ub4 credt, ub4 mode _*/); +sword alloc_bind_handle(/*_ OCIStmt *stmthp, OCIBind *bndhp[], + int nbinds _*/); +void print_raw(/*_ ub1 *raw, ub4 rawlen _*/); + +void free_handles(/*_ OCIEnv *envhp, OCISvcCtx *svchp, OCIServer *srvhp, + OCIError *errhp, OCISession *authp, OCIStmt *stmthp _*/); +void report_error(/*_ OCIError *errhp _*/); +void logout_detach_server(/*_ OCISvcCtx *svchp, OCIServer *srvhp, + OCIError *errhp, OCISession *authp, + text *userid _*/); +sword finish_demo(/*_ boolean loggedon, OCIEnv *envhp, OCISvcCtx *svchp, + OCIServer *srvhp, OCIError *errhp, OCISession *authp, + OCIStmt *stmthp, text *userid _*/); +sword demo_insert(/*_ OCISvcCtx *svchp, OCIStmt *stmthp, + OCIBind *bndhp[], OCIError *errhp _*/); +sword demo_update(/*_ OCISvcCtx *svchp, OCIStmt *stmthp, + OCIBind *bndhp[], OCIError *errhp _*/); +sword demo_delete(/*_ OCISvcCtx *svchp, OCIStmt *stmthp, + OCIBind *bndhp[], OCIError *errhp _*/); +sword bind_name(/*_ OCIStmt *stmthp, OCIBind *bndhp[], OCIError *errhp _*/); +sword bind_in_name(/*_ OCIStmt *stmthp, OCIBind *bndhp[], OCIError *errhp _*/); +sword bind_low_high(/*_ OCIStmt *stmthp, OCIBind *bndhp[], + OCIError *errhp _*/); +sword bind_input(/*_ OCIStmt *stmthp, OCIBind *bndhp[], OCIError *errhp _*/); +sword bind_output(/*_ OCIStmt *stmthp, OCIBind *bndhp[], OCIError *errhp _*/); +sword bind_array(/*_ OCIBind *bndhp[], OCIError *errhp _*/); +sword bind_dynamic(/*_ OCIBind *bndhp[], OCIError *errhp _*/); +sb4 cbf_no_data(/*_ dvoid *ctxp, OCIBind *bindp, ub4 iter, ub4 index, + dvoid **bufpp, ub4 *alenpp, ub1 *piecep, dvoid **indpp _*/); +sb4 cbf_get_data(/*_ dvoid *ctxp, OCIBind *bindp, ub4 iter, ub4 index, + dvoid **bufpp, ub4 **alenpp, ub1 *piecep, + dvoid **indpp, ub2 **rcodepp _*/); +sword alloc_buffer(/*_ ub4 pos, ub4 iter, ub4 rows _*/); +sword read_piece(/*_ OCISvcCtx *svchp, OCILobLocator *lob, ub2 lobtype _*/); +sword write_piece(/*_ OCISvcCtx *svchp, OCILobLocator *lob, ub2 lobtype _*/); +sword check_lob(/*_ int iter, OCISvcCtx *svchp _*/); +sword locator_alloc(/*_ OCILobLocator *lob[], ub4 nlobs _*/); +sword locator_free(/*_ OCILobLocator *lob[], ub4 nlobs _*/); +sword select_locator(/*_ OCISvcCtx *svchp, OCIStmt *stmthp, + OCIBind *bndhp[], OCIError *errhp _*/); + diff --git a/cdemodr2.sql b/cdemodr2.sql new file mode 100644 index 0000000..fb234c5 --- /dev/null +++ b/cdemodr2.sql @@ -0,0 +1,61 @@ +rem +rem $Header: cdemodr2.sql 14-jul-99.13:50:24 mjaeger Exp $ +rem +rem cdemodr2.sql +rem +rem Copyright (c) 1997, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem cdemodr2.sql - create and populate test table TAB2. +rem +rem DESCRIPTION +rem Demonstrate INSERT/UPDATE/DELETE statements RETURNING LOBS. +rem +rem NOTES +rem +rem +rem MODIFIED (MM/DD/YY) +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem azhao 06/03/97 - Created +rem + +connect scott/tiger +drop table tab2; + +create table tab2 (c1 integer, c2 blob, c3 clob); + +rem +rem insert some rows for UPDATE later +rem + +insert into tab2 values(101, null, null); +insert into tab2 values(102, null, null); +insert into tab2 values(103, null, null); +insert into tab2 values(104, null, null); +insert into tab2 values(105, null, null); +insert into tab2 values(106, null, null); +insert into tab2 values(107, null, null); +insert into tab2 values(108, null, null); +insert into tab2 values(109, null, null); +insert into tab2 values(110, null, null); + +rem +rem insert some rows for DELETE later +rem + +insert into tab2 values(201, '111', 'AAA'); +insert into tab2 values(202, '111', 'BBB'); +insert into tab2 values(203, '333', 'CCC'); +insert into tab2 values(204, '444', 'DDD'); +insert into tab2 values(205, '555', 'EEE'); +insert into tab2 values(206, '666', 'FFF'); +insert into tab2 values(207, '777', 'GGG'); +insert into tab2 values(208, '888', 'HHH'); +insert into tab2 values(209, '999', 'III'); +insert into tab2 values(210, '000', 'JJJ'); + + +commit; + +quit + diff --git a/cdemodr3.c b/cdemodr3.c new file mode 100644 index 0000000..741e3d2 --- /dev/null +++ b/cdemodr3.c @@ -0,0 +1,703 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemodr3.c 10-oct-2006.14:39:59 azhao Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1997, 2006, Oracle. All rights reserved. +*/ + +/* + + NAME + cdemodr3.c - DML Returning Demo + + DESCRIPTION + Demonstrate INSERT statement RETURNING REF + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + + + NOTES + + + MODIFIED (MM/DD/YY) + azhao 10/10/06 - case-senstive password change + svedala 10/18/99 - + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + azhao 08/19/97 - replace OCIStmtBindByName with OCIBindByName + azhao 06/03/97 - Creation + +*/ + +/*------------------------Inclusions-------------------------------*/ + +#include + +static boolean logged_on = FALSE; + +static OCIRef *addrref[MAXITER]; /* for returned REF */ +static OCIType *addrtdo = (OCIType *) 0; + +static text in_state[MAXITER][2]; +static text in_zip[MAXITER][10]; +static text *out_zip[MAXITER]; /* for returned ZIP */ + +static short *ind[MAXCOLS][MAXITER]; /* indicators */ +static ub2 *rc[MAXCOLS][MAXITER]; /* return codes */ +static ub4 *rl[MAXCOLS][MAXITER]; /* return lengths */ + +/* Rows returned in each iteration */ +static ub2 rowsret[MAXITER]; + +static ub4 pos[MAXCOLS]; +static sb2 null_ind = -1; + + +static OCIEnv *envhp; +static OCIError *errhp; +static OCISvcCtx *svchp; + +/*------------------------end of Inclusions-----------------------------*/ + + +/*========================== UTILITY FUNCTIONS ======================*/ +/* + * These functions are generic functions that can be used in any + * OCI program. + */ +/* ----------------------------------------------------------------- */ +/* Initialize environment, allocate handles */ +/* ----------------------------------------------------------------- */ +sword init_handles(envhp, svchp, errhp, srvhp, authp, init_mode) +OCIEnv **envhp; +OCISvcCtx **svchp; +OCIError **errhp; +OCIServer **srvhp; +OCISession **authp; +ub4 init_mode; +{ + (void) printf("Environment setup ....\n"); + + /* Initialize the OCI Process */ + if (OCIInitialize(init_mode, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 )) + { + (void) printf("FAILED: OCIInitialize()\n"); + return OCI_ERROR; + } + + /* Inititialize the OCI Environment */ + if (OCIEnvInit((OCIEnv **) envhp, (ub4) OCI_DEFAULT, + (size_t) 0, (dvoid **) 0 )) + { + (void) printf("FAILED: OCIEnvInit()\n"); + return OCI_ERROR; + } + + /* Allocate a service handle */ + if (OCIHandleAlloc((dvoid *) *envhp, (dvoid **) svchp, + (ub4) OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc() on svchp\n"); + return OCI_ERROR; + } + + /* Allocate an error handle */ + if (OCIHandleAlloc((dvoid *) *envhp, (dvoid **) errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc() on errhp\n"); + return OCI_ERROR; + } + + /* Allocate a server handle */ + if (OCIHandleAlloc((dvoid *) *envhp, (dvoid **) srvhp, + (ub4) OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc() on srvhp\n"); + return OCI_ERROR; + } + + /* Allocate a authentication handle */ + if (OCIHandleAlloc((dvoid *) *envhp, (dvoid **) authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc() on authp\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + +/* ----------------------------------------------------------------- */ +/* Attach to server with a given mode. */ +/* ----------------------------------------------------------------- */ +sword attach_server(mode, srvhp, errhp, svchp) +ub4 mode; +OCIServer *srvhp; +OCIError *errhp; +OCISvcCtx *svchp; +{ + text *cstring = (text *)""; + + if (OCIServerAttach(srvhp, errhp, (text *) cstring, + (sb4) strlen((char *)cstring), (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIServerAttach()\n"); + return OCI_ERROR; + } + + /* Set the server handle in the service handle */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, (ub4) OCI_ATTR_SERVER, errhp)) + { + (void) printf("FAILED: OCIAttrSet() server attribute\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} +/* ----------------------------------------------------------------- */ +/* Logon to the database using given username, password & credentials*/ +/* ----------------------------------------------------------------- */ +sword log_on(authp, errhp, svchp, uid, pwd, credt, mode) +OCISession *authp; +OCIError *errhp; +OCISvcCtx *svchp; +text *uid; +text *pwd; +ub4 credt; +ub4 mode; +{ + /* Set attributes in the authentication handle */ + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) uid, (ub4) strlen((char *) uid), + (ub4) OCI_ATTR_USERNAME, errhp)) + { + (void) printf("FAILED: OCIAttrSet() userid\n"); + return OCI_ERROR; + } + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) pwd, (ub4) strlen((char *) pwd), + (ub4) OCI_ATTR_PASSWORD, errhp)) + { + (void) printf("FAILED: OCIAttrSet() passwd\n"); + return OCI_ERROR; + } + + (void) printf("Logging on as %s ....\n", uid); + + if (OCISessionBegin(svchp, errhp, authp, credt, mode)) + { + (void) printf("FAILED: OCIAttrSet() passwd\n"); + return OCI_ERROR; + } + + (void) printf("%s logged on.\n", uid); + + /* Set the authentication handle in the Service handle */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) authp, (ub4) 0, (ub4) OCI_ATTR_SESSION, errhp)) + { + (void) printf("FAILED: OCIAttrSet() session\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + +/*---------------------------------------------------------------------*/ +/* Allocate all required bind handles */ +/*---------------------------------------------------------------------*/ + +sword alloc_bind_handle(stmthp, bndhp, nbinds) +OCIStmt *stmthp; +OCIBind *bndhp[]; +int nbinds; +{ + int i; + /* + * This function allocates the specified number of bind handles + * from the given statement handle. + */ + for (i = 0; i < nbinds; i++) + if (OCIHandleAlloc((dvoid *)stmthp, (dvoid **)&bndhp[i], + (ub4)OCI_HTYPE_BIND, (CONST size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc() bind handle\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + +/* ----------------------------------------------------------------- */ +/* Free the specified handles */ +/* ----------------------------------------------------------------- */ +void free_handles(envhp, svchp, srvhp, errhp, authp, stmthp) +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIServer *srvhp; +OCIError *errhp; +OCISession *authp; +OCIStmt *stmthp; +{ + (void) printf("Freeing handles ...\n"); + + if (srvhp) + (void) OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER); + if (svchp) + (void) OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX); + if (errhp) + (void) OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR); + if (authp) + (void) OCIHandleFree((dvoid *) authp, (ub4) OCI_HTYPE_SESSION); + if (stmthp) + (void) OCIHandleFree((dvoid *) stmthp, (ub4) OCI_HTYPE_STMT); + if (envhp) + (void) OCIHandleFree((dvoid *) envhp, (ub4) OCI_HTYPE_ENV); + + return; +} + +/* ----------------------------------------------------------------- */ +/* Print the error message */ +/* ----------------------------------------------------------------- */ +void report_error(errhp) +OCIError *errhp; +{ + text msgbuf[512]; + sb4 errcode = 0; + + (void) OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + (void) printf("ERROR CODE = %d\n", errcode); + (void) printf("%.*s\n", 512, msgbuf); + return; +} + +/*-------------------------------------------------------------------*/ +/* Logout and detach from the server */ +/*-------------------------------------------------------------------*/ +void logout_detach_server(svchp, srvhp, errhp, authp, userid) +OCISvcCtx *svchp; +OCIServer *srvhp; +OCIError *errhp; +OCISession *authp; +text *userid; +{ + if (OCISessionEnd(svchp, errhp, authp, (ub4) 0)) + { + (void) printf("FAILED: OCISessionEnd()\n"); + report_error(errhp); + } + + (void) printf("%s Logged off.\n", userid); + + if (OCIServerDetach(srvhp, errhp, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCISessionEnd()\n"); + report_error(errhp); + } + + (void) printf("Detached from server.\n"); + + return; +} + +/*---------------------------------------------------------------------*/ +/* Finish demo and clean up */ +/*---------------------------------------------------------------------*/ +sword finish_demo(loggedon, envhp, svchp, srvhp, errhp, authp, stmthp, userid) +boolean loggedon; +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIServer *srvhp; +OCIError *errhp; +OCISession *authp; +OCIStmt *stmthp; +text *userid; +{ + + if (loggedon) + logout_detach_server(svchp, srvhp, errhp, authp, userid); + + free_handles(envhp, svchp, srvhp, errhp, authp, stmthp); + + return OCI_SUCCESS; +} + +/*===================== END OF UTILITY FUNCTIONS ======================*/ + + + +int main(argc, argv) +int argc; +char *argv[]; +{ + text *username = (text *)"SCOTT"; + text *password = (text *)"tiger"; + + OCIServer *srvhp; + OCISession *authp; + OCIStmt *stmthp = (OCIStmt *) NULL; + OCIBind *bndhp[MAXBINDS]; + int i; + + if (init_handles(&envhp, &svchp, &errhp, &srvhp, &authp, (ub4)OCI_OBJECT)) + { + (void) printf("FAILED: init_handles()\n"); + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); + } + + if (attach_server((ub4) OCI_DEFAULT, srvhp, errhp, svchp)) + { + (void) printf("FAILED: attach_server()\n"); + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); + } + + if (log_on(authp, errhp, svchp, username, password, + (ub4) OCI_CRED_RDBMS, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: log_on()\n"); + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); + } + + logged_on = TRUE; + + if (OCIHandleAlloc((dvoid *)envhp, (dvoid **) &stmthp, + (ub4)OCI_HTYPE_STMT, (CONST size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: alloc statement handle\n"); + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); + } + + /* bind handles will be implicitly allocated in the bind calls */ + /* need to initialize them to null prior to first usage in bind calls */ + + for (i = 0; i < MAXBINDS; i++) + bndhp[i] = (OCIBind *) 0; + + + if (demo_insert(svchp, stmthp, bndhp, errhp)) + (void) printf("FAILED: demo_insert()\n"); + else + (void) printf("PASSED: demo_insert()\n"); + + return finish_demo(logged_on, envhp, svchp, srvhp, errhp, authp, + stmthp, username); +} + + +/* ----------------------------------------------------------------- */ +sword bind_input(stmthp, bndhp, errhp) +OCIStmt *stmthp; +OCIBind *bndhp[]; +OCIError *errhp; +{ + if (OCIBindByPos(stmthp, &bndhp[0], errhp, (ub4) 1, + (dvoid *) in_state[0], (sb4) 2, SQLT_CHR, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT) + || OCIBindByPos(stmthp, &bndhp[1], errhp, (ub4) 2, + (dvoid *) in_zip[0], (sb4) 10, SQLT_CHR, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIBindByPos()\n"); + report_error(errhp); + return OCI_ERROR; + } + + if (OCIBindArrayOfStruct(bndhp[0], errhp, 2, 0, 0, 0) + || OCIBindArrayOfStruct(bndhp[1], errhp, 10, 0, 0, 0)) + { + (void) printf("FAILED: OCIBindArrayOfStruct()\n"); + report_error(errhp); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/* ----------------------------------------------------------------- */ +sword bind_output(stmthp, bndhp, errhp) +OCIStmt *stmthp; +OCIBind *bndhp[]; +OCIError *errhp; +{ + ub4 i; + + if (OCITypeByName(envhp, errhp, svchp, (CONST text *) 0, + (ub4) 0, (CONST text *) "ADDRESS_OBJECT", + (ub4) strlen((CONST char *) "ADDRESS_OBJECT"), + (CONST text *) 0, (ub4) 0, + OCI_DURATION_SESSION, OCI_TYPEGET_HEADER, &addrtdo)) + { + (void) printf("FAILED: OCITypeByName()\n"); + report_error(errhp); + return OCI_ERROR; + } + + if (OCIBindByName(stmthp, &bndhp[2], errhp, + (text *) ":addref", (sb4) strlen((char *) ":addref"), + (dvoid *) 0, (sb4) sizeof(OCIRef *), SQLT_REF, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC) + || OCIBindByName(stmthp, &bndhp[3], errhp, + (text *) ":zip", (sb4) strlen((char *) ":zip"), + (dvoid *) 0, (sb4) MAXZIPLEN, SQLT_CHR, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC)) + { + (void) printf("FAILED: OCIBindByName()\n"); + report_error(errhp); + return OCI_ERROR; + } + + if (OCIBindObject(bndhp[2], errhp, (OCIType *) addrtdo, + (dvoid **) &addrref[0], (ub4 *) 0, (dvoid **) 0, (ub4 *) 0)) + { + (void) printf("FAILED: OCIBindObject()\n"); + report_error(errhp); + return OCI_ERROR; + } + + + for (i = 0; i < MAXCOLS; i++) + pos[i] = i; + + if (OCIBindDynamic(bndhp[2], errhp, (dvoid *) &pos[0], cbf_no_data, + (dvoid *) &pos[0], cbf_get_data) + || OCIBindDynamic(bndhp[3], errhp, (dvoid *) &pos[1], cbf_no_data, + (dvoid *) &pos[1], cbf_get_data)) + { + (void) printf("FAILED: OCIBindDynamic()\n"); + report_error(errhp); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/* ----------------------------------------------------------------- */ +/* Intbind callback that does not do any data input. */ +/* ----------------------------------------------------------------- */ +sb4 cbf_no_data(ctxp, bindp, iter, index, bufpp, alenpp, piecep, indpp) +dvoid *ctxp; +OCIBind *bindp; +ub4 iter, index; +dvoid **bufpp; +ub4 *alenpp; +ub1 *piecep; +dvoid **indpp; +{ + *bufpp = (dvoid *) 0; + *alenpp = 0; + null_ind = -1; + *indpp = (dvoid *) &null_ind; + *piecep = OCI_ONE_PIECE; + + return OCI_CONTINUE; +} + + + +/* ----------------------------------------------------------------- */ +/* Outbind callback for returning data. */ +/* ----------------------------------------------------------------- */ +sb4 cbf_get_data(ctxp, bindp, iter, index, bufpp, alenp, piecep, + indpp, rcodepp) +dvoid *ctxp; +OCIBind *bindp; +ub4 iter, index; +dvoid **bufpp; +ub4 **alenp; +ub1 *piecep; +dvoid **indpp; +ub2 **rcodepp; +{ + static ub4 rows = 0; + ub4 pos = *((ub4 *)ctxp); + + if (index == 0) + { + (void) OCIAttrGet((CONST dvoid *)bindp, OCI_HTYPE_BIND, (dvoid *)&rows, + (ub4 *) sizeof(ub4), OCI_ATTR_ROWS_RETURNED, errhp); + rowsret[iter] = (ub2)rows; + + if (alloc_buffer(pos, iter, rows)) + return OCI_ERROR; + } + + switch(pos) + { + case 0: + rl[pos][iter][index] = sizeof(OCIRef *); + *bufpp = (dvoid *) (&addrref[iter]); + break; + case 1: + rl[pos][iter][index] = (ub4) MAXZIPLEN; + *bufpp = (dvoid *) (out_zip[iter]+(index * MAXZIPLEN)); + break; + default: + *bufpp = (dvoid *) 0; + *alenp = (ub4 *) 0; + (void) printf("ERROR: invalid position number: %d\n", *((ub4 *)ctxp)); + } + + *piecep = OCI_ONE_PIECE; + + ind[pos][iter][index] = 0; + *indpp = (dvoid *) &ind[pos][iter][index]; + + rc[pos][iter][index] = 0; + *rcodepp = &rc[pos][iter][index]; + + *alenp = &rl[pos][iter][index]; + + return OCI_CONTINUE; +} + + +/* ----------------------------------------------------------------- */ +/* allocate buffers for callback. */ +/* ----------------------------------------------------------------- */ +sword alloc_buffer(pos, iter, rows) +ub4 pos; +ub4 iter; +ub4 rows; +{ + switch(pos) + { + case 0: + break; + case 1: + out_zip[iter] = (text *) malloc(rows * MAXZIPLEN); + break; + default: + (void) printf("ERROR: invalid position number: %d\n", pos); + return OCI_ERROR; + } + + ind[pos][iter] = (short *) malloc(rows * sizeof(short)); + rc[pos][iter] = (ub2 *) malloc(rows * sizeof(ub2)); + rl[pos][iter] = (ub4 *) malloc(rows * sizeof(ub4)); + + return OCI_SUCCESS; +} + + + + +/* ----------------------------------------------------------------- */ +/* demo for INSERT with RETURNING clause. */ +/* ----------------------------------------------------------------- */ +sword demo_insert(svchp, stmthp, bndhp, errhp) +OCISvcCtx *svchp; +OCIStmt *stmthp; +OCIBind *bndhp[]; +OCIError *errhp; +{ + int i; + address *addr; + text *sqlstmt = (text *) "INSERT INTO EXTADDR E VALUES (:1, :2) \ + RETURNING REF(E), ZIP INTO :addref, :zip"; + + for (i = 0; i < MAXITER; i++) + { + memset((void *) in_state[i], (int)'A' + i%26, (size_t) 2); + (void) sprintf((char *) in_zip[i], "%d", 91200 + i); + in_zip[i][5] = '\0'; + + if (OCIObjectNew(envhp, errhp, svchp, OCI_TYPECODE_REF, + (OCIType *) 0, (dvoid *) 0, OCI_DURATION_SESSION, + FALSE, (dvoid **) &addrref[i])) + { + (void) printf("FAILED: OCIObjectNew()\n"); + report_error(errhp); + return OCI_ERROR; + } + } + + if (OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4)strlen((char *)sqlstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() insert\n"); + report_error(errhp); + return OCI_ERROR; + } + + if (bind_input(stmthp, bndhp, errhp)) + return OCI_ERROR; + + if (bind_output(stmthp, bndhp, errhp)) + return OCI_ERROR; + + + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) MAXITER, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() insert\n"); + report_error(errhp); + return OCI_ERROR; + } + + for (i = 0; i < MAXITER; i++) + { + addr = (address *) 0; + + if (addrref[i]) + { + if (OCIObjectPin(envhp, errhp, addrref[i], (OCIComplexObject *)0, + OCI_PIN_ANY, OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&addr)) + { + (void) printf("FAILED: OCIObjectPin()\n"); + report_error(errhp); + return OCI_ERROR; + } + + if (addr) + (void) printf("address.state = %.2s address.zip = %.10s\n", + OCIStringPtr(envhp, addr->state), + OCIStringPtr(envhp, addr->zip)); + else + (void) printf("Pinned address pointer is null\n"); + + if (OCIObjectUnpin(envhp, errhp, (dvoid *) addr)) + { + (void) printf("FAILED: OCIObjectUnPin()\n"); + report_error(errhp); + return OCI_ERROR; + } + } + else + (void) printf("%dth Address REF is NULL\n", i+1); + } + + + for (i = 0; i < MAXITER; i++) + (void) OCIObjectMarkDelete(envhp, errhp, (dvoid *) addrref[i]); + + return OCI_SUCCESS; +} + + +/* end of file cdemodr3.c */ + diff --git a/cdemodr3.h b/cdemodr3.h new file mode 100644 index 0000000..db15694 --- /dev/null +++ b/cdemodr3.h @@ -0,0 +1,108 @@ +/* + * $Header: cdemodr3.h 14-jul-99.12:44:57 mjaeger Exp $ + */ + +/* Copyright (c) 1997, 1999, Oracle Corporation. All rights reserved. +*/ + +/* NOTE: See 'header_template.doc' in the 'doc' dve under the 'forms' + directory for the header file template that includes instructions. +*/ + +/* + NAME + cdemodr3.h - + + DESCRIPTION + + + RELATED DOCUMENTS + + INSPECTION STATUS + Inspection date: + Inspection status: + Estimated increasing cost defects per page: + Rule sets: + + ACCEPTANCE REVIEW STATUS + Review date: + Review status: + Reviewers: + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + EXAMPLES + + NOTES + + + MODIFIED (MM/DD/YY) + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 10/01/98 - include stdlib.h - bug 714175 + azhao 06/03/97 - Creation + +*/ + +#include +#include +#include +#include + +#define MAXBINDS 5 +#define MAXITER 5 +#define MAXCOLS 2 +#define MAXZIPLEN 10 + +struct address +{ + OCIString *state; + OCIString *zip; +}; + +typedef struct address address; + +struct null_address +{ + sb2 null_address; + sb2 null_state; + sb2 null_zip; +}; + +typedef struct null_address null_address; + + +int main(/*_ int argc, char *argv[] _*/); +sword init_handles(/*_ OCIEnv **envhp, OCISvcCtx **svchp, + OCIError **errhp, OCIServer **svrhp, + OCISession **authp, ub4 mode _*/); + +sword attach_server(/*_ ub4 mode, OCIServer *srvhp, + OCIError *errhp, OCISvcCtx *svchp _*/); +sword log_on(/*_ OCISession *authp, OCIError *errhp, OCISvcCtx *svchp, + text *uid, text *pwd, ub4 credt, ub4 mode _*/); +sword alloc_bind_handle(/*_ OCIStmt *stmthp, OCIBind *bndhp[], int nbinds _*/); + +void free_handles(/*_ OCIEnv *envhp, OCISvcCtx *svchp, OCIServer *srvhp, + OCIError *errhp, OCISession *authp, OCIStmt *stmthp _*/); +void report_error(/*_ OCIError *errhp _*/); +void logout_detach_server(/*_ OCISvcCtx *svchp, OCIServer *srvhp, + OCIError *errhp, OCISession *authp, + text *userid _*/); +sword finish_demo(/*_ boolean loggedon, OCIEnv *envhp, OCISvcCtx *svchp, + OCIServer *srvhp, OCIError *errhp, OCISession *authp, + OCIStmt *stmthp, text *userid _*/); +sword demo_insert(/*_ OCISvcCtx *svchp, OCIStmt *stmthp, + OCIBind *bndhp[], OCIError *errhp _*/); +sword bind_input(/*_ OCIStmt *stmthp, OCIBind *bndhp[], OCIError *errhp _*/); +sword bind_output(/*_ OCIStmt *stmthp, OCIBind *bndhp[], OCIError *errhp _*/); +sb4 cbf_no_data(/*_ dvoid *ctxp, OCIBind *bindp, ub4 iter, ub4 index, + dvoid **bufpp, ub4 *alenpp, ub1 *piecep, dvoid **indpp _*/); +sb4 cbf_get_data(/*_ dvoid *ctxp, OCIBind *bindp, ub4 iter, ub4 index, + dvoid **bufpp, ub4 **alenpp, ub1 *piecep, + dvoid **indpp, ub2 **rcodepp _*/); +sword alloc_buffer(/*_ ub4 pos, ub4 iter, ub4 rows _*/); + diff --git a/cdemodr3.sql b/cdemodr3.sql new file mode 100644 index 0000000..535f324 --- /dev/null +++ b/cdemodr3.sql @@ -0,0 +1,34 @@ +rem +rem $Header: cdemodr3.sql 14-jul-99.13:51:06 mjaeger Exp $ +rem +rem cdemodr3.sql +rem +rem Copyright (c) 1997, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem cdemodr3.sql - setup for cdemodr3.c +rem +rem DESCRIPTION +rem create type and table used for cdemodr3.c +rem +rem NOTES +rem +rem +rem MODIFIED (MM/DD/YY) +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem svedala 09/11/98 - a "/" required after create type - bug 717842 +rem azhao 06/03/97 - Created +rem + +connect scott/tiger + +drop table extaddr; +drop type address_object; + +create type address_object as object (state char(2), zip char(10)); +/ + +create table extaddr of address_object; + +quit + diff --git a/cdemodsa.c b/cdemodsa.c new file mode 100644 index 0000000..1225ee4 --- /dev/null +++ b/cdemodsa.c @@ -0,0 +1,796 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemodsa.c 10-oct-2006.14:39:59 azhao Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1997, 2006, Oracle. All rights reserved. +*/ + +/* + + NAME + cdemodsa.c - + + DESCRIPTION + + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + + + NOTES + + + MODIFIED (MM/DD/YY) + azhao 10/10/06 - case-senstive password change + stsun 06/18/04 - bug3698329: check null str for strncpy + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 09/09/98 - lines longer than 79 chars reformatted - bug 722491 + svedala 05/22/98 - modify describe_typeattr + azhao 06/03/97 - fix lint errors + sgollapu 05/30/97 - Creation + +*/ + +/* + * -- cdemodsa.c -- + * An example program which describes the table EMPNML created by running + * the sql script CDEMODSA.SQL as SCOTT/TIGER. The table EMPNML consists of + * two columns, one of which is an ADT PERSON defined as containing a name + * (CHAR(20)), age (NUMBER), and address (an ADT). + * + * When successfully executed, the program will print the user defined type + * PERSON and its attributes, and then the table EMPNML. Note that the + * schema name and type name are printed for user-defined types only. + */ + +#include +#include +#include +#include +#include + +static text *username = (text *) "SCOTT"; /* username */ +static text *password = (text *) "tiger"; /* password */ +static text *tablename = (text *) "EMPNML"; /* tablename */ + +static OCIEnv *envhp = (OCIEnv *)0; +static OCIServer *srvhp = (OCIServer *)0; +static OCIError *errhp = (OCIError *)0; +static OCISvcCtx *svchp = (OCISvcCtx *)0; +static OCIStmt *stmhp = (OCIStmt *)0; +static OCIDescribe *dschp = (OCIDescribe *)0; +static OCISession *authp = (OCISession *)0; + +static void initialize(/*_ void _*/); +static void logon(/*_ void _*/); +static void describe_table(/*_ void _*/); +static void describe_column(/*_ OCIParam *parmp, ub4 parmcnt _*/); +static void describe_type(/*_ OCIParam *parmp _*/); +static void describe_typeattr(/*_ OCIParam *parmp, ub4 num_attr _*/); +static void describe_typecoll(/*_ OCIParam *parmp, sword typecode _*/); +static void describe_typemethodlist(/*_ OCIParam *parmp, ub4 num_meth, + text *comment _*/); +static void describe_typemethod(/*_ OCIParam *parmp, text *comment _*/); +static void describe_typearg(/*_ OCIParam *parmp, ub1 type, ub4 start, + ub4 end _*/); +static void logout(/*_ void _*/); +static void cleanup(/*_ void _*/); +static void checkerr(/*_ OCIError *errhp, sword status _*/); +int main(/*_ int argc, char *argv[] _*/); + +static sb4 status; + +#define NPOS 30 /* max number of columns */ +#define MAXLEN 128 /* max length of column names */ + + +int main(argc, argv) +int argc; +char *argv[]; +{ + initialize (); + logon (); + + checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmhp, + OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0)); + describe_table (); + logout (); + cleanup (); +} + +static void initialize () +{ + printf ("\nInitializing the environment..\n"); + (void) OCIInitialize (OCI_OBJECT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 ); + + (void) OCIEnvInit ((OCIEnv **) &envhp, OCI_DEFAULT, (size_t) 0, + (dvoid **) 0); + + /* error handle */ + (void) OCIHandleAlloc ((dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + + /* server contexts */ + (void) OCIHandleAlloc ((dvoid *) envhp, (dvoid **) &srvhp, OCI_HTYPE_SERVER, + (size_t) 0, (dvoid **) 0); + + (void) OCIHandleAlloc ((dvoid *) envhp, (dvoid **) &svchp, OCI_HTYPE_SVCCTX, + (size_t) 0, (dvoid **) 0); + + (void) OCIServerAttach (srvhp, errhp, (text *)"", + strlen(""), 0); + + /* set attribute server context in the service context */ + (void) OCIAttrSet ((dvoid *) svchp, OCI_HTYPE_SVCCTX, (dvoid *)srvhp, + (ub4) 0, OCI_ATTR_SERVER, (OCIError *) errhp); +} + +static void logon () +{ + printf ("Logging on as %s/%s..", username, password); + (void) OCIHandleAlloc ((dvoid *) envhp, (dvoid **)&authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0); + + (void) OCIAttrSet ((dvoid *)authp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)username, (ub4)strlen((char *)username), + OCI_ATTR_USERNAME, errhp); + + (void) OCIAttrSet ((dvoid *)authp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)password, (ub4)strlen((char *)password), + OCI_ATTR_PASSWORD, errhp); + + checkerr (errhp, OCISessionBegin (svchp, errhp, authp, OCI_CRED_RDBMS, + (ub4) OCI_DEFAULT)); + printf ("Logged on\n"); + + (void) OCIAttrSet ((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) authp, (ub4) 0, + (ub4) OCI_ATTR_SESSION, errhp); +} + + +static void describe_table () +{ + sword retval; + OCIParam *parmp, *collst; + ub4 parmcnt; + ub2 numcols; + ub4 objid = 0; + + checkerr (errhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **) &dschp, + (ub4) OCI_HTYPE_DESCRIBE, + (size_t) 0, (dvoid **) 0)); + + if ((retval = OCIDescribeAny(svchp, errhp, (dvoid *)tablename, + (ub4) strlen((char *) tablename), + OCI_OTYPE_NAME, (ub1)1, + OCI_PTYPE_TABLE, dschp)) != OCI_SUCCESS) + { + if (retval == OCI_NO_DATA) + { + printf("NO DATA: OCIDescribeAny on %s\n", tablename); + } + else /* OCI_ERROR */ + { + printf( "ERROR: OCIDescribeAny on %s\n", tablename); + checkerr(errhp, retval); + return; + } + } + else + { + /* get the parameter descriptor */ + checkerr (errhp, OCIAttrGet((dvoid *)dschp, (ub4)OCI_HTYPE_DESCRIBE, + (dvoid *)&parmp, (ub4 *)0, (ub4)OCI_ATTR_PARAM, + (OCIError *)errhp)); + + /* Get the attributes of the table */ + checkerr (errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &objid, (ub4 *) 0, + (ub4) OCI_ATTR_OBJID, (OCIError *)errhp)); + /* column list of the table */ + checkerr (errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &collst, (ub4 *) 0, + (ub4) OCI_ATTR_LIST_COLUMNS, (OCIError *)errhp)); + /* number of columns */ + checkerr (errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &numcols, (ub4 *) 0, + (ub4) OCI_ATTR_NUM_COLS, (OCIError *)errhp)); + /* now describe each column */ + describe_column(collst, numcols); + } + /* free the describe handle */ + OCIHandleFree((dvoid *) dschp, (ub4) OCI_HTYPE_DESCRIBE); +} + +static void describe_column(parmp, parmcnt) +OCIParam *parmp; +ub4 parmcnt; +{ + text colname1[NPOS][30], colname2[NPOS][30], colname3[NPOS][30]; + text *namep; + ub4 sizep; + ub2 collen[NPOS]; + ub2 coltyp[NPOS]; + OCIParam *parmdp; + ub4 i, pos; + sword retval; + ub1 precision[NPOS]; + sb1 scale[NPOS]; + + for (pos = 1; pos <= parmcnt; pos++) + { + /* get the parameter descriptor for each column */ + checkerr (errhp, OCIParamGet((dvoid *)parmp, (ub4)OCI_DTYPE_PARAM, errhp, + (dvoid *)&parmdp, (ub4) pos)); + /* column length */ + checkerr (errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &collen[pos-1], (ub4 *) 0, + (ub4) OCI_ATTR_DATA_SIZE, (OCIError *)errhp)); + /* column name */ + checkerr (errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &sizep, + (ub4) OCI_ATTR_NAME, (OCIError *)errhp)); + + if(sizep){ + strncpy((char *)colname1[pos-1], (char *)namep, (size_t) sizep); + } + colname1[pos-1][sizep] = '\0'; + /* schema name */ + checkerr (errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &sizep, + (ub4) OCI_ATTR_SCHEMA_NAME, (OCIError *)errhp)); + + if(sizep){ + strncpy((char *)colname2[pos-1], (char *)namep, (size_t) sizep); + } + colname2[pos-1][sizep] = '\0'; + /* type name */ + checkerr (errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &sizep, + (ub4) OCI_ATTR_TYPE_NAME, (OCIError *)errhp)); + + if(sizep){ + strncpy((char *)colname3[pos-1], (char *)namep, (size_t) sizep); + } + colname3[pos-1][sizep] = '\0'; + /* data type */ + checkerr (errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &coltyp[pos-1], (ub4 *) 0, + (ub4) OCI_ATTR_DATA_TYPE, (OCIError *)errhp)); + /* precision */ + checkerr (errhp, OCIAttrGet ((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &precision[pos-1], (ub4 *) 0, + (ub4) OCI_ATTR_PRECISION, (OCIError *)errhp)); + /* scale */ + checkerr (errhp, OCIAttrGet ((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &scale[pos-1], (ub4 *) 0, + (ub4) OCI_ATTR_SCALE, (OCIError *)errhp)); + + /* if column or attribute is type OBJECT/COLLECTION, describe it by ref */ + if (coltyp[pos-1] == OCI_TYPECODE_OBJECT || + coltyp[pos-1] == OCI_TYPECODE_NAMEDCOLLECTION) + { + OCIDescribe *deshp; + OCIParam *parmhp; + OCIRef *typeref; + + /* get ref to attribute/column type */ + checkerr (errhp, OCIAttrGet ((dvoid *)parmdp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&typeref, (ub4 *)0, + (ub4)OCI_ATTR_REF_TDO, (OCIError *)errhp)); + /* describe it */ + checkerr (errhp, OCIHandleAlloc((dvoid *)envhp, (dvoid **)&deshp, + (ub4)OCI_HTYPE_DESCRIBE, (size_t)0, (dvoid **)0)); + + checkerr (errhp, OCIDescribeAny(svchp, errhp, (dvoid *)typeref, (ub4)0, + OCI_OTYPE_REF, (ub1)1, OCI_PTYPE_TYPE, deshp)); + /* get the parameter descriptor */ + checkerr (errhp, OCIAttrGet((dvoid *)deshp, (ub4)OCI_HTYPE_DESCRIBE, + (dvoid *)&parmhp, (ub4 *)0, (ub4)OCI_ATTR_PARAM, + (OCIError *)errhp)); + /* describe the type */ + describe_type (parmhp); + + /* free describe handle */ + OCIHandleFree((dvoid *) deshp, (ub4) OCI_HTYPE_DESCRIBE); + } + } + + printf ("\n------------------\n"); + printf ("TABLE : %s \n", tablename); + printf ("------------------\n"); + printf ( + "\nColumn Name Schema Length Type Datatype Precision Scale\n"); + printf ( + "_____________________________________________________________________\n"); + for (i = 1; i <= parmcnt; i++) + printf( "%10s%10s%6d%10s%10d%10d%10d\n", colname1[i-1], colname2[i-1], + collen[i-1], colname3[i-1], coltyp[i-1], precision[i-1], scale[i-1]); +} + + +static void describe_type(type_parmp) +OCIParam *type_parmp; +{ + sword retval; + OCITypeCode typecode, + collection_typecode; + text schema_name[MAXLEN], + version_name[MAXLEN], + type_name[MAXLEN]; + text *namep; + ub4 size; /* not used */ + OCIRef *type_ref; /* not used */ + ub2 num_attr, + num_method; + ub1 is_incomplete, + has_table; + OCIParam *list_attr, + *list_method, + *map_method, + *order_method, + *collection_elem; + + printf ("\n\n-----------------\n"); + printf ("USED-DEFINED TYPE\n-----------------\n"); + + checkerr (errhp, OCIAttrGet((dvoid*) type_parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &size, + (ub4) OCI_ATTR_SCHEMA_NAME, (OCIError *) errhp)); + if(size){ + strncpy((char *)schema_name, (char *)namep, (size_t) size); + } + schema_name[size] = '\0'; + printf ( "Schema: %s\n", schema_name); + + checkerr (errhp, OCIAttrGet((dvoid*) type_parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &size, + (ub4) OCI_ATTR_NAME, (OCIError *) errhp)); + if(size){ + strncpy ((char *)type_name, (char *)namep, (size_t) size); + } + type_name[size] = '\0'; + printf ( "Name: %s\n", type_name); + + /* get ref of type, although we are not using it here */ + checkerr (errhp, OCIAttrGet((dvoid *)type_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&type_ref, (ub4 *)0, + (ub4)OCI_ATTR_REF_TDO, (OCIError *)errhp)); + + checkerr (errhp, OCIAttrGet((dvoid*) type_parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &typecode, (ub4 *) 0, + (ub4) OCI_ATTR_TYPECODE, (OCIError *) errhp)); + printf ( "Oracle Typecode: %d\n", typecode); + + checkerr (errhp, OCIAttrGet((dvoid*) type_parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &size, + (ub4) OCI_ATTR_VERSION, (OCIError *) errhp)); + if(size){ + strncpy ((char *)version_name, (char *)namep, (size_t) size); + } + version_name[size] = '\0'; + printf ( "Version: %s\n", version_name); + + checkerr (errhp, OCIAttrGet((dvoid*) type_parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &is_incomplete, (ub4 *) 0, + (ub4) OCI_ATTR_IS_INCOMPLETE_TYPE, (OCIError *)errhp)); + printf ( "Is incomplete: %d\n", is_incomplete); + + checkerr (errhp, OCIAttrGet((dvoid*) type_parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &has_table, (ub4 *) 0, + (ub4) OCI_ATTR_HAS_NESTED_TABLE, (OCIError *)errhp)); + printf ( "Has nested table: %d\n", has_table); + + /* describe type attributes if any */ + checkerr (errhp, OCIAttrGet((dvoid*) type_parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &num_attr, (ub4 *) 0, + (ub4) OCI_ATTR_NUM_TYPE_ATTRS, (OCIError *) errhp)); + printf ( "Number of attrs: %d\n", num_attr); + if (num_attr > 0) + { + /* get the list of attributes and pass it on */ + checkerr (errhp, OCIAttrGet((dvoid *)type_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&list_attr, (ub4 *)0, + (ub4)OCI_ATTR_LIST_TYPE_ATTRS, (OCIError *)errhp)); + describe_typeattr(list_attr, num_attr); + } + + /* describe the collection element if this is a collection type */ + if (typecode == OCI_TYPECODE_NAMEDCOLLECTION) + { + checkerr (errhp, OCIAttrGet((dvoid *)type_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&collection_typecode, (ub4 *)0, + (ub4)OCI_ATTR_COLLECTION_TYPECODE, (OCIError *)errhp)); + printf ( "Collection typecode: %d\n", collection_typecode); + + checkerr (errhp, OCIAttrGet((dvoid *)type_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&collection_elem, (ub4 *)0, + (ub4)OCI_ATTR_COLLECTION_ELEMENT, (OCIError *)errhp)); + + describe_typecoll(collection_elem, collection_typecode); + } + + /* describe the MAP method if any */ + checkerr (errhp, OCIAttrGet((dvoid*) type_parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &map_method, (ub4 *) 0, + (ub4) OCI_ATTR_MAP_METHOD, (OCIError *)errhp)); + if (map_method != (dvoid *)0) + describe_typemethod(map_method,(text *)"TYPE MAP METHOD\n---------------"); + + /* describe the ORDER method if any; note that this is mutually exclusive */ + /* with MAP */ + checkerr (errhp, OCIAttrGet((dvoid *)type_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&order_method, (ub4 *)0, + (ub4)OCI_ATTR_ORDER_METHOD, (OCIError *)errhp)); + if (order_method != (dvoid *)0) + describe_typemethod(order_method, + (text *)"TYPE ORDER METHOD\n-----------------"); + + /* describe all methods (including MAP/ORDER) */ + checkerr (errhp, OCIAttrGet((dvoid *)type_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&num_method, (ub4 *)0, + (ub4)OCI_ATTR_NUM_TYPE_METHODS, (OCIError *)errhp)); + printf("Number of methods: %d\n", num_method); + if (num_method > 0) + { + checkerr (errhp, OCIAttrGet((dvoid *)type_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&list_method, (ub4 *)0, + (ub4)OCI_ATTR_LIST_TYPE_METHODS, (OCIError *)errhp)); + + describe_typemethodlist(list_method, num_method, + (text *)"TYPE METHOD\n-----------"); + } +} + +static void describe_typeattr(attrlist_parmp, num_attr) +OCIParam *attrlist_parmp; +ub4 num_attr; +{ + OCIParam *attr_parmp; + sword retval; + text *attr_name, + *schema_name, + *type_name; + ub4 namesize, snamesize, tnamesize; + ub4 size; + ub2 datasize; + OCITypeCode typecode; + ub2 datatype; + ub1 precision; + sb1 scale; + ub4 i, + pos; + + printf( + "\nAttr Name Schema Type Length Typ Datatyp Pre Scal\n"); + printf( + "____________________________________________________________________\n"); + + for (pos = 1; pos <= num_attr; pos++) + { + /* get the attribute's describe handle from the parameter */ + checkerr (errhp, OCIParamGet((dvoid *)attrlist_parmp, (ub4)OCI_DTYPE_PARAM, + errhp, (dvoid *)&attr_parmp, (ub4)pos)); + + /* obtain attribute values for the type's attributes */ + checkerr (errhp, OCIAttrGet((dvoid *)attr_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&attr_name, (ub4 *)&namesize, + (ub4)OCI_ATTR_NAME, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)attr_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&schema_name, (ub4 *)&snamesize, + (ub4)OCI_ATTR_SCHEMA_NAME, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)attr_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&type_name, (ub4 *)&tnamesize, + (ub4)OCI_ATTR_TYPE_NAME, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)attr_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&datasize, (ub4 *)0, + (ub4)OCI_ATTR_DATA_SIZE, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)attr_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&typecode, (ub4 *)0, + (ub4)OCI_ATTR_TYPECODE, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)attr_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&datatype, (ub4 *)0, + (ub4)OCI_ATTR_DATA_TYPE, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)attr_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&precision, (ub4 *)0, + (ub4)OCI_ATTR_PRECISION, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)attr_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&scale, (ub4 *)0, + (ub4)OCI_ATTR_SCALE, (OCIError *)errhp)); + + /* if typecode == OCI_TYPECODE_OBJECT, you can proceed to describe it + recursively by calling describe_type() with its name; or you can + obtain its OCIRef by using OCI_ATTR_REF_TDO, and then describing the + type by REF */ + + /* print values for the attribute */ + printf("%10.*s%10.*s%16.*s%8d%4d%8d%4d%5d\n", namesize, attr_name, + snamesize, schema_name, tnamesize, type_name, datasize, + typecode, datatype, precision, scale); + } + printf("\n"); +} + + +static void describe_typecoll(collelem_parmp, coll_typecode) +OCIParam *collelem_parmp; +sword coll_typecode; /* OCI_TYPECODE_VARRAY or OCI_TYPECODE_TABLE */ +{ + text *attr_name, + *schema_name, + *type_name; + ub4 size; + ub2 datasize; + ub4 num_elems; + OCITypeCode typecode; + ub2 datatype; + sword retval; + + checkerr (errhp, OCIAttrGet((dvoid *)collelem_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&schema_name, (ub4 *)&size, + (ub4)OCI_ATTR_SCHEMA_NAME, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)collelem_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&type_name, (ub4 *)&size, + (ub4)OCI_ATTR_TYPE_NAME, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)collelem_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&datasize, (ub4 *)0, + (ub4)OCI_ATTR_DATA_SIZE, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)collelem_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&typecode, (ub4 *)0, + (ub4)OCI_ATTR_TYPECODE, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)collelem_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&datatype, (ub4 *)0, + (ub4)OCI_ATTR_DATA_TYPE, (OCIError *)errhp)); + if (coll_typecode == OCI_TYPECODE_VARRAY) + checkerr (errhp, OCIAttrGet((dvoid *)collelem_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&num_elems, (ub4 *)0, + (ub4)OCI_ATTR_NUM_ELEMS, (OCIError *)errhp)); + else num_elems = 0; + + printf("Schema Type Length Type Datatype Elements\n"); + printf("_________________________________________________________\n"); + + printf("%10s%16s%9d%5d%9d%8d\n", schema_name, type_name, + datasize, typecode, datatype, num_elems); +} + +static void describe_typemethodlist(methodlist_parmp, num_method, comment) +OCIParam *methodlist_parmp; +ub4 num_method; +text *comment; +{ + sword retval; + OCIParam *method_parmp; + ub4 i, pos; + /* traverse the method list */ + for (pos = 1; pos <= num_method; pos++) + { + checkerr (errhp, OCIParamGet((dvoid *)methodlist_parmp, + (ub4)OCI_DTYPE_PARAM, errhp, + (dvoid *)&method_parmp, (ub4)pos)); + describe_typemethod(method_parmp, comment); + } +} + +static void describe_typemethod(method_parmp, comment) +OCIParam *method_parmp; +text *comment; +{ + sword retval; + text *method_name; + ub4 size; + ub2 ovrid; + ub4 num_arg; + ub1 has_result, + is_map, + is_order; + OCITypeEncap encap; + OCIParam *list_arg; + + /* print header */ + printf("\n%s\n", comment); + + checkerr (errhp, OCIAttrGet((dvoid *)method_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&method_name, (ub4 *)&size, + (ub4)OCI_ATTR_NAME, (OCIError *)errhp)); + printf("Method Name: %s\n", method_name); + + checkerr (errhp, OCIAttrGet((dvoid *)method_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&ovrid, (ub4 *)0, + (ub4)OCI_ATTR_OVERLOAD_ID, (OCIError *)errhp)); + printf("Overload ID: %d\n", ovrid); + + checkerr (errhp, OCIAttrGet((dvoid *)method_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&encap, (ub4 *)0, + (ub4)OCI_ATTR_ENCAPSULATION, (OCIError *)errhp)); + printf("Encapsulation: %s\n", + (encap == OCI_TYPEENCAP_PUBLIC) ? "public" : "private"); + + checkerr (errhp, OCIAttrGet((dvoid *)method_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&is_map, (ub4 *)0, + (ub4)OCI_ATTR_IS_MAP, (OCIError *)errhp)); + printf("Is map: %d\n", is_map); + + checkerr (errhp, OCIAttrGet((dvoid *)method_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&is_order, (ub4 *)0, + (ub4)OCI_ATTR_IS_ORDER, (OCIError *)errhp)); + printf("Is order: %d\n", is_order); + + /* retrieve the argument list, includes result */ + checkerr (errhp, OCIAttrGet((dvoid *)method_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&list_arg, (ub4 *)0, + (ub4)OCI_ATTR_LIST_ARGUMENTS, (OCIError *)errhp)); + + /* if this is a function (has results, then describe results */ + checkerr (errhp, OCIAttrGet((dvoid *)method_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&has_result, (ub4 *)0, + (ub4)OCI_ATTR_HAS_RESULT, (OCIError *)errhp)); + printf("Has result: %d\n", has_result); + if (has_result) + { + describe_typearg(list_arg, OCI_PTYPE_TYPE_RESULT, 0, 1); + } + + /* describe each argument */ + checkerr (errhp, OCIAttrGet((dvoid *)method_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&num_arg, (ub4 *)0, + (ub4)OCI_ATTR_NUM_ARGS, (OCIError *)errhp)); + printf("Number of args: %d\n", num_arg); + if (num_arg > 0) + { + describe_typearg(list_arg, OCI_PTYPE_TYPE_ARG, 1, num_arg+1); + } +} + +static void describe_typearg (arglist_parmp, type, start, end) +OCIParam *arglist_parmp; +ub1 type; +ub4 start; +ub4 end; +{ + OCIParam *arg_parmp; + sword retval; + text *arg_name, + *schema_name, + *type_name; + ub2 position; + ub2 level; + ub1 has_default; + OCITypeParamMode iomode; + ub4 size; + OCITypeCode typecode; + ub2 datatype; + ub4 i, + pos; + + /* print header */ + printf("Name Pos Type Datatype Lvl Def Iomode SchName TypeName\n"); + printf( + "________________________________________________________________\n"); + + for (pos = start; pos < end; pos++) + { + /* get the attribute's describe handle from the parameter */ + checkerr (errhp, OCIParamGet((dvoid *)arglist_parmp, (ub4)OCI_DTYPE_PARAM, + errhp, (dvoid *)&arg_parmp, (ub4)pos)); + + /* obtain attribute values for the type's attributes */ + /* if this is a result, it has no name, so we give it one */ + if (type == OCI_PTYPE_TYPE_RESULT) + { + arg_name = (text *)"RESULT"; + } + else if (type == OCI_PTYPE_TYPE_ARG) + { + checkerr (errhp, OCIAttrGet((dvoid *)arg_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&arg_name, (ub4 *)&size, + (ub4)OCI_ATTR_NAME, (OCIError *)errhp)); + } + checkerr (errhp, OCIAttrGet((dvoid *)arg_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&position, (ub4 *)0, + (ub4)OCI_ATTR_POSITION, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)arg_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&typecode, (ub4 *)0, + (ub4)OCI_ATTR_TYPECODE, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)arg_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&datatype, (ub4 *)0, + (ub4)OCI_ATTR_DATA_TYPE, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)arg_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&level, (ub4 *)0, + (ub4)OCI_ATTR_LEVEL, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)arg_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&has_default, (ub4 *)0, + (ub4)OCI_ATTR_HAS_DEFAULT, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)arg_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&iomode, (ub4 *)0, + (ub4)OCI_ATTR_IOMODE, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)arg_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&schema_name, (ub4 *)&size, + (ub4)OCI_ATTR_SCHEMA_NAME, (OCIError *)errhp)); + checkerr (errhp, OCIAttrGet((dvoid *)arg_parmp, (ub4)OCI_DTYPE_PARAM, + (dvoid *)&type_name, (ub4 *)&size, + (ub4)OCI_ATTR_TYPE_NAME, (OCIError *)errhp)); + + /* if typecode == OCI_TYPECODE_OBJECT, you can proceed to describe it + recursively by calling describe_type() with its name; or you can + obtain its OCIRef by using OCI_ATTR_REF_TDO, and then describing the + type by REF */ + + /* print values for the argument */ + printf ("%8s%5d%5d%9d%4d%3c%7d%8s%14s\n", arg_name, position, + typecode, datatype, level, has_default ? 'y' : 'n', + iomode, schema_name, type_name); + } +} + +static void logout() +{ + printf ("\n\nFreeing statement handle..\n"); + OCIHandleFree ((dvoid *) stmhp, (ub4) OCI_HTYPE_STMT); + + printf ("Logging off...\n"); + OCISessionEnd (svchp, errhp, authp, (ub4) 0); +} + +static void cleanup() +{ + printf ("\nFreeing global structures..\n"); + if (errhp) OCIServerDetach (srvhp, errhp, (ub4) OCI_DEFAULT ); + if (srvhp) OCIHandleFree((dvoid *) srvhp, (CONST ub4) OCI_HTYPE_SERVER); + if (svchp) OCIHandleFree((dvoid *) svchp, (CONST ub4) OCI_HTYPE_SVCCTX); + if (errhp) OCIHandleFree((dvoid *) errhp, (CONST ub4) OCI_HTYPE_ERROR); + if (authp) OCIHandleFree((dvoid *) authp, (CONST ub4) OCI_HTYPE_SESSION); +} + + +static void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet ((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", 512, errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} + +/* end of file cdemodsa.c */ + diff --git a/cdemodsa.sql b/cdemodsa.sql new file mode 100644 index 0000000..754469f --- /dev/null +++ b/cdemodsa.sql @@ -0,0 +1,48 @@ +rem +rem $Header: cdemodsa.sql 14-jul-99.13:51:36 mjaeger Exp $ +rem +rem cdemodsa.sql +rem +rem Copyright (c) 1997, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem cdemodsa.sql - +rem +rem DESCRIPTION +rem +rem +rem NOTES +rem +rem +rem MODIFIED (MM/DD/YY) +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem svedala 09/11/98 - a "/" required after create type - bug 717842 +rem azhao 06/03/97 - add connect scott/tiger +rem sgollapu 05/30/97 - Created +rem + +connect scott/tiger; + +set echo on; + +drop table customerobj; +drop type address_object; +drop type person; +drop table empnml; +drop table empref; + +create type address_object as object (state char(2), zip char(10)); +/ + +create table customerobj (custno number, addr REF address_object); + +create type person as object(name char(20), age number, + address address_object); +/ + +create table empnml (emp_id number, emp_info person); +create table empref (emp_id number, emp_info REF person); + +commit; + +set echo off; diff --git a/cdemodsc.c b/cdemodsc.c new file mode 100644 index 0000000..2690d72 --- /dev/null +++ b/cdemodsc.c @@ -0,0 +1,870 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemodsc.c 14-jul-99.13:10:30 mjaeger Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1997, 1999, Oracle Corporation. All rights reserved. +*/ + +/* + NAME + cdemodsc.c + DESCRIPTION + Tests OCIDescribeAny on ADT. + + cdemodsc takes the user name and password and a type name + (created in the database) as command line arguments and + dumps all the information about the type -- + its attribute types, methods, + method parameters, etc. + + NOTES + see routines. + + MODIFIED (MM/DD/YY) + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 09/09/98 - lines longer than 79 chars reformatted - bug 722491 + echen 06/04/97 - fix the include files + cchau 05/29/97 - creation +*/ + +#ifndef CDEMODSC_ORACLE +#include "cdemodsc.h" +#endif + +/*****************************************************************************/ +static void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + break; + case OCI_NEED_DATA: + break; + case OCI_NO_DATA: + break; + case OCI_ERROR: + (void) OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); + (void) printf("Error - %s\n", errbuf); + exit(1); + break; + case OCI_INVALID_HANDLE: + break; + case OCI_STILL_EXECUTING: + break; + case OCI_CONTINUE: + break; + default: + break; + } +} + +/*----------------------------------------------------------------------*/ + +static void chk_methodlst(envhp, errhp, svchp, parmp, count, comment) +OCIEnv *envhp; +OCIError *errhp; +OCISvcCtx *svchp; +dvoid *parmp; +ub4 count; +const text *comment; +{ + sword retval; + ub4 pos; + dvoid *parmdp; + + for (pos = 1; pos <= count; pos++) + { + checkerr(errhp, OCIParamGet((dvoid *)parmp, (ub4) OCI_DTYPE_PARAM, errhp, + (dvoid *)&parmdp, (ub4) pos)); + chk_method(envhp, errhp, svchp, parmdp, comment); + } +} + +/*----------------------------------------------------------------------*/ + +static void chk_method(envhp, errhp, svchp, parmp, comment) +OCIEnv *envhp; +OCIError *errhp; +OCISvcCtx *svchp; +dvoid *parmp; +const text *comment; +{ + sword retval; + text method[MAXNAME], + *namep; + ub4 size; + ub4 num_arg; + ub1 has_result, + is_selfish, + is_virtual, + is_inline, + is_constructor, + is_destructor, + is_constant, + is_operator, + is_map, + is_order, + is_rnds, + is_rnps, + is_wnds, + is_wnps; + OCITypeEncap encap; + dvoid *list_arg; + + /* get name of the method */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &size, + (ub4) OCI_ATTR_NAME, (OCIError *) errhp)); + + (void) strncpy((char *)method, (char *)namep, (size_t) size); + method[size] = '\0'; + + /* get the number of arguments */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &num_arg, (ub4 *) 0, + (ub4) OCI_ATTR_NUM_ARGS, (OCIError *) errhp)); + + /* encapsulation (public?) */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &encap, (ub4 *) 0, + (ub4) OCI_ATTR_ENCAPSULATION, (OCIError *) errhp)); + + /* has result */ + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&has_result, (ub4 *)0, + (ub4)OCI_ATTR_HAS_RESULT, (OCIError *) errhp)); + + /* map method */ + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&is_map, (ub4 *)0, + (ub4)OCI_ATTR_IS_MAP, (OCIError *) errhp)); + + /* order method */ + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&is_order, (ub4 *)0, + (ub4)OCI_ATTR_IS_ORDER, (OCIError *) errhp)); + + /* selfish method */ + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&is_selfish, (ub4 *)0, + (ub4)OCI_ATTR_IS_SELFISH, (OCIError *) errhp)); + + /* virtual method */ + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&is_virtual, (ub4 *)0, + (ub4)OCI_ATTR_IS_VIRTUAL, (OCIError *) errhp)); + + /* inline method */ + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&is_inline, (ub4 *)0, + (ub4)OCI_ATTR_IS_INLINE, (OCIError *) errhp)); + + /* constant method */ + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&is_constant, (ub4 *)0, + (ub4)OCI_ATTR_IS_CONSTANT, (OCIError *) errhp)); + + /* operator */ + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&is_operator, (ub4 *)0, + (ub4)OCI_ATTR_IS_OPERATOR, (OCIError *) errhp)); + + /* constructor method */ + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&is_constructor, (ub4 *)0, + (ub4)OCI_ATTR_IS_CONSTRUCTOR, (OCIError *) errhp)); + + /* destructor method */ + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&is_destructor, (ub4 *)0, + (ub4)OCI_ATTR_IS_DESTRUCTOR, (OCIError *) errhp)); + + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&is_rnds, (ub4 *)0, + (ub4)OCI_ATTR_IS_RNDS, (OCIError *) errhp)); + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&is_rnps, (ub4 *)0, + (ub4)OCI_ATTR_IS_RNPS, (OCIError *) errhp)); + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&is_wnds, (ub4 *)0, + (ub4)OCI_ATTR_IS_WNDS, (OCIError *) errhp)); + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&is_wnps, (ub4 *)0, + (ub4)OCI_ATTR_IS_WNPS, (OCIError *) errhp)); + + /* get list of arguments */ + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&list_arg, (ub4 *)0, + (ub4)OCI_ATTR_LIST_ARGUMENTS, (OCIError *) errhp)); + + SPACING; + printf ( "\n%s\n", comment); + SPACING; + printf ( "Name: %s\n", method); + SPACING; + printf ( "Number of args: %d\n", num_arg); + SPACING; + printf ( "Encapsulation: %s\n", + (encap==OCI_TYPEENCAP_PUBLIC) ? "public" : "private"); + SPACING; + printf ( "Has result: %d\n", has_result); + SPACING; + printf ( "Is selfish: %d\n", is_selfish); + SPACING; + printf ( "Is virtual: %d\n", is_virtual); + SPACING; + printf ( "Is inline: %d\n", is_inline); + SPACING; + printf ( "Is constructor: %d\n", is_constructor); + SPACING; + printf ( "Is desctructor: %d\n", is_destructor); + SPACING; + printf ( "Is constant: %d\n", is_constant); + SPACING; + printf ( "Is operator: %d\n", is_operator); + SPACING; + printf ( "Is map: %d\n", is_map); + SPACING; + printf ( "Is order: %d\n", is_order); + SPACING; + printf ( "Is RNDS: %d\n", is_rnds); + SPACING; + printf ( "Is RNPS: %d\n", is_rnps); + SPACING; + printf ( "Is WNPS: %d\n", is_wnps); + printf("\n"); + + if (has_result) + chk_arg(envhp, errhp, svchp, list_arg, OCI_PTYPE_TYPE_RESULT, 0, 1); + if (num_arg > 0) + chk_arg(envhp, errhp, svchp, list_arg, OCI_PTYPE_TYPE_ARG, 1, num_arg + 1); +} + +/*----------------------------------------------------------------------*/ + +static void chk_arglst(envhp, errhp, svchp, parmp) +OCIEnv *envhp; +OCIError *errhp; +OCISvcCtx *svchp; +dvoid *parmp; +{ + dvoid *arglst; + ub4 numargs; + ub1 ptype; + sword retval; + + /* get list of arguments */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &arglst, (ub4 *) 0, + (ub4) OCI_ATTR_LIST_ARGUMENTS, (OCIError *) errhp)); + + /* get number of parameters */ + checkerr(errhp, OCIAttrGet((dvoid*) arglst, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &numargs, (ub4 *) 0, + (ub4) OCI_ATTR_NUM_PARAMS, (OCIError *) errhp)); + + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &ptype, (ub4 *) 0, + (ub4) OCI_ATTR_PTYPE, (OCIError *) errhp)); + + switch (ptype) + { + case OCI_PTYPE_FUNC: + chk_arg (envhp, errhp, svchp, arglst, OCI_PTYPE_ARG, 0, numargs); + break; + case OCI_PTYPE_PROC: + chk_arg (envhp, errhp, svchp, arglst, OCI_PTYPE_ARG, 1, numargs); + } +} + +/*----------------------------------------------------------------------*/ + +static void chk_arg (envhp, errhp, svchp, parmp, type, start, end) +OCIEnv *envhp; +OCIError *errhp; +OCISvcCtx *svchp; +dvoid *parmp; +ub1 type; +ub4 start; +ub4 end; +{ + text argname[NPOS][30]; + text *namep; + ub4 sizep; + ub2 collen[NPOS]; + ub2 coldesr[NPOS]; + dvoid *parmdp; + ub4 i, pos; + sword retval; + ub2 level[NPOS]; + ub1 radix[NPOS], def[NPOS]; + ub4 iomode[NPOS]; + ub1 precision[NPOS], scale[NPOS], isnull[NPOS]; + + + for (pos = start; pos < end; pos++) + { + + checkerr(errhp, OCIParamGet((dvoid *)parmp, (ub4) OCI_DTYPE_PARAM, errhp, + (dvoid *)&parmdp, (ub4) pos)); + + /* get data type */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &coldesr[pos], (ub4 *) 0, + (ub4) OCI_ATTR_DATA_TYPE, + (OCIError *) errhp)); + + /* method's result has no name */ + iomode[pos] = 0; + def[pos] = 0; + sizep = 0; + if (type != OCI_PTYPE_TYPE_RESULT) + { + /* has default */ + checkerr(errhp, OCIAttrGet((dvoid *)parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&def[pos], (ub4 *)0, + (ub4)OCI_ATTR_HAS_DEFAULT, (OCIError *) errhp)); + + /* get iomode */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &iomode[pos], (ub4 *) 0, + (ub4) OCI_ATTR_IOMODE, (OCIError *) errhp)); + + /* get argument name */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &sizep, + (ub4) OCI_ATTR_NAME, (OCIError *) errhp)); + + (void) strncpy((char *)argname[pos], (char *)namep, (size_t) sizep); + } + argname[pos][sizep] = '\0'; + + /* the following are not for type arguments and results */ + precision[pos] = 0; + scale[pos] = 0; + collen[pos] = 0; + level[pos] = 0; + radix[pos] = 0; + isnull[pos] = FALSE; + if (type != OCI_PTYPE_TYPE_ARG && type != OCI_PTYPE_TYPE_RESULT) + { + /* get the data size */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &collen[pos], (ub4 *) 0, + (ub4) OCI_ATTR_DATA_SIZE, (OCIError *) errhp)); + + /* get the precision of the attribute */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &precision, (ub4 *) 0, + (ub4) OCI_ATTR_PRECISION, (OCIError *) errhp)); + + /* get the scale of the attribute */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &scale, (ub4 *) 0, + (ub4) OCI_ATTR_SCALE, (OCIError *) errhp)); + + /* get the level of the attribute */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &level[pos], (ub4 *) 0, + (ub4) OCI_ATTR_LEVEL, (OCIError *) errhp)); + + /* get the radix of the attribute */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &radix[pos], (ub4 *) 0, + (ub4) OCI_ATTR_RADIX, (OCIError *) errhp)); + + /* is null */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &isnull, (ub4 *) 0, + (ub4) OCI_ATTR_IS_NULL, (OCIError *) errhp)); + + /* should get error 24328 */ + if (OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &isnull, (ub4 *) 0, + (ub4) OCI_ATTR_INDEX_ONLY, (OCIError *) errhp) + != OCI_ERROR) + printf("ERROR: should get error here\n"); + } + } + + SPACING; + (void) printf("Argument Name Length Datatype Level Radix Default Iomode" + " Prec Scl Null\n"); + SPACING; + (void) printf("___________________________________________________" + "______________________\n"); + for (i = start; i < end; i++) + { + SPACING; + (void) printf( "%15s%6d%8d%6d%6d %c%6d%9d%4d%4d\n", argname[i], + collen[i], coldesr[i], level[i], radix[i], + (def[i])?'y':'n', iomode[i], precision[i], scale[i], + isnull[i]); + } + printf("\n"); + +} + +static void chk_collection (envhp, errhp, svchp, parmp, is_array) +OCIEnv *envhp; +OCIError *errhp; +OCISvcCtx *svchp; +dvoid *parmp; +sword is_array; +{ + text schema[MAXNAME], + type[MAXNAME], + *namep; + ub4 size; + ub2 len; + ub4 num_elems; + OCITypeCode typecode; + sword retval; + + /* get the data size */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &len, (ub4 *) 0, + (ub4) OCI_ATTR_DATA_SIZE, (OCIError *) errhp)); + + /* get the name of the collection */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &size, + (ub4) OCI_ATTR_TYPE_NAME, (OCIError *) errhp)); + + (void) strncpy((char *)type, (char *)namep, (size_t) size); + type[size] = '\0'; + + /* get the name of the schema */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &size, + (ub4) OCI_ATTR_SCHEMA_NAME, (OCIError *) errhp)); + + (void) strncpy((char *)schema, (char *)namep, (size_t) size); + schema[size] = '\0'; + + /* get the data type */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &typecode, (ub4 *) 0, (ub4) OCI_ATTR_DATA_TYPE, + (OCIError *) errhp)); + + num_elems = 0; + if (is_array) + /* get the number of elements */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &num_elems, (ub4 *) 0, + (ub4) OCI_ATTR_NUM_ELEMS, (OCIError *) errhp)); + + SPACING; + (void) + printf ( "Schema Type Length Datatype Elements\n"); + SPACING; + (void) + printf ( "____________________________________________________\n"); + SPACING; + (void) printf( "%10s%16s%6d%11d%9d\n", schema, type, len, typecode, + num_elems); + printf("\n"); +} + +/*----------------------------------------------------------------------*/ + +static void chk_column(envhp, errhp, svchp, parmp, parmcnt) +OCIEnv *envhp; +OCIError *errhp; +OCISvcCtx *svchp; +dvoid *parmp; +ub4 parmcnt; +{ + text colname1[NPOS][30], colname2[NPOS][30], colname3[NPOS][30]; + text *namep; + ub4 sizep; + ub2 collen[NPOS]; + ub2 coldesr[NPOS]; + dvoid *parmdp; + ub4 i, pos; + sword retval; + + /* loop through all the attributes in the type and get all information */ + for (pos = 1; pos <= parmcnt; pos++) + { + /* get the parameter list for each attribute */ + checkerr(errhp, OCIParamGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, errhp, + (dvoid *)&parmdp, (ub4) pos)); + + /* size of the attribute (non ADT or REF) objects */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &collen[pos-1], (ub4 *) 0, + (ub4) OCI_ATTR_DATA_SIZE, (OCIError *) errhp)); + + /* name of the attribute */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &sizep, + (ub4) OCI_ATTR_NAME, (OCIError *) errhp)); + + (void) strncpy((char *)colname1[pos-1], (char *)namep, (size_t) sizep); + colname1[pos-1][sizep] = '\0'; + + /* get the schema name */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &sizep, + (ub4) OCI_ATTR_SCHEMA_NAME, (OCIError *) errhp)); + + (void) strncpy((char *)colname2[pos-1], (char *)namep, (size_t) sizep); + colname2[pos-1][sizep] = '\0'; + + /* name of the attribute */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &sizep, + (ub4) OCI_ATTR_TYPE_NAME, (OCIError *) errhp)); + + (void) strncpy((char *)colname3[pos-1], (char *)namep, (size_t) sizep); + colname3[pos-1][sizep] = '\0'; + + /* get data type */ + checkerr(errhp, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &coldesr[pos-1], (ub4 *) 0, + (ub4) OCI_ATTR_DATA_TYPE, + (OCIError *) errhp)); + + if (coldesr[pos-1] == SQLT_NTY || coldesr[pos-1] == SQLT_REF) + { + /* call tst_desc_type here if the type is ADT or REF */ + tab += 5; + SPACING; + printf("!!!!ATTRIBUTE IS A TYPE OR REF!!!!\n"); + SPACING; + printf("ATTRIBUTE NAME IS %s\n", colname3[pos-1]); + SPACING; + printf("ATTRIBUTE TYPE IS %d\n", coldesr[pos-1]); + tst_desc_type(envhp, errhp, svchp, colname3[pos-1]); + tab -= 5; + printf("\n"); + } + + } + + SPACING; + (void) + printf ( "Column Name Schema Type Length Datatype\n"); + SPACING; + (void) + printf ( "__________________________________________________________\n"); + for (i = 1; i <= parmcnt; i++) + { + SPACING; + (void) printf( "%15s%10s%16s%6d%8d\n", colname1[i-1], colname2[i-1], + colname3[i-1], collen[i-1], coldesr[i-1] ); + } + printf("\n"); +} + +/*----------------------------------------------------------------------*/ + +static void tst_desc_type(envhp, errhp, svchp, objname) +OCIEnv *envhp; +OCIError *errhp; +OCISvcCtx *svchp; +text *objname; +{ + OCIDescribe *dschp = (OCIDescribe *) 0; + sword retval; + OCITypeCode typecode, + collection_typecode; + text schema[MAXNAME], + version[MAXNAME], + *namep, + *type_name; + ub4 size, + text_len; + OCIRef *type_ref; + ub2 num_attr, + num_method; + ub1 is_incomplete, + is_system, + is_predefined, + is_transient, + is_sysgen, + has_table, + has_lob, + has_file; + dvoid *list_attr, + *list_method, + *map_method, + *order_method, + *collection_dschp, + *some_object; + OCIParam *parmp; + ub1 objtype; + + /* must allocate describe handle first for OCIDescribeAny */ + checkerr(errhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **) &dschp, + (ub4) OCI_HTYPE_DESCRIBE, + (size_t) 0, (dvoid **) 0)); + + /* call OCIDescribeAny and passing in the type name */ + checkerr(errhp, OCIDescribeAny(svchp, errhp, (text *)objname, + (ub4) strlen((char *)objname), OCI_OTYPE_NAME, (ub1)1, + (ub1) OCI_PTYPE_TYPE, dschp)); + + /* get the parameter list for the requested type */ + checkerr(errhp, OCIAttrGet((dvoid *) dschp, (ub4) OCI_HTYPE_DESCRIBE, + (dvoid *)&parmp, (ub4 *)0, (ub4)OCI_ATTR_PARAM, errhp)); + + /* get the schema name for the requested type */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp,(ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &size, + (ub4) OCI_ATTR_SCHEMA_NAME, (OCIError *) errhp)); + + (void) strncpy((char *)schema, (char *)namep, (size_t) size); + schema[size] = '\0'; + + /* get the type code for the requested type */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &typecode, (ub4 *) 0, + (ub4) OCI_ATTR_TYPECODE, (OCIError *) errhp)); + + /* get other information for collection type */ + if (typecode == OCI_TYPECODE_NAMEDCOLLECTION) + { + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&collection_typecode, (ub4 *)0, + (ub4)OCI_ATTR_COLLECTION_TYPECODE, (OCIError *)errhp)); + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&collection_dschp, (ub4 *)0, + (ub4)OCI_ATTR_COLLECTION_ELEMENT, (OCIError *)errhp)); + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&collection_dschp, (ub4 *)0, + (ub4)OCI_ATTR_COLLECTION_ELEMENT, (OCIError *)errhp)); + } + + /* get the ref to the type descriptor */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &type_ref, (ub4 *) 0, + (ub4) OCI_ATTR_REF_TDO, (OCIError *) errhp)); + + /* get the type version */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &namep, (ub4 *) &size, + (ub4) OCI_ATTR_VERSION, (OCIError *) errhp)); + + (void) strncpy((char *)version, (char *)namep, (size_t) size); + version[size] = '\0'; + + /* incomplete type */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &is_incomplete, (ub4 *) 0, + (ub4) OCI_ATTR_IS_INCOMPLETE_TYPE, (OCIError *) errhp)); + + /* system type */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &is_system, (ub4 *) 0, + (ub4) OCI_ATTR_IS_SYSTEM_TYPE, (OCIError *) errhp)); + + /* predefined type */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &is_predefined, (ub4 *) 0, + (ub4) OCI_ATTR_IS_PREDEFINED_TYPE, (OCIError *) errhp)); + + /* transient type */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &is_transient, (ub4 *) 0, + (ub4) OCI_ATTR_IS_TRANSIENT_TYPE, (OCIError *) errhp)); + + /* system generated type */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &is_sysgen, (ub4 *) 0, + (ub4) OCI_ATTR_IS_SYSTEM_GENERATED_TYPE, (OCIError*) errhp)); + + /* has nested table */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &has_table, (ub4 *) 0, + (ub4) OCI_ATTR_HAS_NESTED_TABLE, (OCIError *) errhp)); + + /* has lob */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &has_lob, (ub4 *) 0, + (ub4) OCI_ATTR_HAS_LOB, (OCIError *) errhp)); + + /* has file */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &has_file, (ub4 *) 0, + (ub4) OCI_ATTR_HAS_FILE, (OCIError *) errhp)); + + /* get the list of attributes */ + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&list_attr, (ub4 *)0, + (ub4)OCI_ATTR_LIST_TYPE_ATTRS, (OCIError *)errhp)); + + /* number of attributes */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &num_attr, (ub4 *) 0, + (ub4) OCI_ATTR_NUM_TYPE_ATTRS, (OCIError *) errhp)); + + /* get method list */ + checkerr(errhp, OCIAttrGet((dvoid *) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid *)&list_method, (ub4 *)0, + (ub4)OCI_ATTR_LIST_TYPE_METHODS, (OCIError *)errhp)); + + /* get number of methods */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &num_method, (ub4 *) 0, + (ub4) OCI_ATTR_NUM_TYPE_METHODS, (OCIError *) errhp)); + + /* get map method list */ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &map_method, (ub4 *) 0, + (ub4) OCI_ATTR_MAP_METHOD, (OCIError *) errhp)); + + /* get order method list*/ + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &order_method, (ub4 *) 0, + (ub4) OCI_ATTR_ORDER_METHOD, (OCIError *) errhp)); + + SPACING; + printf ( "TYPE : Attributes : \n"); + SPACING; + printf ( "Schema: %s\n", schema); + SPACING; + printf ( "Typecode: %d\n", typecode); + if (typecode == OCI_TYPECODE_NAMEDCOLLECTION) + { + SPACING; + printf ( "Collection typecode: %d\n", collection_typecode); + } + SPACING; + printf ( "Version: %s\n", version); + SPACING; + printf ( "Number of attrs: %d\n", num_attr); + SPACING; + printf ( "Number of methods: %d\n", num_method); + SPACING; + printf ( "Is incomplete: %d\n", is_incomplete); + SPACING; + printf ( "Is system: %d\n", is_system); + SPACING; + printf ( "Is predefined: %d\n", is_predefined); + SPACING; + printf ( "Is sys-gen: %d\n", is_sysgen); + SPACING; + printf ( "Is transient: %d\n", is_transient); + SPACING; + printf ( "Has nested table: %d\n", has_table); + SPACING; + printf ( "Has LOB: %d\n", has_lob); + SPACING; + printf ( "Has file: %d\n", has_file); + printf("\n"); + + if (num_attr > 0) + chk_column(envhp, errhp, svchp, list_attr, num_attr); + else if (typecode == OCI_TYPECODE_NAMEDCOLLECTION) + chk_collection(envhp, errhp, svchp, collection_dschp, + collection_typecode == OCI_TYPECODE_VARRAY); + if (map_method != (dvoid *)0) + chk_method(envhp, errhp, svchp, map_method, + "TYPE MAP METHOD\n---------------"); + if (order_method != (dvoid *)0) + chk_method(envhp, errhp, svchp, order_method, + "TYPE ORDER METHOD\n-----------------"); + if (num_method > 0) + chk_methodlst(envhp, errhp, svchp, list_method, num_method, + "TYPE METHOD\n-----------"); +} + + +/*****************************************************************************/ +int main(int argc, char *argv[]) +{ + OCIEnv *envhp = (OCIEnv *) 0; + OCIServer *srvhp = (OCIServer *) 0; + OCIError *errhp = (OCIError *) 0; + OCISvcCtx *svchp = (OCISvcCtx *) 0; + OCISession *usrhp = (OCISession *) 0; + dvoid *tmp; + int i; + + tab = 0; + + if (argc < 4) + { + (void) printf( + "Usage -- cdemort \n"); + return (0); + } + + (void) OCIInitialize((ub4) OCI_THREADED | OCI_OBJECT, + (dvoid *)0, (dvoid * (*)()) 0, + (dvoid * (*)()) 0, (void (*)()) 0 ); + + (void) OCIHandleAlloc( (dvoid *) NULL, (dvoid **) &envhp, + (ub4) OCI_HTYPE_ENV, + 52, (dvoid **) &tmp); + + (void) OCIEnvInit( &envhp, (ub4) OCI_DEFAULT, 21, (dvoid **) &tmp ); + + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, + 52, (dvoid **) &tmp); + + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, + 52, (dvoid **) &tmp); + + checkerr(errhp, OCIServerAttach( srvhp, errhp, (text *) "", + (sb4) strlen(""), (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, + 52, (dvoid **) &tmp)); + + checkerr(errhp, OCIAttrSet( (dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, + (ub4) OCI_ATTR_SERVER, (OCIError *) errhp)); + + checkerr(errhp, OCIHandleAlloc((dvoid *)envhp, (dvoid **)&usrhp, + (ub4)OCI_HTYPE_SESSION, 0, (dvoid **)0)); + + checkerr(errhp, OCIAttrSet((dvoid *) usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)argv[1], (ub4)strlen(argv[1]), + (ub4)OCI_ATTR_USERNAME, errhp)); + + checkerr(errhp, OCIAttrSet((dvoid *) usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)argv[2], (ub4)strlen(argv[2]), + (ub4)OCI_ATTR_PASSWORD, errhp)); + + checkerr(errhp, OCISessionBegin (svchp, errhp, usrhp, + OCI_CRED_RDBMS, OCI_DEFAULT)); + + checkerr(errhp, OCIAttrSet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)usrhp, (ub4)0, + (ub4)OCI_ATTR_SESSION, errhp)); + + /* dump an adt with all the types */ + SPACING; + (void) printf("%s\n", argv[3]); + tst_desc_type(envhp, errhp, svchp, argv[3]); + printf("\n"); + + checkerr(errhp, OCISessionEnd (svchp, errhp, usrhp, OCI_DEFAULT)); + + (void) OCIServerDetach( srvhp, errhp, (ub4) OCI_DEFAULT ); + + checkerr(errhp, OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX)); + checkerr(errhp, OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR)); + checkerr(errhp, OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER)); + + return (0); +} + + +/* end of file cdemodsc.c */ + diff --git a/cdemodsc.h b/cdemodsc.h new file mode 100644 index 0000000..e9b3b48 --- /dev/null +++ b/cdemodsc.h @@ -0,0 +1,109 @@ +/* + * $Header: cdemodsc.h 23-jun-2004.17:12:05 aliu Exp $ + */ + +/* Copyright (c) 1997, 2004, Oracle. All rights reserved. +*/ + +/* NOTE: See 'header_template.doc' in the 'doc' dve under the 'forms' + directory for the header file template that includes instructions. +*/ + +/* + NAME + cdemodsc.h - header file for cdemodsc.c + + DESCRIPTION + This file will contain the header information for the cdemodsc.c + + RELATED DOCUMENTS + + INSPECTION STATUS + Inspection date: + Inspection status: + Estimated increasing cost defects per page: + Rule sets: + + ACCEPTANCE REVIEW STATUS + Review date: + Review status: + Reviewers: + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + EXAMPLES + + NOTES + + + MODIFIED (MM/DD/YY) + aliu 06/23/04 - fix lrg 1712708 - include header files + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 09/09/98 - lines longer than 79 chars reformatted - bug 722491 + echen 06/04/97 - fix the include files + cchau 05/29/97 - Creation. +*/ + +/*----------------------------------------------------------------------*/ +#ifndef CDEMODSC +#define CDEMODSC + +#ifndef STDIO +#include +#endif + +#ifndef STDLIB +#include +#endif + +#ifndef STRING +#include +#endif + +#ifndef OCI_ORACLE +#include +#endif + +/*----------------------------------------------------------------------*/ +/* +** #define +*/ + +#define MAXNAME 30 +#define MAXOBJLEN 60 +#define MAXOBJS 7 +#define NPOS 40 +#define SPACING for (glindex = 0; glindex < tab; glindex++)\ + printf(" ") + +/*----------------------------------------------------------------------*/ +/* +** Prototypes for functions in cdemodsc.c +*/ +static void chk_column(/*_ OCIEnv *envhp, OCIError *errhp, + OCISvcCtx *svchp, dvoid *dschp, ub4 parmcnt _*/); +static void chk_method(/*_ OCIEnv *envhp, OCIError *errhp, + OCISvcCtx *svchp, dvoid *dschp, const text *comment _*/); +static void chk_methodlst(/*_ OCIEnv *envhp, OCIError *errhp, + OCISvcCtx *svchp, dvoid *dschp, ub4 count, const text *comment _*/); +static void chk_arglst(/*_ OCIEnv *envhp, OCIError *errhp, + OCISvcCtx *svchp, dvoid *dschp _*/); +static void chk_arg(/*_ OCIEnv *envhp, OCIError *errhp, OCISvcCtx *svchp, + dvoid *dschp, ub1 type, ub4 start, ub4 end _*/); +static void chk_collection (/*_ OCIEnv *envhp, OCIError *errhp, + OCISvcCtx *svchp, dvoid *dschp, sword is_array _*/); +static void tst_desc_type(/*_ OCIEnv *envhp, OCIError *errhp, + OCISvcCtx *svchp, text *objname _*/); +static void checkerr(/*_ OCIError *errhp, sword status _*/); + +/* Prototype for main function */ +int main(/*_ int argc, char *argv[] _*/); +int tab; +int glindex; + +#endif /* CDEMODSC */ + diff --git a/cdemodt.c b/cdemodt.c new file mode 100644 index 0000000..5972237 --- /dev/null +++ b/cdemodt.c @@ -0,0 +1,1225 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemodt.c 10-oct-2006.14:39:59 azhao Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 2001, 2006, Oracle. All rights reserved. +*/ + +/* + + NAME + cdemodt.c - Datetime/Interval type demo program in OCI + + DESCRIPTION - Demonstrate insertion and selection of timestamp, timestamp + with time zone, timestamp with local time zone, interval year + to month, and interval day to seconds via Bind and Define with + SQL statements. + Demonstrate IN/OUT bind with PL/SQL procedure. + Demonstrate how time zone names work and daylight saving features + using OCIDateTimeConvert() on different values of timestamp with + time zone region. + Demonstrate how daylight saving works with time zone names when + time changes from daylight saving time to standard time or vice + verse using OCIDateTimeIntervalAdd(). + + Note: Before running this program, ensure that the database is started + up with compatible=9.0.0.0.0 and a table CDEMODT_FOO or a procedure + CDEMODT_INS_SEL does not exist in the SCOTT/TIGER sample account. + + + MODIFIED (MM/DD/YY) + azhao 10/10/06 - case-senstive password change + aliu 06/27/01 - Change table and procedure names to be free of conflict with other tests. + aliu 06/12/01 - Fix porting bug 1827600. + aliu 04/24/01 - Merged aliu_dt_demo_oci + aliu 04/24/01 - Modify variable names and main prototype. + aliu 04/23/01 - Update lint warnings. + aliu 04/12/00 - Creation + +*/ + +#ifndef CDEMOXML +#define CDEMOXML + +/*------------------------------------------------------------------------ + * Include Files + */ + +#ifndef STDIO +#include +#endif + +#ifndef STDLIB +#include +#endif + +#ifndef STRING +#include +#endif + +#ifndef OCI_ORACLE +#include +#endif + +/*----------------- End of including files -----------------*/ + +/*--------------------- Public Constants and Variables ----------------------*/ + +/* constants */ +#define MAXDATELEN 64 +#define COLNUM 6 + +/* database login information */ +static OraText *user=(OraText *)"SCOTT"; +static OraText *password=(OraText *)"tiger"; + +/* OCI Handles and Variables */ +static OCIEnv *envhp; +static OCIServer *srvhp; +static OCISvcCtx *svchp; +static OCIError *errhp; +static OCISession *authp; +static OCIBind *bndhp[COLNUM] = { (OCIBind *)0, (OCIBind *)0, (OCIBind *)0, + (OCIBind *)0, (OCIBind *)0, (OCIBind *)0 }; +static OCIDefine *defhp[COLNUM] = { (OCIDefine *)0, (OCIDefine *)0, (OCIDefine *)0, + (OCIDefine *)0, (OCIDefine *)0, (OCIDefine *)0 }; +static OCIStmt *stmthp = (OCIStmt *) 0; + +/* Misellaneous */ +static boolean ret = FALSE; +static boolean tab_exists = FALSE; +static boolean proc_exists = FALSE; +static ub2 sqlt[COLNUM] = {SQLT_TIMESTAMP, SQLT_TIMESTAMP_TZ, SQLT_TIMESTAMP_LTZ, + SQLT_INTERVAL_YM, SQLT_INTERVAL_DS, SQLT_INT}; +static ub4 ocit[COLNUM-1] = { OCI_DTYPE_TIMESTAMP, OCI_DTYPE_TIMESTAMP_TZ, + OCI_DTYPE_TIMESTAMP_LTZ, OCI_DTYPE_INTERVAL_YM, + OCI_DTYPE_INTERVAL_DS }; + +/*----------------- End of Constants and Variables -----------------*/ + +/*--------------------- Functions Declaration --------------------*/ + +int main(/*_ int argc, char *argv[] _*/); +static sb4 add_interval(/* OraText *dt, OraText *interval, OraText *fmt, ub4 type1, ub4 type2 _*/); +static sb4 alloc_desc(/*_ OCIDateTime *dvar[], OCIInterval *ivar[], sword size1, sword size2 _*/); +static void chk_err(/*_ OCIError *errhp, boolean ec, sb2 linenum, OraText *comment _*/); +static void cleanup(/*_ void _*/); +static sb4 connect_server(/*_ OraText *cstring _*/); +static sb4 conv_dt(/*_ OraText *str1, ub4 type1, ub4 type2, OraText *fmt1, + OraText *fmt2, OraText *name1, OraText *name2 _*/); +static void disconnect_server(/*_ void _*/); +static sb4 exe_insert(/*_ OraText *insstmt, OraText *strdate[COLNUM-1], + OraText *fmtdate[3], OCIDateTime *dvar[], OCIInterval *ivar[], size_t rownum_*/); +static sb4 exe_sql(/*_ OraText *stmt _*/); +static sb4 free_desc(/*_ OCIDateTime *dvar[], OCIInterval *ivar[], sword size1, sword size2 _*/); +static sb4 init_env_handle(/*_ void _*/); +static sb4 init_sql(/*_ void _*/); +static sb4 insert_dt(/*_ size_t rownum _*/); +static sb4 io_proc(/*_ _*/); +static sb4 select_dt(/*_ size_t rownum _*/); +static sb4 set_sdtz(); +static sb4 tzds_1(); +static sb4 tzds_2(); + +/*--------------------- End of Functions Declaration --------------------*/ + +#endif + + +/*---------------------------Main function -----------------------------*/ +int main(argc, argv) +int argc; +char *argv[]; +{ + OraText cstring[50]; + size_t rownum = 1; + + memset((void *)cstring, '\0', 50); + + if (argc > 1 && strncmp((char *) "remote", (char *)argv[1], 6) == 0) + { + strcpy((char *)cstring, "inst1_alias"); + } + + /* Initialize the environment and allocate handles */ + if (init_env_handle()) + { + printf("FAILED: init_env_handle()!\n"); + return OCI_ERROR; + } + + /* Log on to the server and begin a session */ + if (connect_server(cstring)) + { + printf("FAILED: connect_server()!\n"); + cleanup(); + return OCI_ERROR; + } + + /* Initialize the demo table and PL/SQL procedure */ + if (init_sql()) + { + printf("FAILED: init_sql()\n"); + disconnect_server(); + return OCI_ERROR; + } + + /* Set the session datetime zone */ + if (set_sdtz()) + { + printf("FAILED: set_sdtz()\n"); + disconnect_server(); + return OCI_ERROR; + } + + rownum = 1; + /* Insertion via SQL statement */ + if (insert_dt(rownum)) + { + printf("FAILED: insert_dt()!\n"); + disconnect_server(); + return OCI_ERROR; + } + + /* Selection via SQL statement */ + if (select_dt(rownum)) + { + printf("FAILED: select_dt()!\n"); + disconnect_server(); + return OCI_ERROR; + } + + /* An example on IN/OUT BIND in PL/SQL procedure */ + if (io_proc()) + { + printf("FAILED: io_proc()!\n"); + disconnect_server(); + return OCI_ERROR; + } + + /* An example on time zone name and daylight saving using OCIDateTimeConvert() */ + if (tzds_1()) + { + printf("FAILED: tzds_1()!\n"); + disconnect_server(); + return OCI_ERROR; + } + + /* An example on time zone name and daylight saving using OCIDateTimeIntervalAdd() */ + if (tzds_2()) + { + printf("FAILED: tzds_2()!\n"); + disconnect_server(); + return OCI_ERROR; + } + + /* Detach from a server and clean up the environment */ + disconnect_server(); + + return OCI_SUCCESS; +} + + +/*---------------------------Subfunctions -----------------------------*/ + +/*--------------------------------------------------------*/ +/* Add an interval to a datetime */ +/*--------------------------------------------------------*/ +sb4 add_interval(dt, interval, fmt, type1, type2) +OraText *dt, *interval, *fmt; +ub4 type1, type2; +{ + OCIDateTime *var1, *result; + OCIInterval *var2; + OraText *str, *fmt2; + ub4 buflen; + + /* Initialize the output string */ + str = (OraText *)malloc(MAXDATELEN); + memset ((void *) str, '\0', MAXDATELEN); + fmt2 = (OraText *)malloc(MAXDATELEN); + memset ((void *) fmt2, '\0', MAXDATELEN); + + /* Allocate descriptors */ + if (ret = OCIDescriptorAlloc((dvoid *)envhp,(dvoid **)&var1, type1, + 0, (dvoid **) 0) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIDescriptorAlloc"); + return OCI_ERROR; + } + if (ret = OCIDescriptorAlloc((dvoid *)envhp,(dvoid **)&result, type1, + 0, (dvoid **) 0) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIDescriptorAlloc"); + return OCI_ERROR; + } + if (ret = OCIDescriptorAlloc((dvoid *)envhp,(dvoid **)&var2, type2, + 0,(dvoid **)0) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIDescriptorAlloc"); + return OCI_ERROR; + } + + /* Change to datetime type format */ + if (ret = OCIDateTimeFromText((dvoid *)authp,errhp,(CONST OraText *)dt, + (ub4) strlen((char *)dt), (CONST OraText *)fmt, + (ub1) strlen((char *)fmt),(CONST OraText *)0,0, var1) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIDateTimeFromText"); + return OCI_ERROR; + } + /* Change to interval type format */ + if ((ret = OCIIntervalFromText((dvoid *)authp, errhp,(CONST OraText *)interval, + (ub4) strlen((char *)interval), + (OCIInterval *)var2)) != OCI_SUCCESS) { + chk_err(errhp, ret, __LINE__,(OraText *)"OCIIntervalFromText"); + return OCI_ERROR; + } + + /* Add the interval to datetime */ + if (ret = OCIDateTimeIntervalAdd(envhp, errhp, var1, var2, result) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIDateTimeIntervalAdd"); + return OCI_ERROR; + } + + buflen = MAXDATELEN; + + /* Change the result to text format */ + strcpy((char *)fmt2,"DD-MON-RR HH.MI.SSXFF AM TZR TZD"); + if (ret = OCIDateTimeToText((dvoid *)authp,errhp,(CONST OCIDateTime *)result, + (CONST OraText *)fmt2,(ub1)strlen((char *)fmt2),(ub1) 2, + (CONST OraText *) NULL, + (ub4)0, (ub4 *) &buflen, (OraText *) str) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIDateTimeToText"); + return OCI_ERROR; + } + + printf("( %s ) + ( %s ) --->\n\t%s\n\n", dt, interval, str); + + /* Free the descriptors */ + if (var1) { + OCIDescriptorFree((dvoid *) var1, (ub4) type1); + } + if (result) { + OCIDescriptorFree((dvoid *) result, (ub4) type1); + } + if (var2) { + OCIDescriptorFree((dvoid *) var2, (ub4) type2); + } + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* Allocate descriptors */ +/*--------------------------------------------------------*/ +sb4 alloc_desc(dvar, ivar, size1, size2) +OCIDateTime *dvar[]; +OCIInterval *ivar[]; +sword size1, size2; +{ + sword i; + + /* allocate datetime and interval descriptors */ + for (i=0; i %s:\n", name1, name2); + printf("\t%s ---> %s\n\n", str1, str2); + + /* Free the descriptors */ + if (var1) { + OCIDescriptorFree((dvoid *) var1, (ub4) type1); + } + if (var2) { + OCIDescriptorFree((dvoid *) var2, (ub4) type2); + } + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* End the session, detach server and free environmental handles. */ +/*--------------------------------------------------------*/ +void disconnect_server() +{ + printf("\n\nLogged off and detached from server.\n"); + + /* Drop the demo table and procedure if any */ + if (tab_exists) + exe_sql((OraText *)"drop table cdemodt_foo"); + if (proc_exists) + exe_sql((OraText *)"drop procedure cdemodt_ins_sel"); + + /* End a session */ + if (ret = OCISessionEnd((OCISvcCtx *)svchp, (OCIError *)errhp, + (OCISession *)authp, (ub4) OCI_DEFAULT)) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCISessionEnd"); + cleanup(); + return; + } + + /* Detach from the server */ + if (ret = OCIServerDetach((OCIServer *)srvhp, (OCIError *)errhp, + (ub4)OCI_DEFAULT)) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIServerDetach"); + cleanup(); + return; + } + + /* Free the handles */ + if (stmthp) { + OCIHandleFree((dvoid *)stmthp, (ub4) OCI_HTYPE_STMT); + } + if (authp) { + OCIHandleFree((dvoid *)authp, (ub4) OCI_HTYPE_SESSION); + } + if (svchp) { + OCIHandleFree((dvoid *)svchp, (ub4) OCI_HTYPE_SVCCTX); + } + if (srvhp) { + OCIHandleFree((dvoid *)srvhp, (ub4) OCI_HTYPE_SERVER); + } + if (errhp) { + OCIHandleFree((dvoid *)errhp, (ub4) OCI_HTYPE_ERROR); + } + if (envhp) { + OCIHandleFree((dvoid *)envhp, (ub4) OCI_HTYPE_ENV); + } + + return; +} + + +/*--------------------------------------------------------*/ +/* Execute the insertion */ +/*--------------------------------------------------------*/ +sb4 exe_insert(insstmt, strdate, fmtdate, dvar, ivar, rownum) +OraText *insstmt, *strdate[COLNUM-1], *fmtdate[3]; +OCIDateTime *dvar[3]; +OCIInterval *ivar[2]; +size_t rownum; +{ + sword i; + size_t colc = rownum; + + /* Converts the text strings to the datetime types in the table */ + for (i=0; i<3; i++) { + if (ret = OCIDateTimeFromText(authp,errhp,(CONST OraText *)strdate[i], + (ub4) strlen((char *)strdate[i]),(CONST OraText *) fmtdate[i], + (ub1) strlen((char *)fmtdate[i]),(OraText *) NULL,(ub4) 0,dvar[i])) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIDateFromText"); + return OCI_ERROR; + } + } + + /* Converts the text strings to the interval types in the table */ + for (i=0; i<2; i++) { + if ((ret = OCIIntervalFromText((dvoid *)authp, errhp,(CONST OraText *) + strdate[i+3], (ub4) strlen((char *)strdate[i+3]), + (OCIInterval *)ivar[i])) != OCI_SUCCESS) { + chk_err(errhp, ret, __LINE__,(OraText *)"OCIIntervalFromText"); + return OCI_ERROR; + } + } + + /* Preparation of statment handle for the SQL statement */ + if ((ret = OCIStmtPrepare(stmthp, errhp, insstmt, (ub4)strlen((char *)insstmt), OCI_NTV_SYNTAX, + OCI_DEFAULT)) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIStmtPrepare"); + return OCI_ERROR; + } + + /* Binds the input variable */ + for (i=0; i<3; i++) { + if ((ret = OCIBindByPos(stmthp,&bndhp[i],errhp,i+1,(dvoid *)&dvar[i], + (sb4) sizeof(OCIDateTime *), sqlt[i], (dvoid *)0, + (ub2 *) 0,(ub2 *) 0,(ub4) 0,(ub4 *)0,OCI_DEFAULT)) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIBindByPos"); + return OCI_ERROR; + } + } + for (i=0; i<2; i++) { + if ((ret = OCIBindByPos(stmthp,&bndhp[i+3],errhp,i+4,(dvoid *)&ivar[i], + (sb4) sizeof(OCIInterval *), sqlt[i+3], (dvoid *)0, + (ub2 *) 0,(ub2 *) 0,(ub4) 0,(ub4 *)0,OCI_DEFAULT)) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIBindByPos"); + return OCI_ERROR; + } + } + if ((ret = OCIBindByPos(stmthp,&bndhp[5],errhp,6,(dvoid *)&colc, + (sb4) sizeof(colc), sqlt[5], (dvoid *)0, + (ub2 *) 0,(ub2 *) 0,(ub4) 0,(ub4 *)0,OCI_DEFAULT)) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIBindByPos"); + return OCI_ERROR; + } + + /* Executing the SQL statement */ + if ((ret = OCIStmtExecute(svchp, stmthp, errhp, 1, 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, OCI_DEFAULT)) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIStmtExecute"); + return OCI_ERROR; + } + + printf("Values inserted\n\n"); + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* Execute a sql statement */ +/*--------------------------------------------------------*/ +sb4 exe_sql(stmt) +OraText *stmt; +{ + /* prepare statement */ + if (ret = OCIStmtPrepare(stmthp, errhp, stmt, (ub4) strlen((char *) stmt), (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIStmtPrepare"); + return OCI_ERROR; + } + /* execute statement */ + if (ret = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) 0, (OCISnapshot *) 0, + (ub4) OCI_DEFAULT)) + { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIStmtExecute"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* Free the descriptors */ +/*--------------------------------------------------------*/ +sb4 free_desc(dvar, ivar, size1, size2) +OCIDateTime *dvar[]; +OCIInterval *ivar[]; +sword size1, size2; +{ + sword i; + + /* Free the descriptors */ + for (i=0; iInsertion via SQL statement\n\n"); + /* execute the insertion */ + if (exe_insert(insstmt, strdate, fmtdate, dvar, ivar, rownum)) { + printf("FAILED: exe_insert()!\n"); + return OCI_ERROR; + } + + /* Free the descriptors */ + if (free_desc(dvar, ivar, 3, 2)) { + printf("FAILED: free_desc()!\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* Insert/Select via In/Out Bind */ +/*--------------------------------------------------------*/ +sb4 io_proc() +{ + sword i; + size_t rownum = 1; + OCIDateTime *dvar[3]; + OCIInterval *ivar[2]; + ub4 str_size[COLNUM-1]; + size_t resultlen; + OraText *strdate[COLNUM-1]; + OraText *fmtdate[3]; + OraText *sqlstmt = (OraText *)"BEGIN CDEMODT_INS_SEL(:1, :2, :3, :4, :5, :6); END; "; + + /* Initialize strings */ + for (i=0; iInsertion and Selection via PL/SQL procedure\n\n"); + + strcpy((char *)strdate[0],"1999-12-01 01:30:10"); + strcpy((char *)strdate[1],"1999-12-01 01:30:10 US/Pacific PST"); + strcpy((char *)strdate[2],"1999-12-01 01:30:10"); + strcpy((char *)strdate[3],"02-03"); + strcpy((char *)strdate[4],"2 03:03:03.09"); + strcpy((char *)fmtdate[0],"YYYY-MM-DD HH24:MI:SS"); + strcpy((char *)fmtdate[1],"YYYY-MM-DD HH24:MI:SS TZR TZD"); + strcpy((char *)fmtdate[2],"YYYY-MM-DD HH24:MI:SS"); + + /* allocate datetime and interval descriptors */ + if (alloc_desc(dvar, ivar, 3, 2)) { + printf("FAILED: alloc_desc()!\n"); + return OCI_ERROR; + } + + /* execute the statement */ + if (exe_insert(sqlstmt, strdate, fmtdate, dvar, ivar, rownum)) { + printf("FAILED: exe_insert()!\n"); + return OCI_ERROR; + } + + /* Convert to text format */ + printf("Values selected:\n"); + for (i=0; i<3; i++) { + str_size[i] = MAXDATELEN; + if ((ret = OCIDateTimeToText(authp, errhp, dvar[i], (OraText*)fmtdate[i], + (ub1) strlen((char *)fmtdate[i]), (ub1) 2, (OraText*)0, 0, + &str_size[i], (OraText*)strdate[i])) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIDateTimeToText"); + return OCI_ERROR; + } + printf("Column %d: %s\n", i+1, strdate[i]); + } + for (i=0; i<2; i++) { + str_size[i+3] = MAXDATELEN; + if ((ret = OCIIntervalToText(envhp, errhp, ivar[i], (ub1) 3, (ub1)2, + strdate[i+3],str_size[i+3],(size_t *)&resultlen)) != 0) { + chk_err(errhp, ret, __LINE__,(OraText *)"Error in OCIIntervalToText"); + return OCI_ERROR; + } + printf("Column %d: %s\n", i+4, strdate[i+3]); + } + printf("Column 6: %d\n\n", rownum); + + /* Free the descriptors */ + if (free_desc(dvar, ivar, 3, 2)) { + printf("FAILED: free_desc()!\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* Select datetime/interval values from the table */ +/*--------------------------------------------------------*/ +sb4 select_dt(rownum) +size_t rownum; +{ + sword i, var6; + size_t colc = rownum; + OraText *strdate[COLNUM-1]; + OraText *fmtdate[3]; + ub4 str_size[COLNUM-1]; + size_t resultlen; + OCIDateTime *dvar[3]; + OCIInterval *ivar[2]; + OraText *selstmt = (OraText *) "SELECT * FROM CDEMODT_FOO WHERE int = :1"; + + /* Initialize strings */ + for (i=0; iSelection via SQL statement\n\n"); + /* Preparation of statment handle for the SQL statement */ + if ((ret = OCIStmtPrepare(stmthp, errhp, selstmt, (ub4)strlen((char *)selstmt), OCI_NTV_SYNTAX, + OCI_DEFAULT)) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIStmtPrepare"); + return OCI_ERROR; + } + + /* associate variable colc with bind placeholder in the SQL statement */ + if ((ret = OCIBindByPos(stmthp, &bndhp[0], errhp, 1, &colc, sizeof(colc), + SQLT_INT,(void *)0, (ub2 *)0,(ub2 *)0, 0, (ub4 *)0, OCI_DEFAULT)) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIBindByPos"); + return OCI_ERROR; + } + + /* Defining the positions for the variables */ + for (i=0; i<3; i++) { + if ((ret = OCIDefineByPos(stmthp, &defhp[i], errhp, i+1, &dvar[i], sizeof(dvar[i]), + sqlt[i], (void *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT)) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIDefineByPos"); + return OCI_ERROR; + } + } + for (i=0; i<2; i++) { + if ((ret = OCIDefineByPos(stmthp, &defhp[i+3], errhp, i+4, &ivar[i], sizeof(ivar[i]), + sqlt[i+3], (void *)0,(ub2 *)0, (ub2 *)0, OCI_DEFAULT)) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIDefineByPos"); + return OCI_ERROR; + } + } + if ((ret = OCIDefineByPos(stmthp, &defhp[5], errhp, 6, &var6, sizeof(var6), + sqlt[5], (void *)0, (ub2 *)0,(ub2 *)0, OCI_DEFAULT)) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIDefineByPos"); + return OCI_ERROR; + } + + /* Executing the SQL statement */ + if ((ret = OCIStmtExecute(svchp, stmthp, errhp, 1, 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, OCI_DEFAULT)) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIStmtExecute"); + return OCI_ERROR; + } + + /* Convert to text format */ + printf("Values selected:\n"); + for (i=0; i<3; i++) { + str_size[i] = MAXDATELEN; + if ((ret = OCIDateTimeToText(authp, errhp, dvar[i], (OraText*)fmtdate[i], + (ub1) strlen((char *)fmtdate[i]), (ub1) 2, (OraText*)0,(size_t)0, + &str_size[i], (OraText*)strdate[i])) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIDateTimeToText"); + return OCI_ERROR; + } + printf("Column %d: %s\n", i+1, strdate[i]); + } + for (i=0; i<2; i++) { + str_size[i+3] = MAXDATELEN; + if ((ret = OCIIntervalToText(envhp, errhp, ivar[i], (ub1) 3, (ub1)2, + strdate[i+3],str_size[i+3],(size_t *)&resultlen)) != 0) { + chk_err(errhp, ret, __LINE__, (OraText *)"Error in OCIIntervalToText"); + return OCI_ERROR; + } + printf("Column %d: %s\n", i+4, strdate[i+3]); + } + printf("Column 6: %d\n\n", var6); + + /* Free the descriptors */ + if (free_desc(dvar, ivar, 3, 2)) { + printf("FAILED: free_desc()!\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* Set session datetime zone */ +/*--------------------------------------------------------*/ +sb4 set_sdtz() +{ + OraText *altstmt=(OraText *)"ALTER SESSION SET TIME_ZONE='US/Central'"; + OraText *selstmt=(OraText *)"SELECT SESSIONTIMEZONE FROM DUAL"; + OraText *str; + + /* Initialize strings */ + str = (OraText *)malloc(MAXDATELEN); + memset ((void *) str, '\0', MAXDATELEN); + + /* Alter session time zone */ + if (exe_sql(altstmt)) { + printf("FAILED: exe_sql()!\n"); + return OCI_ERROR; + } + + /* Preparation of statment handle for the select SQL statement */ + if ((ret = OCIStmtPrepare(stmthp, errhp, selstmt, (ub4) strlen((char *)selstmt), + OCI_NTV_SYNTAX, OCI_DEFAULT)) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIStmtPrepare"); + return OCI_ERROR; + } + + /* Defining the position for the variable */ + if ((ret = OCIDefineByPos(stmthp, &defhp[0], errhp, 1, str, MAXDATELEN, + SQLT_STR, (void *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT)) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIDefineByPos"); + return OCI_ERROR; + } + + /* Executing the SQL statement */ + if ((ret = OCIStmtExecute(svchp, stmthp, errhp, 1, 0, (OCISnapshot *) NULL, + (OCISnapshot *) NULL, OCI_DEFAULT)) != OCI_SUCCESS) { + chk_err(errhp,ret,__LINE__,(OraText *)"OCIStmtExecute"); + return OCI_ERROR; + } + + printf("The session time zone is set to %s\n\n", str); + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* An example on time zone name and daylight saving using OCIDateTimeConvert */ +/*--------------------------------------------------------*/ +sb4 tzds_1() +{ + ub4 type1, type2; + OraText *str1, *fmt1, *fmt2, *name1, *name2; + + /* Initialize strings */ + str1 = (OraText *)malloc(MAXDATELEN); + memset ((void *) str1, '\0', MAXDATELEN); + fmt1 = (OraText *)malloc(MAXDATELEN); + memset ((void *) fmt1, '\0', MAXDATELEN); + fmt2 = (OraText *)malloc(MAXDATELEN); + memset ((void *) fmt2, '\0', MAXDATELEN); + name1 = (OraText *)malloc(MAXDATELEN); + memset ((void *) name1, '\0', MAXDATELEN); + name2 = (OraText *)malloc(MAXDATELEN); + memset ((void *) name2, '\0', MAXDATELEN); + + printf("-->Conversion of datetime types\n\n"); + /* Convert from timestamp with time zone region to timestamp with time zone offset */ + /* The same time zone name will return different time zone offsets for standard time and daylight saving time */ + /* daylight saving time, expected time zone offset is -07:00 */ + type1 = OCI_DTYPE_TIMESTAMP_TZ; + type2 = OCI_DTYPE_TIMESTAMP_TZ; + strcpy((char *)str1,"1999-10-01 01:30:10 US/Pacific"); + strcpy((char *)fmt1,"YYYY-MM-DD HH:MI:SS TZR"); + strcpy((char *)fmt2,"YYYY-MM-DD HH:MI:SS TZH:TZM"); + strcpy((char *)name1, "TIMESTAMP WITH TIME ZONE REGION"); + strcpy((char *)name2, "TIMESTAMP WITH TIME ZONE OFFSET"); + if (conv_dt(str1, type1, type2, fmt1, fmt2, name1, name2)) { + printf("FAILED: conv_dt()!\n"); + return OCI_ERROR; + } + + /* standard time, expected time zone offset is -08:00 */ + strcpy((char *)str1,"1999-11-01 01:30:10 US/Pacific"); + if (conv_dt(str1, type1, type2, fmt1, fmt2, name1, name2)) { + printf("FAILED: conv_dt()!\n"); + return OCI_ERROR; + } + + /* Convert from timestamp with time zone region to timestamp with local time zone, + the session time zone was set to US/Central at the begining of the program */ + /* daylight saving time */ + type1 = OCI_DTYPE_TIMESTAMP_TZ; + type2 = OCI_DTYPE_TIMESTAMP_LTZ; + strcpy((char *)str1,"1999-10-31 01:30:10 US/Pacific PDT"); + strcpy((char *)fmt1,"YYYY-MM-DD HH24:MI:SS TZR TZD"); + strcpy((char *)fmt2,"YYYY-MM-DD HH24:MI:SS"); + strcpy((char *)name1, "TIMESTAMP WITH TIME ZONE REGION"); + strcpy((char *)name2, "TIMESTAMP WITH LOCAL TIME ZONE"); + if (conv_dt(str1, type1, type2, fmt1, fmt2, name1, name2)) { + printf("FAILED: conv_dt()!\n"); + return OCI_ERROR; + } + + /* standard time */ + strcpy((char *)str1,"1999-10-31 01:30:10 US/Pacific PST"); + if (conv_dt(str1, type1, type2, fmt1, fmt2, name1, name2)) { + printf("FAILED: conv_dt()!\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* An example on time zone name and daylight saving using OCIDateTimeIntervalAdd */ +/*--------------------------------------------------------*/ +sb4 tzds_2() +{ + ub4 type1, type2; + OraText *dt, *interval, *fmt; + + /* Initialize strings */ + dt = (OraText *)malloc(MAXDATELEN); + memset ((void *) dt, '\0', MAXDATELEN); + interval = (OraText *)malloc(MAXDATELEN); + memset ((void *) interval, '\0', MAXDATELEN); + fmt = (OraText *)malloc(MAXDATELEN); + memset ((void *) fmt, '\0', MAXDATELEN); + + printf("-->Addition of timestamp with time zone and interval day to seconds\n\n"); + /* The following two cases show that daylight saving is automatically + reflected with a time zone name */ + type1 = OCI_DTYPE_TIMESTAMP_TZ; + type2 = OCI_DTYPE_INTERVAL_DS; + strcpy((char *)interval,"0 08:00:00.00"); + strcpy((char *)fmt,"YYYY-MM-DD HH24:MI:SS TZR"); + + /* Standard time + an interval = daylight saving time */ + strcpy((char *)dt,"2000-4-1 23:24:54 AMERICA/LOS_ANGELES"); + if (add_interval(dt, interval, fmt, type1, type2)) { + printf("FAILED: add_interval()!\n"); + return OCI_ERROR; + } + + /* Daylight saving time + an interval = standard time */ + strcpy((char *)dt,"2000-10-28 22:00:00 AMERICA/LOS_ANGELES"); + if (add_interval(dt, interval, fmt, type1, type2)) { + printf("FAILED: add_interval()!\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/* end of file cdemodt.c */ diff --git a/cdemoext.c b/cdemoext.c new file mode 100644 index 0000000..1dff2f4 --- /dev/null +++ b/cdemoext.c @@ -0,0 +1,310 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemoext.c 14-jul-99.13:10:58 mjaeger Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1997, 1999,, 2000 Oracle Corporation. All rights reserved. +*/ + +/* + + NAME + cdemoext.c - C Demo for ociEXTract + + DESCRIPTION + This file demonstrates an example of using the OCIExtract package + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + + + NOTES + + + MODIFIED (MM/DD/YY) + tsaulys 01/05/00 - #(1078628) do not use strlist + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + nramakri 01/16/98 - add demos for OCINUM and List support + nramakri 12/17/97 - Creation + +*/ + +#include +#include +#include +#include + +#define NUMKEYS 9 /* Number of parameter keys */ + +/* Default values and ranges for various parameter keys */ +static const sb4 dflt_intval = 1234; +static const ub1 dflt_boolval = TRUE; + +static const sb4 intrange[] = {1234, 5678}; +static const text *strlst[] = {(const text *)"abcd", + (const text *)"efghi", + (const text *)"ijlkmn", + (const text *)"mnopqrs", + (const text *)"tuvwxyz", + (const text *)0 + }; + +/* strings containing parameters to be parsed */ +static text *par_str[] = {(text *)"param2=hello param3=30", + (text *)"Param4=hi Param5=5555 Param6=tuvwxyz", + (text *)"param1=45 param7=f param9=3.1415" + }; + +/* file containing parameters to be parsed */ +static text *par_file = (text *)"cdemoext.dat"; + +/* behavior flags to use while parsing parameter string */ +static const ub4 par_str_flags[] = {0, + OCI_EXTRACT_CASE_SENSITIVE, + OCI_EXTRACT_APPEND_VALUES + }; + +/* behavior flags to use while parsing parameter file */ +static const ub4 par_file_flags = OCI_EXTRACT_APPEND_VALUES; + +static sword checkerr(/*_ OCIError *errhp, sword status _*/); +int main(/*_ void _*/); + +int main() +{ + OCIEnv *envhp; + OCIError *errhp; + sword status; + sb4 outi; + ub1 outb; + text outs[100]; + OCINumber outn; + uword scount; + uword numkeys; + text *keyname; + ub1 keytype; + uword keynumvals; + dvoid **keyvalues; + double dnum; + + /* Set up OCI */ + (void) OCIInitialize((ub4)OCI_OBJECT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t))0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *))0 ); + + (void) OCIEnvInit((OCIEnv **)&envhp, OCI_DEFAULT, (size_t)0, (dvoid **)0); + + (void) OCIHandleAlloc((dvoid *)envhp, (dvoid **)&errhp, OCI_HTYPE_ERROR, + (size_t)0, (dvoid **)0); + + /* Initialize OCI extraction package */ + if (checkerr(errhp, OCIExtractInit(envhp, errhp)) != OCI_SUCCESS) + goto exit0; + + /* Set definitions for parameters to be extracted */ + if (checkerr(errhp, OCIExtractSetNumKeys(envhp, errhp, NUMKEYS+1)) + != OCI_SUCCESS) + goto exit0; + + /* Reset parameter space, cancels previous setting */ + (void) checkerr(errhp, OCIExtractReset(envhp, errhp)); + + if (checkerr(errhp, OCIExtractSetNumKeys(envhp, errhp, NUMKEYS)) + != OCI_SUCCESS) + goto exit0; + + /* 1: integer parameter, with no default value */ + (void) checkerr(errhp, OCIExtractSetKey(envhp, errhp, + (CONST text *)"Param1", + (ub1)OCI_EXTRACT_TYPE_INTEGER, + (ub4)OCI_EXTRACT_MULTIPLE, + (dvoid *)0, + (sb4 *)0, + (CONST text *CONST *)0)); + + /* 2: string parameter, with no default value */ + (void) checkerr(errhp, OCIExtractSetKey(envhp, errhp, + (CONST text *)"Param2", + (ub1)OCI_EXTRACT_TYPE_STRING, + (ub4)0, + (dvoid *)0, + (sb4 *)0, + (CONST text *CONST *)0)); + + /* 3: integer parameter, with a default value */ + (void) checkerr(errhp, OCIExtractSetKey(envhp, errhp, + (CONST text *)"Param3", + (ub1)OCI_EXTRACT_TYPE_INTEGER, + (ub4)0, + (dvoid *)&dflt_intval, + (sb4 *)0, + (CONST text *CONST *)0)); + + /* 4: string parameter, with a default value */ + (void) checkerr(errhp, OCIExtractSetKey(envhp, errhp, + (CONST text *)"Param4", + (ub1)OCI_EXTRACT_TYPE_STRING, + (ub4)0, + (dvoid *)"abcd", + (sb4 *)0, + (CONST text *CONST *)0)); + + /* 5: integer parameter, with no default value, and allowable range */ + (void) checkerr(errhp, OCIExtractSetKey(envhp, errhp, + (CONST text *)"Param5", + (ub1)OCI_EXTRACT_TYPE_INTEGER, + (ub4)0, + (dvoid *)0, + (sb4 *)intrange, + (CONST text *CONST *)0)); + + /* 6: string parameter, with a default value, and allowable list */ + (void) checkerr(errhp, OCIExtractSetKey(envhp, errhp, + (CONST text *)"Param6", + (ub1)OCI_EXTRACT_TYPE_STRING, + (ub4)0, + (dvoid *)"efghi", + (sb4 *)0, + (CONST text *CONST *)strlst)); + + /* 7: boolean parameter, with no default value */ + (void) checkerr(errhp, OCIExtractSetKey(envhp, errhp, + (CONST text *)"Param7", + (ub1)OCI_EXTRACT_TYPE_BOOLEAN, + (ub4)OCI_EXTRACT_MULTIPLE, + (dvoid *)0, + (sb4 *)0, + (CONST text *CONST *)0)); + + /* 8: boolean parameter, with a default value */ + (void) checkerr(errhp, OCIExtractSetKey(envhp, errhp, + (CONST text *)"Param8", + (ub1)OCI_EXTRACT_TYPE_BOOLEAN, + (ub4)0, + (dvoid *)&dflt_boolval, + (sb4 *)0, + (CONST text *CONST *)0)); + + /* 9: ocinum parameter with no default value */ + (void) checkerr(errhp, OCIExtractSetKey(envhp, errhp, + (CONST text *)"Param9", + OCI_EXTRACT_TYPE_OCINUM, + OCI_EXTRACT_MULTIPLE, + (CONST dvoid *)0, + (CONST sb4 *)0, + (CONST text *CONST *)0)); + + /* Extract parameters from a file */ + (void) checkerr(errhp, OCIExtractFromFile(envhp, errhp, + par_file_flags, par_file)); + + /* Extract parameters from strings */ + for (scount = 0; scount < 3; scount++) + (void) checkerr(errhp, OCIExtractFromStr(envhp, errhp, + par_str_flags[scount], + par_str[scount])); + + /* Output some parameters */ + if (checkerr(errhp, OCIExtractToInt(envhp, errhp, (text *)"Param1", + 0, &outi)) == OCI_SUCCESS) + printf("Param1 is %d\n", outi); + + if (checkerr(errhp, OCIExtractToStr(envhp, errhp, (text *)"Param6", + 0, outs, 100)) == OCI_SUCCESS) + printf("Param6 is %s\n", outs); + + if (checkerr(errhp, OCIExtractToBool(envhp, errhp, (text *)"Param8", + 0, &outb)) == OCI_SUCCESS) + printf("Param8 is %s\n", (outb == TRUE)?"true":"false"); + + if (checkerr(errhp, OCIExtractToList(envhp, errhp, &numkeys)) + == OCI_SUCCESS) + { + /* Extract some key */ + (void) checkerr(errhp, OCIExtractFromList(envhp, errhp, 1, + &keyname, &keytype, + &keynumvals, &keyvalues)); + + /* Print details about the extracted key */ + printf("The key extracted was \'%s\'\n", keyname); + printf("%s contains %d ", keyname, keynumvals); + switch(keytype) + { + case OCI_EXTRACT_TYPE_INTEGER: + printf("integer values which are:\n"); + for (scount=0; scount < keynumvals; scount++) + printf("%d\n", *(sb4 *)keyvalues[scount]); + break; + case OCI_EXTRACT_TYPE_BOOLEAN: + printf("boolean values which are:\n"); + for (scount=0; scount < keynumvals; scount++) + printf("%s\n", (*(ub1 *)keyvalues[scount]==TRUE)?"true":"false"); + break; + case OCI_EXTRACT_TYPE_STRING: + printf("string values which are:\n"); + for (scount=0; scount < keynumvals; scount++) + printf("%s\n", (text *)keyvalues[scount]); + break; + case OCI_EXTRACT_TYPE_OCINUM: + printf("OCINumber values which are:\n"); + for (scount=0; scount < keynumvals; scount++) + { + (void) checkerr(errhp, + OCINumberToReal(errhp, + (CONST OCINumber *)keyvalues[scount], + (uword)sizeof(dnum), (dvoid *)&dnum)); + (void) printf("%11.4f\n", dnum); + } + break; + default: + printf("unknown values\n"); + break; + } + } + + /* Terminate OCI extraction package */ + (void) checkerr(errhp, OCIExtractTerm(envhp, errhp)); + + exit0: + if (errhp) + (void) OCIHandleFree((dvoid *)errhp, OCI_HTYPE_ERROR); + + return 0; +} + +static sword checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", 512, errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + default: + break; + } + return status; +} + +/* end of file cdemoext.c */ + diff --git a/cdemoext.dat b/cdemoext.dat new file mode 100644 index 0000000..ecb57a3 --- /dev/null +++ b/cdemoext.dat @@ -0,0 +1,11 @@ +# +# parameter file +# +param1=25 +param2=world +param3=145 +param4=hi +param5=5555 +param6=efghi +param7=true +param9=-63378.4542 .2096 diff --git a/cdemofil.c b/cdemofil.c new file mode 100644 index 0000000..95ec3a0 --- /dev/null +++ b/cdemofil.c @@ -0,0 +1,242 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemofil.c 27-jul-2004.08:40:29 jchai Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1997, 2004, Oracle. All rights reserved. +*/ + +/* + + NAME + cdemofil.c - C Demo for ociFILe + + DESCRIPTION + This file demonstrates an example of using the OCIFile package + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + + + NOTES + + + MODIFIED (MM/DD/YY) + jchai 07/27/04 - + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + nramakri 12/17/97 - Creation + +*/ + +#include +#include +#include + +#ifndef OCI_ORACLE +#include +#endif + +static sword checkerr(/*_ OCIError *errhp, sword status _*/); +int main(/*_ int argc, char *argv[] _*/); + +int main(argc, argv) +int argc; +char *argv[]; +{ + OCIEnv *envhp; + OCIError *errhp; + + OCIFileObject *of1o, *of2o; + OraText *f1name, *f1path, *f2name, *f2path; + OraText buf1[500], buf2[50], buf3[500], buf4[500]; + ub4 bytes1, bytes2, i; + ubig_ora f1len, f2len; + ub1 flag; /* boolean */ + + f1name = (OraText *)"test_file1.dat"; + f1path = (OraText *)NULL; + + f2name = (OraText *)"test_file2.dat"; + f2path = (OraText *)NULL; + + + (void) OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 ); + + (void) OCIEnvInit( (OCIEnv **) &envhp, OCI_DEFAULT, (size_t) 0, + (dvoid **) 0 ); + + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + + /* Initialize OCIFile */ + if (checkerr(errhp, OCIFileInit(envhp, errhp)) != OCI_SUCCESS) + goto exit0; + else + printf("OCIFile initialized successfully\n"); + + + /* Create the file and open it for read & write: file1 */ + if (checkerr(errhp, OCIFileOpen(envhp, errhp, &of1o, f1name, f1path, + OCI_FILE_READ_WRITE, OCI_FILE_CREATE, + OCI_FILE_TEXT)) != OCI_SUCCESS) + goto exit0; + else + printf("File %s opened successfully\n", f1name); + + /* fill buf4 with data to be written */ + for (i=0; i<500; i++) + buf4[i] = 'a'+i%26; + + /* write buf2 */ + if (checkerr(errhp, OCIFileWrite(envhp, errhp, of1o, (void *)buf4, + 500, &bytes1)) + == OCI_SUCCESS) + { + printf("No of bytes written to file %s is %d\n", f1name, bytes1); + } + + /* flush the buffers */ + checkerr(errhp, OCIFileFlush(envhp, errhp, of1o)); + + /* Print out the length of file1 */ + if (checkerr(errhp, OCIFileGetLength(envhp, errhp, f1name, f1path, &f1len)) + == OCI_SUCCESS) + { + printf("The length of the file %s is %d\n",f1name, f1len); + } + + /* Seek to the beginning of the file */ + if (checkerr(errhp, OCIFileSeek(envhp, errhp, of1o, OCI_FILE_SEEK_BEGINNING, + 0, OCI_FILE_FORWARD)) != OCI_SUCCESS) + goto exit0; + + /* Read upto 400 bytes from test_file1.txt */ + if (checkerr(errhp, OCIFileRead(envhp, errhp, of1o, (void *)buf1, + 400, &bytes1)) == OCI_SUCCESS) + { + printf("No of bytes read from file %s is %d\n", f1name, bytes1); + } + + flag = FALSE; + + /* Check whether file2 exists */ + checkerr(errhp, OCIFileExists(envhp, errhp, f2name, f2path, &flag)); + + if (flag == FALSE) + { + /* File doesn't exist, Open for write in exclusive mode */ + /* skip printf, causes dif in tkpgoci2.tsc */ + /* printf("File %s does not exist\n", f2name); */ + if (checkerr(errhp, OCIFileOpen(envhp, errhp, &of2o, f2name, f2path, + OCI_FILE_READ_WRITE, OCI_FILE_EXCL, + OCI_FILE_TEXT)) != OCI_SUCCESS) + goto exit0; + else + printf("File %s opened successfully\n", f2name); + } + else /* File exists, open in truncate mode */ + { + /* skip printf, causes dif in tkpgoci2.tsc */ + /*printf("File %s exists \n", f2name); */ + if (checkerr(errhp, OCIFileOpen(envhp, errhp, &of2o, f2name, f2path, + OCI_FILE_READ_WRITE, OCI_FILE_TRUNCATE, + OCI_FILE_TEXT)) != OCI_SUCCESS) + goto exit0; + else + printf("File %s opened successfully\n", f2name); + } + + /* write from buf1 */ + if (checkerr(errhp, OCIFileWrite(envhp, errhp, of2o, buf1, bytes1, &bytes2)) + == OCI_SUCCESS) + { + printf("No of bytes written to file %s is %d\n", f2name, bytes2); + } + + /* Seek to the end of the file */ + if (checkerr(errhp, OCIFileSeek(envhp, errhp, of2o, OCI_FILE_SEEK_END, 0, + OCI_FILE_FORWARD)) != OCI_SUCCESS) + goto exit0; + + strcpy((char *)buf2, "This is the end of this file!"); + + /* write buf2 */ + if (checkerr(errhp, OCIFileWrite(envhp, errhp, of2o, (void *)buf2, + strlen((CONST char *)buf2), &bytes2)) + == OCI_SUCCESS) + printf("No of bytes written to file %s is %d\n", f2name, bytes2); + + /* flush the buffers */ + checkerr(errhp, OCIFileFlush(envhp, errhp, of2o)); + + /* Print out the length of the file */ + if (checkerr(errhp, OCIFileGetLength(envhp, errhp, f2name, f2path, &f2len)) + == OCI_SUCCESS) + printf("The length of file %s is %d\n", f2name, f2len); + + /* Seek to the beginning of file2 */ + if (checkerr(errhp, OCIFileSeek(envhp, errhp, of2o, OCI_FILE_SEEK_BEGINNING, + 0, OCI_FILE_FORWARD)) != OCI_SUCCESS) + goto exit0; + + /* Read all the data from test_file2.txt */ + if (checkerr(errhp, OCIFileRead(envhp, errhp, of2o, (void *)buf3, + f2len, &bytes1)) == OCI_SUCCESS) + printf("No of bytes read from file %s is %d\n", f2name, bytes1); + + /* append buf2 contents to buf1 */ + memcpy(buf1+400, buf2, bytes2); + + /* compare buf1 & buf3 */ + if (memcmp(buf1, buf3, bytes1) == 0) + printf("Reads & Writes are successful\n"); + else + printf("Error in data read/written\n"); + + /* close the files and terminate OCIFile */ + checkerr(errhp, OCIFileClose(envhp, errhp, of2o)); + checkerr(errhp, OCIFileClose(envhp, errhp, of1o)); + checkerr(errhp, OCIFileTerm(envhp, errhp)); + + exit0: + if (errhp) + (void) OCIHandleFree((dvoid *) errhp, OCI_HTYPE_ERROR); + + return 0; +} + +sword checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + OraText errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (OraText *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s", 512, errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + default: + break; + } + return status; +} + +/* end of file cdemofil.c */ + diff --git a/cdemofo.c b/cdemofo.c new file mode 100644 index 0000000..dfc326b --- /dev/null +++ b/cdemofo.c @@ -0,0 +1,398 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemofo.c 16-jul-2003.09:08:43 srseshad Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1998, 2003, Oracle Corporation. All rights reserved. +*/ + +/* + + NAME + cdemofo.c - C demo program for OCI callbacks for application failover + + DESCRIPTION + This is an example program to demonstrate the registration + and operation of OCI application failover callbacks. + + PUBLIC FUNCTION(S) + main - main entry point + + PRIVATE FUNCTION(S) + checkerr - check errors + cleanup - cleanup resources + register_callback - register failover callback + callback_fn - callback function + + + RETURNS + EX_SUCESS on success + EX_FAILURE on failure + + NOTES + This is just a demo program for the failover callbacks. A complete + failover example would require someway of simulating the failure of the + connection and switching to a new instance + + + MODIFIED (MM/DD/YY) + srseshad 07/16/03 - remove direct ref to ocikp.h and ociap.h + porangas 10/08/02 - Fix for bug#2540468 + slari 05/15/02 - Change to fix core dumep during cleanup at demo exit.. + emendez 09/13/00 - fix top 5 olint errors + mrhodes 01/25/00 - make sleep call nt compatible + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + slari 10/14/98 - remove OCI_FO_TXNAL + slari 10/13/98 - demo program for oci application failover callbacks + slari 10/13/98 - Creation + +*/ + + +/* for WINDOWS compatibility of 'sleep' call */ +#if defined(WIN32COMMON) || defined(WIN32) || defined(_WIN32) +#include +#define sleep(x) Sleep(1000*(x)) +#endif + + +#include +#include +#include +#include + +#define EX_SUCCESS 0 +#define EX_FAILURE -1 +#define FAILOVER_S "Application Failover Context" + +static text *username = (text *) "SCOTT"; +static text *password = (text *) "TIGER"; +static text *dbname = (text *) "inst1"; + + /* Define SQL statements to be used in program. */ +static text *sel1 = (text *) "SELECT empno FROM emp order by empno"; + +static OCIEnv *envhp = NULL; +static OCIServer *srvhp = NULL; +static OCIError *errhp = NULL; +static OCISvcCtx *svchp = NULL; +static OCIStmt *stmthp = NULL; +static OCIDefine *defnp = (OCIDefine *) 0; + +static OCIBind *bnd1p = (OCIBind *) 0; + +static sb4 checkerr(/*_ OCIError *errhp, sword status _*/); +static void cleanup(/*_ void _*/); + +static sb4 register_callback(); +static sb4 callback_fn(); + +int main(/*_ int argc, char *argv[] _*/); +static sword status; + + + +int main(argc, argv) +int argc; +char *argv[]; +{ + OCIFocbkStruct failover; + int exitCode = EX_FAILURE; + + sword i=0, empno=0, count=0, totcount=0; + + OCISession *authp = (OCISession *) 0; + + + if (checkerr(NULL, OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0))) + goto terminate; + + if (checkerr(NULL, OCIEnvInit((OCIEnv **) &envhp, OCI_DEFAULT, (size_t) 0, + (dvoid **) 0))) + goto terminate; + + if (checkerr(envhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp, + OCI_HTYPE_ERROR, (size_t) 0, (dvoid **)0))) + goto terminate; + + /* server contexts */ + if (checkerr(envhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **) &srvhp, + OCI_HTYPE_SERVER, (size_t) 0, + (dvoid **) 0))) + goto terminate; + + if (checkerr(envhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **) &svchp, + OCI_HTYPE_SVCCTX, (size_t) 0, + (dvoid **) 0))) + goto terminate; + + if (checkerr(errhp, OCIServerAttach(srvhp, errhp, (text *)dbname, + strlen((char *)dbname), 0))) + goto terminate; + + /* set attribute server context in the service context */ + if (checkerr(errhp, OCIAttrSet((dvoid *) svchp, OCI_HTYPE_SVCCTX, + (dvoid *)srvhp, (ub4) 0, OCI_ATTR_SERVER, + (OCIError *) errhp))) + goto terminate; + + if (checkerr(envhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **)&authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, + (dvoid **) 0))) + goto terminate; + + if (checkerr(errhp, OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) username, (ub4) strlen((char *)username), + (ub4) OCI_ATTR_USERNAME, errhp))) + goto terminate; + + if (checkerr(errhp, OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) password, (ub4) strlen((char *)password), + (ub4) OCI_ATTR_PASSWORD, errhp))) + goto terminate; + + if (checkerr(errhp, OCISessionBegin(svchp, errhp, authp, OCI_CRED_RDBMS, + (ub4) OCI_DEFAULT))) + goto terminate; + + if (checkerr(errhp, OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) authp, (ub4) 0, + (ub4) OCI_ATTR_SESSION, errhp))) + goto terminate; + + /* registers the OCI application failover callbacks */ + if (register_callback(srvhp, errhp,&failover)) + goto terminate; + + if (checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp, + OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0))) + goto terminate; + + /* process SQL statement */ + if (checkerr(errhp, OCIStmtPrepare(stmthp, errhp, sel1, + (ub4) strlen((char *) sel1), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT))) + goto terminate; + + if (checkerr(errhp, OCIDefineByPos(stmthp, &defnp, errhp, 1, + (dvoid *) &empno, + (sword) sizeof(sword), SQLT_INT, (dvoid *) 0, (ub2 *)0, + (ub2 *)0, OCI_DEFAULT))) + goto terminate; + + status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL, OCI_DEFAULT); + for(;;) + { + if (status != 0) + { + if (status == OCI_NO_DATA) + break; + else + { + checkerr(errhp, status); + goto terminate; + } + } + printf("empno: %d\n", empno); + /* execute and fetch */ + status=OCIStmtFetch(stmthp, errhp, (ub4) 1, (ub4) 0, (ub4) 0); + } + + exitCode = EX_SUCCESS; + + terminate: + + if (exitCode == EX_SUCCESS) + printf("No errors.\n"); + else + printf("Failed due to errors.\n"); + + cleanup(); + return exitCode; +} + /* application failoever callback function */ +sb4 callback_fn(svchp, envhp, fo_ctx, fo_type, fo_event ) +dvoid * svchp; +dvoid * envhp; +dvoid *fo_ctx; +ub4 fo_type; +ub4 fo_event; +{ + switch (fo_event) + { + case OCI_FO_BEGIN: + { + printf(" Failing Over ... Please stand by \n"); + printf(" Failover type was found to be %s \n", + ((fo_type==OCI_FO_NONE) ? "NONE" + :(fo_type==OCI_FO_SESSION) ? "SESSION" + :(fo_type==OCI_FO_SELECT) ? "SELECT" + : "UNKNOWN!")); + printf(" Failover Context is :%s\n", + (fo_ctx?(char *)fo_ctx:"NULL POINTER!")); + break; + } + + case OCI_FO_ABORT: + { + printf(" Failover aborted. Failover will not take place.\n"); + break; + } + + case OCI_FO_END: + { + printf(" Failover ended ...resuming services\n"); + break; + } + + case OCI_FO_REAUTH: + { + printf(" Failed over user. Resuming services\n"); + + /* Application can check the OCI_ATTR_SESSION attribute of + the service handle to find out the user being + re-authenticated. + + After this, the application can replay any ALTER SESSION + commands associated with this session. These must have + been saved by the application in the fo_ctx + */ + break; + } + + + case OCI_FO_ERROR: + { + printf(" Failover error gotten. Sleeping...\n"); + sleep(3); + return OCI_FO_RETRY; + break; + } + + default: + { + printf("Bad Failover Event: %d.\n", fo_event); + break; + } + } + return 0; +} + + + + /* callback function registration */ +sb4 register_callback(srvhp, errhp,failover) +dvoid *srvhp; /* the server handle */ +OCIError *errhp; /* the error handle */ +OCIFocbkStruct *failover; +{ + + if (!(failover->fo_ctx = + (dvoid *)malloc(strlen(FAILOVER_S) + 1))) + { + (void) printf("Error - could not allocate failover context\n"); + return EX_FAILURE; + } + + /* initialize the context. */ + strcpy((char *)failover->fo_ctx, FAILOVER_S); + failover->callback_function = &callback_fn; + /* do the registration */ + if (checkerr(errhp, OCIAttrSet(srvhp, (ub4) OCI_HTYPE_SERVER, + (dvoid *) failover, (ub4) 0, + (ub4) OCI_ATTR_FOCBK, errhp))) + { + printf("Failed to set failover attribute\n"); + return EX_FAILURE; + } + + return EX_SUCCESS; +} + + + /* error handler */ +sb4 checkerr(ehndlp, status) +OCIError *ehndlp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + return EX_SUCCESS; + + case OCI_SUCCESS_WITH_INFO: + printf("Error - OCI_SUCCESS_WITH_INFO\n"); + return EX_SUCCESS; + + case OCI_NEED_DATA: + printf("Error - OCI_NEED_DATA\n"); + return EX_SUCCESS; + + case OCI_NO_DATA: + printf("Error - OCI_NODATA\n"); + return EX_SUCCESS; + + case OCI_ERROR: + if (ehndlp) + { + OCIErrorGet((dvoid *)ehndlp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + printf("Error - %.*s\n", 512, errbuf); + } + else + printf("Error - OCI_ERROR\n"); + return EX_FAILURE; + + case OCI_INVALID_HANDLE: + printf("Error - OCI_INVALID_HANDLE\n"); + return EX_FAILURE; + + case OCI_STILL_EXECUTING: + printf("Error - OCI_STILL_EXECUTE\n"); + return EX_SUCCESS; + + case OCI_CONTINUE: + printf("Error - OCI_CONTINUE\n"); + return EX_SUCCESS; + + default: + printf("Error - Unknown error\n"); + return EX_FAILURE; + } +} + + + /* cleanup resources */ +void cleanup() +{ + if (stmthp) + checkerr(errhp, OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT)); + + if (errhp && srvhp) + (void) OCIServerDetach( srvhp, errhp, OCI_DEFAULT ); + + if (srvhp) + checkerr(errhp, OCIHandleFree((dvoid *) srvhp, OCI_HTYPE_SERVER)); + + if (svchp) + (void) OCIHandleFree((dvoid *) svchp, OCI_HTYPE_SVCCTX); + + if (errhp) + (void) OCIHandleFree((dvoid *) errhp, OCI_HTYPE_ERROR); + + if (envhp) + (void) OCIHandleFree((dvoid *) envhp, OCI_HTYPE_ENV); + return; +} + + + +/* end of file cdemofo.c */ + diff --git a/cdemofor.c b/cdemofor.c new file mode 100644 index 0000000..97efe32 --- /dev/null +++ b/cdemofor.c @@ -0,0 +1,143 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemofor.c 14-jul-99.13:12:32 mjaeger Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1997, 1999, Oracle Corporation. All rights reserved. +*/ + +/* + + NAME + cdemofor.c - C Demo for ociFORmat + + DESCRIPTION + This file demonstrates an example of using the OCIFormat package. + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + + + NOTES + + + MODIFIED (MM/DD/YY) + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ewaugh 05/06/98 - OCIString renamed to OCIFormat. + nramakri 12/17/97 - Creation + +*/ + +#include +#include +#include +#include + +#define BUFLEN 100 +#define FORMATLEN 100 + +struct +{ + text buffer[BUFLEN]; + sbig_ora bytesWritten; + text formatString[FORMATLEN]; + text style[3]; +} MyDate[2]; + +sword checkerr(/*_ OCIError *errhp, sword status _*/); +int main (/*_ int argc, char *argv[] _*/); + +int main(argc, argv) +int argc; +char *argv[]; +{ + OCIEnv *envhp; + OCIError *errhp; + + ub1 month = 12; + ub1 day = 31; + ub1 year = 97; + + uword i; + + strcpy((char *)MyDate[0].formatString, "%(2)02u/%(1)02u/%(3)02u"); + strcpy((char *)MyDate[0].style, "US"); + strcpy((char *)MyDate[1].formatString, "%(1)02u/%(2)02u/%(3)02u"); + strcpy((char *)MyDate[1].style, "NZ"); + + (void) OCIInitialize(OCI_DEFAULT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t))0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *))0); + + (void) OCIEnvInit((OCIEnv **)&envhp, OCI_DEFAULT, (size_t)0, (dvoid **)0); + + (void) OCIHandleAlloc((dvoid *)envhp, (dvoid **)&errhp, OCI_HTYPE_ERROR, + (size_t)0, (dvoid **)0); + + if (checkerr(errhp, OCIFormatInit(envhp, errhp)) != OCI_SUCCESS) + { + goto error; + } + + for (i = 0 ; i < 2 ; i++) + { + if (checkerr(errhp, OCIFormatString(envhp, errhp, MyDate[i].buffer, + BUFLEN, &MyDate[i].bytesWritten, + (CONST text *)MyDate[i].formatString, + OCIFormatUb1(day), + OCIFormatUb1(month), + OCIFormatUb1(year), + OCIFormatEnd)) == OCI_SUCCESS) + { + (void) printf("New Year's eve in %s style is %s\n", + (char *)MyDate[i].style, (char *)MyDate[i].buffer); + } + } + + (void) checkerr(errhp, OCIFormatTerm(envhp, errhp)); + +error: + if (errhp) + { + (void) OCIHandleFree((dvoid *)errhp, OCI_HTYPE_ERROR); + } + + return 0; +} + +sword checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4)1, (text *)NULL, + &errcode, + errbuf, (ub4)sizeof(errbuf), + OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", (int)512, (char *)errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + default: + break; + } + + return status; +} + +/* end of file cdemofor.c */ + diff --git a/cdemoin1.c b/cdemoin1.c new file mode 100644 index 0000000..d7a6db7 --- /dev/null +++ b/cdemoin1.c @@ -0,0 +1,761 @@ +/* Copyright (c) 1996, 2001, Oracle Corporation. All rights reserved. */ + +/* + + NAME + cdemoin1 - Demo program which modifies an inherited type in a table and + displays a record from the table. + + DESCRIPTION + This program pins an inherited instance in the object cache and displays + the attributes in it. It also updates a record of a table. + + NOTES + dependent files : + cdemoin1.h - Header file + cdemoin1.sql - SQL script to be run before execution + cdemoin1.tsc - test script (optional) + + Program Notes : + + MODIFIED (MM/DD/YY) + pzwu 05/18/01 - Fix bug1786565 + jchai 04/29/01 - change schema + rdwajan 08/22/00 - Creation +*/ + +#define NUMREC 3 +#include "cdemoin1.h" + +static OCIError *errhp = (OCIError *)0; +static OCIEnv *envhp = (OCIEnv *)0; +static OCIServer *svrhp = (OCIServer *)0; +static OCISession *sesnhp = (OCISession *)0; +static OCISvcCtx *svchp = (OCISvcCtx *)0; +static OCIStmt *stmthp = (OCIStmt *)0; + +static OCIRef *workadd[NUMREC]; /* Array of REFs for workadd to be populated */ +static text *database =(text *)""; +static text *username =(text *)"scott"; +static text *password =(text *)"tiger"; + +static text *selectSql = (text *) + "SELECT REF(a) FROM i_manager_tab a WHERE VALUE(a) IS OF (ONLY i_manager)"; + +static text *updateSql = (text *) + "SELECT REF(a) FROM i_manager_tab a WHERE VALUE(a) IS OF (ONLY i_manager) FOR UPDATE"; + +static text *insertSql = (text *) + "INSERT INTO i_people_tab VALUES (:v1)"; + +static text *selRef = (text *) + "SELECT REF(a) FROM i_residence_tab a"; + +int main(/*void*/); +/* Free the allocated handles */ +static void cleanup (void); + +/* Function to modify a record of an inherited object table */ +static void modifyFunction(); + +/* Function to select the ref of an inherited object */ +static void selectFunction (); + +/* Function to insert an instance of the subtype into a supertype table */ +static void insertFunction(); + +/* Function to display the attributes of the object */ +static void display (i_manager *sub_obj); + +/* Function to get an array of REFs */ +static void getRef(); + +static sword status = 0; + +int main (void) +{ + printf + ("cdemoin1 - Demonstrating select, insert and update on a subtype table\n"); + /* Initializing the environment in the Object mode*/ + + OCIEnvCreate((OCIEnv **) &envhp, OCI_OBJECT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0, (size_t) 0, (dvoid **) 0 ); + + OCIHandleAlloc (envhp, (dvoid **)&errhp, OCI_HTYPE_ERROR, (size_t)0, + (dvoid **)0); + + OCIHandleAlloc(envhp, (dvoid **)&svrhp, OCI_HTYPE_SERVER, (size_t)0, + (dvoid **)0); + + status = OCIServerAttach(svrhp, errhp, (text *)database, + (sb4)strlen((char *)database), OCI_DEFAULT); + + if (status != OCI_SUCCESS) + { + printf("OCIServerAttach failed \n"); + } + else + printf("OCIServerAttach - Success \n"); + + OCIHandleAlloc(envhp, (dvoid **)&svchp, OCI_HTYPE_SVCCTX, (size_t)0, + (dvoid **)0); + OCIAttrSet(svchp, OCI_HTYPE_SVCCTX, (dvoid *)svrhp, (ub4)0, OCI_ATTR_SERVER, + errhp); + + OCIHandleAlloc(envhp, (dvoid **)&sesnhp, OCI_HTYPE_SESSION, (size_t)0, + (dvoid **)0); + + OCIAttrSet(sesnhp, OCI_HTYPE_SESSION, (dvoid *)username, + (ub4)strlen((char *)username), OCI_ATTR_USERNAME, errhp); + + OCIAttrSet(sesnhp, OCI_HTYPE_SESSION, (dvoid*)password, + (ub4)strlen((char *)password), OCI_ATTR_PASSWORD, errhp); + + printf("Connecting as %s/%s@%s\n",username,password,database); + + status = OCISessionBegin(svchp, errhp, sesnhp, OCI_CRED_RDBMS, OCI_DEFAULT); + if (status != OCI_SUCCESS) + { + printf("Connection failed \n"); + } + else + printf("Connection - Success \n"); + + OCIAttrSet(svchp, OCI_HTYPE_SVCCTX, sesnhp, (ub4)0, OCI_ATTR_SESSION, errhp); + + /* Calling function to get an array of REFs to populate the varray */ + getRef(); + + /* Function to insert an instance of the subtype into a supertype table */ + insertFunction(); + + /* Function to modify the data of an inherited object */ + modifyFunction(); + + /* Function to display data from the table */ + selectFunction(); + + /* Free the allocated handles */ + cleanup(); + + printf("cdemoin1 - Done\n"); + return 1; +} /* End of main() */ + +/* Function to insert an instance of the subtype into a supertype table */ +static void insertFunction() +{ + OCIBind *bindhp = (OCIBind *)0; + i_residence elem; + i_residence *elemptr = &elem; + i_manager *sub_obj = (i_manager *)0; + i_manager_ind ind; + OCIType *i_manager_tdo = (OCIType *)0; + + ub4 subSize = 0; + ub4 sizeUB4 = sizeof (ub4); + sb4 size = 0; + text *name = (text*)"JENNY"; + ub4 name_len =(ub4)( strlen( (char * ) name)); + ub4 ssn = 303; /* Data for ssn */ + ub4 addr_hno = 33; /*Data for hno of addr */ + text *addr_street = (text *)"T33"; /*Data for street of addr */ + ub4 addr_streetLen = (ub4)(strlen( (char *)addr_street)); + ub4 altadrs_hno = 333; /*data for hno of altadrs */ + text *altadrs_street = (text *)"T333"; /*Data for street of altadrs */ + ub4 altadrs_streetLen = (ub4)(strlen( (char *)altadrs_street)); + ub4 empno = 3333; /* data for empno */ + + sb4 index1 = 0; /* Index for the starting point of the scan */ + sb4 index2 = 0; /* Index of the next existing element */ + boolean eoc = TRUE; /* For getting the status for the availability of + the next index */ + ub4 count = 0; /* Loop counter */ + + memset(&ind, 0, sizeof(ind)); + memset(elemptr, 0, sizeof(elem)); + OCIHandleAlloc (envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0); + + if ((status = OCIStmtPrepare (stmthp, errhp, (text *)insertSql, + (ub4)strlen((char *)insertSql),OCI_NTV_SYNTAX, OCI_DEFAULT)) != OCI_SUCCESS) + { + printf ("OCIStmtPrepare - Fail\n"); + } + + if ((status = OCIBindByName(stmthp, &bindhp, errhp, (text *)":v1", + (sb4) -1, (dvoid *)0, (sb4)0, SQLT_NTY, (dvoid *)0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, OCI_DEFAULT)) != OCI_SUCCESS) + { + printf ("OCIBindByName - Failure \n"); + } + + if ((status = OCITypeByName (envhp, errhp, svchp, (CONST text *)0, (ub4)0, + (CONST text *)"I_MANAGER", (ub4)strlen ((char *)"I_MANAGER"), + (CONST text *)0, (ub4)0, OCI_DURATION_SESSION, OCI_TYPEGET_HEADER, + &i_manager_tdo)) != OCI_SUCCESS) + { + printf ("OCITypeByName - Fail\n"); + } + + if (( status = OCIObjectNew(envhp, errhp, svchp, OCI_TYPECODE_OBJECT, + (OCIType *)i_manager_tdo, (dvoid *)0, OCI_DURATION_SESSION, TRUE, + (dvoid **) &sub_obj)) != OCI_SUCCESS) + { + printf ("OCIObjectNew - Failure\n"); + } + OCINumberFromInt (errhp, (dvoid *)&ssn, sizeof(ssn), OCI_NUMBER_UNSIGNED, + &(sub_obj->_super.ssn)); + OCINumberFromInt (errhp, (dvoid *)&empno, sizeof(empno), OCI_NUMBER_UNSIGNED, + &(sub_obj->empno)); + + OCINumberFromInt (errhp, (dvoid *)&addr_hno, sizeof(addr_hno),OCI_NUMBER_UNSIGNED, + &(sub_obj->_super.addr.hno)); + + OCIStringAssignText (envhp, errhp, (text *)name, (ub2)name_len, + &(sub_obj->_super.name)); + OCIStringAssignText (envhp, errhp, (text *)addr_street, (ub2)addr_streetLen, + &(sub_obj->_super.addr.street)); + for (count = 0; count < NUMREC; ++count) + { + OCIStringAssignText (envhp, errhp, (text *)altadrs_street, (ub2)altadrs_streetLen, + &(elemptr->street)); + OCINumberFromInt (errhp, (dvoid *)&altadrs_hno, sizeof(altadrs_hno), + OCI_NUMBER_UNSIGNED, &(elemptr->hno)); + if (( status = OCICollAppend (envhp, errhp, (dvoid *)elemptr, (dvoid *)&ind, + (OCIColl *)sub_obj->_super.altadrs)) != OCI_SUCCESS) + { + printf ("OCICollAppend - Fail\n"); + } + altadrs_hno ++; + } + for (count = 0; count < NUMREC; ++count) + { + if (( status = OCICollAppend (envhp, errhp, (dvoid *)workadd[count], + (dvoid *)&ind, (OCIColl *)sub_obj->workadd)) != OCI_SUCCESS) + { + printf ("OCICollAppend - Fail\n"); + } + } + OCITableSize(envhp, errhp,(CONST OCITable*) (sub_obj->_super.altadrs), &size); + OCITableSize(envhp, errhp,(CONST OCITable*) (sub_obj->workadd), &size); + + if (OCIBindObject(bindhp, errhp, i_manager_tdo, + (dvoid **) &sub_obj, (ub4 *)0, (dvoid **)&ind , (ub4 *) 0) != OCI_SUCCESS) + { + printf("OCIBindObject - Failure \n"); + } + + printf ("\nExecuting the statement:%s\n", insertSql); + if (OCIStmtExecute (svchp, stmthp, errhp, (ub4)1, (ub4)0, + (OCISnapshot *)0, (OCISnapshot *)0, OCI_COMMIT_ON_SUCCESS ) != OCI_SUCCESS) + { + printf("OCIStmtExecute - Failure \n"); + } + else + printf("OCIStmtExecute - Success\n"); + + OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT); +}/* End on insertFunction() */ + +/* Function to modify the data of an inherited object */ +static void modifyFunction () +{ + OCIDefine *defhp = (OCIDefine *)0; + OCIRef *sub_ref = (OCIRef *)0; + i_residence elem; + i_residence *elemptr = (i_residence *)0; + i_manager *sub_obj = (i_manager *)0; + ub4 subSize = 0; + ub4 sizeUB4 = sizeof (ub4); + OCIType *mtype = (OCIType *)0; + + text *name = (text*)"JENNY"; + ub4 name_len=(ub4)strlen( (char * ) name); + ub4 ssn = 808; /* Data for ssn */ + ub4 addr_hno = 800; /*Data for hno of addr */ + text *addr_street = (text *)"Laurel Road"; /*Data for street of addr */ + ub4 addr_streetLen = (ub4)strlen( (char *)addr_street); + ub4 altadrs_hno = 800; /*data for hno of altadrs */ + text *altadrs_street = (text *)"Shoreline Street"; /*Data for street of altadrs */ + ub4 altadrs_streetLen = (ub4)strlen( (char *)altadrs_street); + ub4 empno = 8888; /* data for empno */ + + sb4 index1 = 0; /* Index for the starting point of the scan */ + sb4 index2 = 0; /* Index of the next existing element */ + boolean eoc = TRUE; /* For getting the status for the availability of + the next index */ + ub4 count = 0; /* Loop counter */ + OCIHandleAlloc (envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0); + + if ((status = OCIStmtPrepare (stmthp, errhp, (text *)updateSql, + (ub4)strlen((char *)updateSql),OCI_NTV_SYNTAX, OCI_DEFAULT)) != OCI_SUCCESS) + { + printf ("OCIStmtPrepare - Fail\n"); + } + + if (( status = OCIObjectNew(envhp, errhp, svchp, OCI_TYPECODE_REF, + (OCIType *)0, (dvoid *)0, OCI_DURATION_DEFAULT, FALSE, + (dvoid **) &sub_ref)) != OCI_SUCCESS) + { + printf ("OCIObjectNew - Failure\n"); + } + + if ((status = OCIDefineByPos(stmthp, &defhp, errhp, (ub4) 1, + (dvoid *) 0, (sb4) 0, SQLT_REF, (dvoid *) 0, + (ub2 *)0, (ub2 *)0, (ub4) OCI_DEFAULT)) != OCI_SUCCESS) + { + printf ("OCIDefineByPos - Failure \n"); + } + + if ((status = OCIDefineObject(defhp, errhp, (OCIType *)0, + (dvoid **)&sub_ref, (ub4 *)&subSize, (dvoid **) 0, (ub4 *) 0)) + != OCI_SUCCESS) + { + printf ("OCIDefineObject - Failure \n"); + } + + printf ("\nExecuting the statement:%s\n", updateSql); + if (OCIStmtExecute (svchp, stmthp, errhp, (ub4)1, (ub4)0, + (OCISnapshot *)0, (OCISnapshot *)0, OCI_COMMIT_ON_SUCCESS ) != OCI_SUCCESS) + { + printf("OCIStmtExecute - Failure \n"); + } + else + { + printf("OCIStmtExecute - Success\n"); + if ((status = OCIObjectPin(envhp, errhp, sub_ref, (OCIComplexObject *)0, + OCI_PIN_ANY, OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **) &sub_obj)) != OCI_SUCCESS) + { + printf("OCIObjectPin - Failure \n"); + } + else + { + printf ("\nDisplaying the original data from the employee table \n"); + display (sub_obj); + printf ("\nModifying the data present in the object\n"); + if ((status = OCIObjectMarkUpdate (envhp, errhp, (dvoid *)sub_obj)) + != OCI_SUCCESS) + { + printf ("OCIObjectMarkUpdate - Fail\n"); + } + else + { + printf ("OCIObjectMarkUpdate - Success\n"); + } + OCINumberFromInt (errhp, (dvoid *)&ssn, sizeof(ssn), OCI_NUMBER_UNSIGNED, + &(sub_obj->_super.ssn)); + OCINumberFromInt (errhp, (dvoid *)&empno, sizeof(empno), + OCI_NUMBER_UNSIGNED, &(sub_obj->empno)); + OCINumberFromInt (errhp, (dvoid *)&addr_hno, sizeof(addr_hno), + OCI_NUMBER_UNSIGNED, &(sub_obj->_super.addr.hno)); + OCIStringAssignText (envhp, errhp, (text *)name, (ub2)name_len, + &(sub_obj->_super.name)); + OCIStringAssignText (envhp, errhp, (text *)addr_street, (ub2)addr_streetLen, + &(sub_obj->_super.addr.street)); + OCITableFirst(envhp, errhp, (CONST OCITable*)sub_obj->_super.altadrs, + &index1); + OCICollGetElem(envhp, errhp, (OCIColl *)sub_obj->_super.altadrs, + index1, (boolean *)&eoc, (dvoid **)&elemptr, (dvoid **)0); + OCINumberFromInt (errhp, (dvoid *)&altadrs_hno, sizeof(altadrs_hno), + OCI_NUMBER_UNSIGNED, &(elemptr->hno)); + OCIStringAssignText (envhp, errhp, (text *)altadrs_street, (ub2)altadrs_streetLen, + &(elemptr->street)); + for (count = 0; count < NUMREC-1; ++count) + { + altadrs_hno += count; + OCITableNext(envhp, errhp, index1, + (CONST OCITable*) sub_obj->_super.altadrs, &index2, &eoc); + OCICollGetElem(envhp, errhp, (OCIColl *)sub_obj->_super.altadrs, + index2, (boolean *)&eoc, (dvoid **)&elemptr, (dvoid **)0); + OCINumberFromInt (errhp, (dvoid *)&altadrs_hno, sizeof(altadrs_hno), + OCI_NUMBER_UNSIGNED, &(elemptr->hno)); + OCIStringAssignText (envhp, errhp, (text *)altadrs_street, (ub2)altadrs_streetLen, + &(elemptr->street)); + index1 = index2; + } + index1 = 0; + index2 = 0; + + OCITableFirst(envhp, errhp, (CONST OCITable*)sub_obj->workadd, &index1); + OCICollAssignElem (envhp, errhp, index1, (dvoid *)workadd[count], + (dvoid *)0, (OCIColl *)sub_obj->workadd); + for (count = 0; count < NUMREC; ++count) + { + OCITableNext(envhp, errhp, index1,(CONST OCITable*) sub_obj->workadd, + &index2, &eoc); + OCICollAssignElem (envhp, errhp, index1, (dvoid *)workadd[count], + (dvoid *)0, (OCIColl *)sub_obj->workadd); + index1 = index2; + } + + if ((status = OCIObjectFlush(envhp, errhp, sub_obj)) != OCI_SUCCESS) + { + printf ("OCIObjectFlush - Fail\n"); + } + else + { + printf ("OCIObjectFlush - Success\n"); + } + printf ("Refreshing the object\n"); + if ((status = OCIObjectRefresh(envhp, errhp, (dvoid *)sub_obj)) + != OCI_SUCCESS) + { + printf ("OCIObjectRefresh - Fail\n"); + } + else + { + printf ("OCIObjectRefresh - Success\n"); + } + printf ("\nDisplaying the data in the employee table after the refresh\n"); + display (sub_obj); + + printf ("\nModifying the data present in the object once again\n"); + ssn = 606; /* Data for ssn */ + addr_hno = 200; /*Data for hno of addr */ + addr_street = (text *)"Main Street"; /*Data for street of addr */ + addr_streetLen = (ub4)strlen( (char *)addr_street); + altadrs_hno = 600; /*data for hno of altadrs */ + altadrs_street = (text *)"Shell Blvd";/*Data for street of altadrs*/ + altadrs_streetLen = (ub4)strlen( (char *)altadrs_street); + empno = 6666; /* data for empno */ + + if ((status = OCIObjectMarkUpdate (envhp, errhp, (dvoid *)sub_obj)) + != OCI_SUCCESS) + { + printf ("OCIObjectMarkUpdate - Fail\n"); + } + else + { + printf ("OCIObjectMarkUpdate - Success\n"); + } + index1 = 0; + index2 = 0; + OCINumberFromInt (errhp, (dvoid *)&ssn, sizeof(ssn), OCI_NUMBER_UNSIGNED, + &(sub_obj->_super.ssn)); + OCINumberFromInt (errhp, (dvoid *)&empno, sizeof(empno), OCI_NUMBER_UNSIGNED, + &(sub_obj->empno)); + OCINumberFromInt (errhp, (dvoid *)&addr_hno, sizeof(addr_hno), + OCI_NUMBER_UNSIGNED, &(sub_obj->_super.addr.hno)); + OCIStringAssignText (envhp, errhp, (text *)addr_street, + (ub2)addr_streetLen, &(sub_obj->_super.addr.street)); + OCITableFirst(envhp, errhp,(CONST OCITable*)sub_obj->_super.altadrs, + &index1); + OCICollGetElem(envhp, errhp, (OCIColl *)sub_obj->_super.altadrs, + index1, (boolean *)&eoc, (dvoid **)&elemptr, (dvoid **)0); + OCINumberFromInt (errhp, (dvoid *)&altadrs_hno, sizeof(altadrs_hno), + OCI_NUMBER_UNSIGNED, &(elemptr->hno)); + OCIStringAssignText (envhp, errhp, (text *)altadrs_street, (ub2)altadrs_streetLen, + &(elemptr->street)); + for (count = 0; count < NUMREC-1; ++count) + { + altadrs_hno += count; + OCITableNext(envhp, errhp, index1,(CONST OCITable*) sub_obj->_super.altadrs, &index2, + &eoc); + OCICollGetElem(envhp, errhp, (OCIColl *)sub_obj->_super.altadrs, + index2, (boolean *)&eoc, (dvoid **)&elemptr, (dvoid **)0); + OCINumberFromInt (errhp, (dvoid *)&altadrs_hno, sizeof(altadrs_hno), + OCI_NUMBER_UNSIGNED, &(elemptr->hno)); + OCIStringAssignText (envhp, errhp, (text *)altadrs_street, (ub2)altadrs_streetLen, + &(elemptr->street)); + index1 = index2; + } + index1 = 0; + index2 = 0; + + OCITableFirst(envhp, errhp, (CONST OCITable*)sub_obj->workadd, &index1); + OCICollAssignElem (envhp, errhp, index1, (dvoid *)workadd[count], + (dvoid *)0, (OCIColl *)sub_obj->workadd); + for (count = 0; count < NUMREC; ++count) + { + OCITableNext(envhp, errhp, index1, (CONST OCITable*)sub_obj->workadd, + &index2, &eoc); + OCICollAssignElem (envhp, errhp, index1, (dvoid *)workadd[count], + (dvoid *)0, (OCIColl *)sub_obj->workadd); + index1 = index2; + } + if ((status = OCICacheFlush (envhp, errhp, svchp, NULL, NULL, &sub_ref)) + != OCI_SUCCESS) + { + printf ("OCICacheFlush - Fail\n"); + } + else + { + printf ("OCICacheFlush - Success\n"); + } + } + + if ((status = OCITransCommit (svchp, errhp, OCI_DEFAULT)) != OCI_SUCCESS) + { + printf ("OCITransCommit - Fail\n"); + } + else + printf ("OCITransCommit - Success\n"); + } + OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT); + +} /* end of modifyFunction() */ + +/* Function to display data from the table */ +static void selectFunction () +{ + OCIDefine *defhp = (OCIDefine *)0; + OCIRef *sub_ref = (OCIRef *)0; + i_manager *sub_obj = (i_manager *)0; + ub4 subSize = 0; + ub4 sizeUB4 = sizeof (ub4); + OCIType *mtype = (OCIType *)0; + + OCIHandleAlloc (envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0); + + if ((status = OCIStmtPrepare (stmthp, errhp, (text *)selectSql, + (ub4)strlen((char *)selectSql),OCI_NTV_SYNTAX, OCI_DEFAULT)) != OCI_SUCCESS) + { + printf ("OCIStmtPrepare - Fail\n"); + } + + if (( status = OCIObjectNew(envhp, errhp, svchp, OCI_TYPECODE_REF, + (OCIType *)0, (dvoid *)0, OCI_DURATION_DEFAULT, FALSE, + (dvoid **) &sub_ref)) != OCI_SUCCESS) + { + printf ("OCIObjectNew - Failure\n"); + } + + if ((status = OCIDefineByPos(stmthp, &defhp, errhp, (ub4) 1, + (dvoid *) 0, (sb4) 0, SQLT_REF, (dvoid *) 0, + (ub2 *)0, (ub2 *)0, (ub4) OCI_DEFAULT)) != OCI_SUCCESS) + { + printf ("OCIDefineByPos - Failure \n"); + } + + if ((status = OCIDefineObject(defhp, errhp, (OCIType *) 0, + (dvoid **)&sub_ref, (ub4 *)&subSize, (dvoid **) 0, (ub4 *) 0)) + != OCI_SUCCESS) + { + printf ("OCIDefineObject - Failure \n"); + } + + printf ("\nExecuting the statement:%s\n", selectSql); + if (OCIStmtExecute (svchp, stmthp, errhp, (ub4)1, (ub4)0, + (OCISnapshot *)0, (OCISnapshot *)0, OCI_DEFAULT ) != OCI_SUCCESS) + { + printf("OCIStmtExecute - Failure \n"); + } + else + { + printf("OCIStmtExecute - Success\n"); + if ((status = OCIObjectPin(envhp, errhp, sub_ref, (OCIComplexObject *)0, + OCI_PIN_ANY, OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **) &sub_obj)) != OCI_SUCCESS) + { + printf("OCIObjectPin - Failure \n"); + } + else + { + printf ("\nDisplaying the contents of the object\n"); + display (sub_obj); + } + } +} /* end of selectFunction() */ + +/* Function to display the attributes of the object */ +static void display (i_manager *sub_obj) +{ + ub4 sizeUB4 = sizeof (ub4); + ub4 ssn = 0; /* Variable to fetch ssn */ + ub4 addr_hno = 0; /*Variable to fetch hno of addr */ + text *name; /*Variable to fetch name */ + ub4 name_len = 0; + text *addr_street; /*Variable to fetch street of addr */ + ub4 addr_streetLen = 0; + ub4 altadrs_hno = 0; /*Variable to fetch hno of altadrs */ + text *altadrs_street; /*Variable to fetch street of altadrs */ + ub4 altadrs_streetLen = 0; + ub4 empno = 0; /* Variable to fetch empno */ + ub4 workadd_hno = 0; /*Variable to fetch hno of workadd */ + text *workadd_street; /*Variable to fetch street of workadd */ + ub4 workadd_streetLen = 0; + + sb4 size = 111; + sb4 index1 = 0; /* Index for the starting point of the scan */ + sb4 index2 = 0; /* Index of the next existing element */ + boolean eoc = TRUE; /* For getting the status for the availability of + the next index */ + ub4 count = 0; + i_residence *elem = (i_residence *)0; /* To get the element from the + nested table */ + i_residence_ref *elemref = (i_residence_ref *)0; + i_residence *objptr = (i_residence *)0; + + name = OCIStringPtr(envhp, sub_obj->_super.name); + name_len = OCIStringSize (envhp, sub_obj->_super.name); + printf("name is : %.*s\n", name_len, name); + OCINumberToInt (errhp, &(sub_obj->_super.ssn), sizeof(ub4), + OCI_NUMBER_UNSIGNED, (dvoid *)&ssn); + printf("SSN: %d\n", ssn); + OCINumberToInt (errhp, &(sub_obj->_super.addr.hno), sizeof(ub4), + OCI_NUMBER_UNSIGNED, (dvoid *)&addr_hno); + addr_street = OCIStringPtr(envhp, sub_obj->_super.addr.street); + addr_streetLen = OCIStringSize (envhp, sub_obj->_super.addr.street); + printf("Primary address: %d %.*s\n", addr_hno,addr_streetLen, addr_street); + + OCITableSize(envhp, errhp, (CONST OCITable*)(sub_obj->_super.altadrs), &size); + OCITableFirst(envhp, errhp,(CONST OCITable*)sub_obj->_super.altadrs, &index1); + status = OCICollGetElem(envhp, errhp, (OCIColl *)sub_obj->_super.altadrs, + index1, (boolean *)&eoc, (dvoid **)&elem, (dvoid **)0); + OCINumberToInt (errhp, &(elem->hno), sizeof(ub4), + OCI_NUMBER_UNSIGNED, (dvoid *)&altadrs_hno); + altadrs_street = OCIStringPtr(envhp, elem->street); + altadrs_streetLen = OCIStringSize (envhp, elem->street); + printf("Other addresses:\n"); + printf(" %d %.*s\n", altadrs_hno, altadrs_streetLen, + altadrs_street); + for (count = 1; count < size; count++) + { + OCITableNext(envhp, errhp, index1, + (CONST OCITable*)sub_obj->_super.altadrs, &index2, &eoc); + OCICollGetElem(envhp, errhp,(OCIColl *)sub_obj->_super.altadrs, index2, + (boolean *)&eoc, (dvoid **)&elem, (dvoid **)0); + OCINumberToInt (errhp, &(elem->hno), sizeof(ub4), OCI_NUMBER_UNSIGNED, + (dvoid *)&altadrs_hno); + altadrs_street = OCIStringPtr(envhp, elem->street); + altadrs_streetLen = OCIStringSize (envhp, elem->street); + printf(" %d %.*s\n", altadrs_hno, altadrs_streetLen, + altadrs_street); + index1 = index2; + } + + OCINumberToInt (errhp, &(sub_obj->empno), sizeof(ub4), + OCI_NUMBER_UNSIGNED, (dvoid *)&empno); + printf("EMPNO: %d\n", empno); + + index1 = 1; + eoc = TRUE; + OCITableSize(envhp, errhp, (CONST OCITable*) sub_obj->workadd, &size); + OCITableFirst(envhp, errhp,(CONST OCITable*) sub_obj->workadd, &index1); + status = OCICollGetElem(envhp, errhp, (OCIColl *)(sub_obj->workadd), + index1, (boolean *)&eoc, (dvoid **)&elemref, (dvoid **)0); + if (status != OCI_SUCCESS) + { + printf("OCICollGetElem - Failure \n"); + } + elemref = *( OCIRef **)elemref; + + if ((status = OCIObjectPin(envhp, errhp, elemref, + (OCIComplexObject *)0, + OCI_PIN_ANY, OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **) &objptr)) != OCI_SUCCESS) + { + printf("OCIObjectPin - Failure \n"); + } + + OCINumberToInt (errhp, &(objptr->hno), sizeof(ub4), OCI_NUMBER_UNSIGNED, + (dvoid *)&workadd_hno); + + workadd_street = OCIStringPtr(envhp, objptr->street); + workadd_streetLen = OCIStringSize (envhp, objptr->street); + printf("Work Addresses:\n"); + printf(" %d %.*s\n", workadd_hno,workadd_streetLen, + workadd_street); + for (count = 1; count < size; count++) + { + OCITableNext(envhp, errhp, index1, + (CONST OCITable*)sub_obj->workadd, &index2, &eoc); + status = OCICollGetElem(envhp, errhp, (OCIColl *)(sub_obj->workadd), + index2, (boolean *)&eoc, (dvoid **)&elemref, (dvoid **)0); + if (status != OCI_SUCCESS) + { + printf("OCICollGetElem - Failure \n"); + } + elemref = *( OCIRef **)elemref; + + if ((status = OCIObjectPin(envhp, errhp, elemref, + (OCIComplexObject *)0, + OCI_PIN_ANY, OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **) &objptr)) != OCI_SUCCESS) + { + printf("OCIObjectPin - Failure \n"); + } + OCINumberToInt (errhp, &(objptr->hno), sizeof(ub4), OCI_NUMBER_UNSIGNED, + (dvoid *)&workadd_hno); + + workadd_street = OCIStringPtr(envhp, objptr->street); + workadd_streetLen = OCIStringSize (envhp, objptr->street); + printf(" %d %.*s\n", workadd_hno,workadd_streetLen, + workadd_street); + index1 = index2; + } +} /* end of display ((i_manager *) */ + +/* Function to get an array of REFs to populate the varray of REFs*/ +static void getRef() +{ + OCIDefine *defhp = (OCIDefine *) 0; /* For the REF column */ + i_residence *sub_obj[NUMREC]; + ub4 subsize[NUMREC]; + ub4 pos = 0; + ub4 arraySize = NUMREC; + + OCIHandleAlloc(envhp, (dvoid **) &stmthp, OCI_HTYPE_STMT, (size_t) 0, + ((dvoid **) 0)); + + if((status = OCIStmtPrepare(stmthp, errhp, (text *) selRef, + (ub4) strlen((char *) selRef), OCI_NTV_SYNTAX, OCI_DEFAULT)) != OCI_SUCCESS) + { + printf("OciStmtPrepare - Failure\n"); + } + + if((status = OCIObjectNew(envhp, errhp, svchp, OCI_TYPECODE_REF, + (OCIType *) 0, (dvoid *) 0, OCI_DURATION_DEFAULT, FALSE, + (dvoid **) workadd)) != OCI_SUCCESS) + { + printf("OCIObjectNew - Failure\n"); + } + + if((status = OCIDefineByPos(stmthp, &defhp, errhp, (ub4) 1, (dvoid *) 0, + (sb4) 0, SQLT_REF, (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) OCI_DEFAULT )) + != OCI_SUCCESS) + { + printf("OCIDefineByPos - Failure\n"); + } + + if((status = OCIDefineObject(defhp, errhp, (OCIType *) 0, (dvoid **) workadd, + subsize, (dvoid **) 0, (ub4 *) 0)) != OCI_SUCCESS) + { + printf("OCIDefineObject - failure\n"); + } + + if((status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) NUMREC, (ub4) 0, + (OCISnapshot *) 0, (OCISnapshot *) 0, OCI_DEFAULT)) != OCI_SUCCESS) + { + printf("OCIStmtExecute - Failure\n"); + } + else + { + if((status = OCIObjectArrayPin(envhp, errhp, workadd, (ub4) arraySize, + (OCIComplexObject **) 0, 0, OCI_PIN_ANY, OCI_DURATION_SESSION, + OCI_LOCK_NONE, (dvoid **) sub_obj, (ub4 *) &pos)) != OCI_SUCCESS) + { + printf("OCIObjectArrayPin - Failure\n"); + } + } + OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT); +} /* End of getRef() */ + +/* Freeing the allocated handles */ +static void cleanup () +{ + OCISessionEnd (svchp, errhp, sesnhp, OCI_DEFAULT ); + OCIHandleFree((dvoid *) sesnhp, OCI_HTYPE_SESSION); + OCIServerDetach(svrhp, errhp, OCI_DEFAULT ); + OCIHandleFree((dvoid *) svrhp, OCI_HTYPE_SERVER); + OCIHandleFree((dvoid *) svchp, OCI_HTYPE_SVCCTX); + OCIHandleFree((dvoid *) errhp, OCI_HTYPE_ERROR); + return; +}/* End of cleanup() */ + + diff --git a/cdemoin1.h b/cdemoin1.h new file mode 100644 index 0000000..edde208 --- /dev/null +++ b/cdemoin1.h @@ -0,0 +1,85 @@ +/* Copyright (c) Oracle Corporation 1995. All Rights Reserved. */ + +/* + NAME + i_residence - Demo program which modifies an inherited type in a table and + displays a record from the table. + + DESCRIPTION + This program pins an inherited instance in the object cache and displays + the attributes in it. It also updates a record of a table. + + RELATED DOCUMENTS + + + NOTES + MODIFIED + rdwajan 08/11/00 Created +*/ +#include +#include + +#ifndef CDEMOIN1_ORACLE +# define CDEMOIN1_ORACLE + +#ifndef OCI_ORACLE +# include +#endif + +typedef OCIRef i_manager_ref; +typedef OCIArray i_residence_arr; +typedef OCIRef i_people_ref; +typedef OCIRef i_residence_ref; +typedef OCITable i_residence_nest; + +struct i_residence +{ + OCINumber hno; + OCIString * street; +}; +typedef struct i_residence i_residence; + +struct i_residence_ind +{ + OCIInd _atomic; + OCIInd hno; + OCIInd street; +}; +typedef struct i_residence_ind i_residence_ind; + +struct i_people +{ + OCIString * name; + OCINumber ssn; + struct i_residence addr; + i_residence_nest * altadrs; +}; +typedef struct i_people i_people; + +struct i_people_ind +{ + OCIInd _atomic; + OCIInd name; + OCIInd ssn; + struct i_residence_ind addr; + OCIInd altadrs; +}; +typedef struct i_people_ind i_people_ind; + +struct i_manager +{ + i_people _super; + OCINumber empno; + i_residence_arr * workadd; +}; +typedef struct i_manager i_manager; + +struct i_manager_ind +{ + i_people _super; + OCIInd empno; + OCIInd workadd; +}; +typedef struct i_manager_ind i_manager_ind; + +#endif diff --git a/cdemoin1.sql b/cdemoin1.sql new file mode 100644 index 0000000..536f084 --- /dev/null +++ b/cdemoin1.sql @@ -0,0 +1,66 @@ +/* Copyright (c) Oracle Corporation 1995. All Rights Reserved. */ + +/* + NAME + cdemoin1 - Demo program which modifies an inherited type in a table and + displays a record from the table. + + DESCRIPTION + This program pins an inherited instance in the object cache and displays + the attributes in it. It also updates a record of a table. + + MODIFIED + rdwajan 08/29/00 Created + +*/ + +SET SERVEROUTPUT ON +CONNECT scott/tiger; + +DROP TABLE i_manager_tab; +DROP TABLE i_people_tab; +DROP TABLE i_residence_tab; +DROP TYPE i_manager; +DROP TYPE i_people; +DROP TYPE i_residence_nest; +DROP TYPE i_residence_arr; +DROP TYPE i_residence; + +CREATE TYPE i_residence AS OBJECT +( hno NUMBER, street VARCHAR2(50) ) +/ + +CREATE TYPE i_residence_arr AS VARRAY(3) OF REF i_residence; +/ +CREATE TYPE i_residence_nest AS TABLE OF i_residence; +/ + +CREATE TYPE i_people AS OBJECT +(name VARCHAR2(10), ssn NUMBER, addr i_residence, atladrs i_residence_nest) NOT FINAL; +/ + +CREATE TYPE i_manager UNDER i_people +( empno NUMBER, workadd i_residence_arr) ; +/ + +CREATE TABLE i_residence_tab OF i_residence; + +INSERT INTO i_residence_tab values (100, 'Oracle Parkway'); +INSERT INTO i_residence_tab values (200, 'Oracle Parkway'); +INSERT INTO i_residence_tab values (300, 'Oracle Parkway'); + +CREATE TABLE i_people_tab OF i_people +NESTED TABLE atladrs STORE AS i_people_nt_tab1; + +CREATE TABLE i_manager_tab OF i_manager +NESTED TABLE atladrs STORE AS i_manager_nt_tab2; + +INSERT INTO i_manager_tab VALUES (i_manager('ROOPA',101, +i_residence (1000, 'Silver Blvd'), +i_residence_nest (i_residence (201, 'Willow Road'), i_residence (505, 'Springfield St')), +45001, +i_residence_arr ((SELECT REF(a) FROM i_residence_tab a WHERE a.hno = 100), +(SELECT REF(a) FROM i_residence_tab a WHERE a.hno = 200), +(SELECT REF(a) FROM i_residence_tab a WHERE a.hno = 300))) ); + +COMMIT; diff --git a/cdemoin2.c b/cdemoin2.c new file mode 100644 index 0000000..4f5da53 --- /dev/null +++ b/cdemoin2.c @@ -0,0 +1,488 @@ +/* Copyright (c) Oracle Corporation 1996, 1997, 1998. All Rights Reserved. */ + +/* + + NAME + cdemoin2 - Demo program to perform attribute substitutability. + + DESCRIPTION + This program demonstrates attribute substitutability, wherein a column + which is of REF to a supertype is substituted with a REF to a subtype. + All the data from the table are then displayed. + + + NOTES + dependent files : + cdemoin2.h - Header file + cdemoin2.sql - SQL script to be run before execution + cdemoin2.tsc - test script (optional) + + Program Notes : + + MODIFIED (MM/DD/YY) + rdwajan 08/25/00 - Creation +*/ + +#include "cdemoin2.h" + +static OCIError *errhp = (OCIError *)0; +static OCIEnv *envhp = (OCIEnv *)0; +static OCIServer *svrhp = (OCIServer *)0; +static OCISession *sesnhp = (OCISession *)0; +static OCISvcCtx *svchp = (OCISvcCtx *)0; +static OCIStmt *stmthp = (OCIStmt *)0; + +static text *database =(text *)""; +static text *username =(text *)"scott"; +static text *password =(text *)"tiger"; + +static text *updateSql1 = (text *) + "UPDATE cdemoin2_person_tab SET vacation_home = :v1 WHERE ssn = 999"; + +static text *updateSql2 = (text *) + "UPDATE cdemoin2_person_tab SET first_home = :v1 WHERE ssn = 999"; + +static text *getRefSql1 = (text *) + "SELECT REF(a) FROM cdemoin2_address_tab a WHERE a.hno = 300"; + +static text *getRefSql2 = (text *) + "SELECT REF(a) FROM cdemoin2_sec_address_tab a WHERE a.hno = 100"; + +static text *displaySql = (text *) +"SELECT vacation_home, first_home FROM cdemoin2_person_tab"; +/* where deref(vacation_home) is of (cdemoin2_sec_address, cdemoin2_address)";*/ + +/* Free the allocated handles */ +static void cleanup (void); + +/* Check for errors */ +void checkerr (OCIError *errhp, sword status); + +/* Function to display the records before updation*/ +static void displayFunction1(); + +/* Function to display the records after updation*/ +static void displayFunction2(); + +/* Function to modify the REF column to show substitutability */ +static void updateFunction(text *getRefSql, text *updateSql); + +sword status = 0; + +int main (void) +{ + printf("cdemoin2 - Demo program to perform attribute substitutability\n"); + /* Initializing the environment in the Object mode*/ + OCIEnvCreate (&envhp, OCI_OBJECT, (dvoid *)0, (dvoid * (*)()) 0, + (dvoid * (*)()) 0, (dvoid (*)()) 0, 0, (dvoid *)0); + + OCIHandleAlloc (envhp, (dvoid **)&errhp, OCI_HTYPE_ERROR, (size_t)0, + (dvoid **)0); + + OCIHandleAlloc(envhp, (dvoid **)&svrhp, OCI_HTYPE_SERVER, (size_t)0, + (dvoid **)0); + + status = OCIServerAttach(svrhp, errhp, (text *)database, + (sb4)strlen((char *)database), OCI_DEFAULT); + + if (status != OCI_SUCCESS) + { + printf("OCIServerAttach failed \n"); + checkerr(errhp, status); + } + else + printf("OCIServerAttach - Success \n"); + + OCIHandleAlloc(envhp, (dvoid **)&svchp, OCI_HTYPE_SVCCTX, (size_t)0, + (dvoid **)0); + OCIAttrSet(svchp, OCI_HTYPE_SVCCTX, (dvoid *)svrhp, (ub4)0, OCI_ATTR_SERVER, + errhp); + + OCIHandleAlloc(envhp, (dvoid **)&sesnhp, OCI_HTYPE_SESSION, (size_t)0, + (dvoid **)0); + + OCIAttrSet(sesnhp, OCI_HTYPE_SESSION, (dvoid *)username, + (ub4)strlen((char *)username), OCI_ATTR_USERNAME, errhp); + + OCIAttrSet(sesnhp, OCI_HTYPE_SESSION, (dvoid*)password, + (ub4)strlen((char *)password), OCI_ATTR_PASSWORD, errhp); + + printf("Connecting as %s/%s@%s\n",username,password,database); + + status = OCISessionBegin(svchp, errhp, sesnhp, OCI_CRED_RDBMS, OCI_DEFAULT); + if (status != OCI_SUCCESS) + { + printf("Connection failed \n"); + checkerr(errhp, status); + } + else + printf("Connection - Success \n"); + + OCIAttrSet(svchp, OCI_HTYPE_SVCCTX, sesnhp, (ub4)0, OCI_ATTR_SESSION, errhp); + + /* Function to display records before updation*/ + printf ("Displaying records before updation\n"); + displayFunction1(); + + /* Substituting a REF of a subtype with a REF of a supertype */ + updateFunction(getRefSql1, updateSql1); + + /* Substituting a REF of a supertype with a REF of a subtype */ + updateFunction(getRefSql2, updateSql2); + + /* Function to display records after updation*/ + printf ("Displaying records after updation\n"); + displayFunction2(); + + /* Free the allocated handles */ + cleanup(); + + printf("cdemoin2 - Done\n"); +} /* End of main() */ + +/* Function to display the contents of the table before updation*/ +static void displayFunction1 () +{ + OCIDefine *def1hp = (OCIDefine *)0; /* For vacation_home */ + OCIDefine *def2hp = (OCIDefine *)0; /* For first_home */ + OCIRef *s_ref = (OCIRef *)0; + OCIRef *ref = (OCIRef *)0; + cdemoin2_sec_address *s_obj = (cdemoin2_sec_address *)0; + cdemoin2_address *obj = (cdemoin2_address *)0; + ub4 subSize = 0; + sb4 size = 0; + + ub4 hno = 0; /* Variable to fetch hno */ + ub4 sizeUB4 = sizeof (ub4); + text *street; /* Variable to fetch street */ + ub4 streetLength = 0; + text *city; /* Variable to fetch city */ + ub4 cityLength = 0; + text *state; /* Variable to fetch state */ + ub4 stateLength = 0; + + OCIHandleAlloc (envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0); + + if ((status = OCIStmtPrepare (stmthp, errhp, (text *)displaySql, + (ub4)strlen(displaySql), OCI_NTV_SYNTAX, OCI_DEFAULT)) != OCI_SUCCESS) + { + printf ("OCIStmtPrepare - Fail\n"); + checkerr (errhp, status); + } + + if (status = OCIDefineByPos(stmthp, &def1hp, errhp, (ub4)1, (dvoid *)0, + (ub4)0, SQLT_REF, (dvoid *)0, (ub2 *)0, (ub2 *)0, + OCI_DEFAULT) != OCI_SUCCESS) + { + printf("OCIDefineByPos - Failure \n"); + checkerr(errhp, status); + } + + if (status = OCIDefineByPos(stmthp, &def2hp, errhp, (ub4)2, (dvoid *)0, + (ub4)0, SQLT_REF, (dvoid *)0, (ub2 *)0, (ub2 *)0, + OCI_DEFAULT) != OCI_SUCCESS) + { + printf("OCIDefineByPos - Failure \n"); + checkerr(errhp, status); + } + + if (status = OCIDefineObject(def1hp, errhp, (OCIType *)NULL, + (dvoid **)&s_ref, (ub4 *)0, (dvoid **)0, (ub4)0) != OCI_SUCCESS) + { + printf("OCIDefineObject - Failure \n"); + checkerr(errhp, status); + } + + if (status = OCIDefineObject(def2hp, errhp, (OCIType *)NULL, + (dvoid **)&ref, (ub4 *)0, (dvoid **)0, (ub4)0) != OCI_SUCCESS) + { + printf("OCIDefineObject - Failure \n"); + checkerr(errhp, status); + } + + printf ("Executing the statement:%s\n", displaySql); + if (status = OCIStmtExecute (svchp, stmthp, errhp, (ub4)1, (ub4)0, + (OCISnapshot *)0, (OCISnapshot *)0, OCI_DEFAULT ) != OCI_SUCCESS) + { + printf("OCIStmtExecute - Failure \n"); + checkerr (errhp, status); + } + else + { + printf("OCIStmtExecute - Success\n"); + if (status = OCIObjectPin(envhp, errhp, ref, + (OCIComplexObject *)0, OCI_PIN_ANY, OCI_DURATION_SESSION, + OCI_LOCK_NONE, (dvoid **)&obj) != OCI_SUCCESS) + { + printf("OCIObjectPin - Failure \n"); + checkerr(errhp, status); + } + if (status = OCIObjectPin(envhp, errhp, s_ref, + (OCIComplexObject *)0, OCI_PIN_ANY, OCI_DURATION_SESSION, + OCI_LOCK_NONE, (dvoid **)&s_obj) != OCI_SUCCESS) + { + printf("OCIObjectPin - Failure \n"); + checkerr(errhp, status); + } + printf ("Col2 data\n"); + OCINumberToInt (errhp, &(s_obj->_super.hno), sizeUB4, + OCI_NUMBER_UNSIGNED, (dvoid *)&hno); + printf("HNO: %d\n", hno); + street = OCIStringPtr(envhp, s_obj->_super.street); + streetLength = OCIStringSize (envhp, s_obj->_super.street); + printf("STREET: %.*s\n", streetLength, street); + city = OCIStringPtr(envhp, s_obj->city); + cityLength = OCIStringSize (envhp, s_obj->city); + printf("CITY: %.*s\n", cityLength, city); + state = OCIStringPtr(envhp, s_obj->state); + stateLength = OCIStringSize (envhp, s_obj->state); + printf("STATE: %.*s\n", stateLength, state); + printf ("Col3 data\n"); + OCINumberToInt (errhp, &(obj->hno), sizeUB4, + OCI_NUMBER_UNSIGNED, (dvoid *)&hno); + printf("HNO: %d\n", hno); + street = OCIStringPtr(envhp, obj->street); + streetLength = OCIStringSize (envhp, obj->street); + printf("STREET: %.*s\n", streetLength, street); + } + OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT); +} /* end of displayFunction1() */ + +/* Function to display the contents of the table after updation*/ +static void displayFunction2 () +{ + OCIDefine *def1hp = (OCIDefine *)0; /* For vacation_home */ + OCIDefine *def2hp = (OCIDefine *)0; /* For first_home */ + OCIRef *s_ref = (OCIRef *)0; + OCIRef *ref = (OCIRef *)0; + cdemoin2_sec_address *s_obj = (cdemoin2_sec_address *)0; + cdemoin2_address *obj = (cdemoin2_address *)0; + ub4 subSize = 0; + sb4 size = 0; + + ub4 hno = 0; /* Variable to fetch hno */ + ub4 sizeUB4 = sizeof (ub4); + text *street; /* Variable to fetch street */ + ub4 streetLength = 0; + text *city; /* Variable to fetch city */ + ub4 cityLength = 0; + text *state; /* Variable to fetch state */ + ub4 stateLength = 0; + + OCIHandleAlloc (envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0); + + if ((status = OCIStmtPrepare (stmthp, errhp, (text *)displaySql, + (ub4)strlen(displaySql), OCI_NTV_SYNTAX, OCI_DEFAULT)) != OCI_SUCCESS) + { + printf ("OCIStmtPrepare - Fail\n"); + checkerr (errhp, status); + } + + if (status = OCIDefineByPos(stmthp, &def1hp, errhp, (ub4)1, (dvoid *)0, + (ub4)0, SQLT_REF, (dvoid *)0, (ub2 *)0, (ub2 *)0, + OCI_DEFAULT) != OCI_SUCCESS) + { + printf("OCIDefineByPos - Failure \n"); + checkerr(errhp, status); + } + + if (status = OCIDefineByPos(stmthp, &def2hp, errhp, (ub4)2, (dvoid *)0, + (ub4)0, SQLT_REF, (dvoid *)0, (ub2 *)0, (ub2 *)0, + OCI_DEFAULT) != OCI_SUCCESS) + { + printf("OCIDefineByPos - Failure \n"); + checkerr(errhp, status); + } + + if (status = OCIDefineObject(def1hp, errhp, (OCIType *)NULL, + (dvoid **)&ref, (ub4 *)0, (dvoid **)0, (ub4)0) != OCI_SUCCESS) + { + printf("OCIDefineObject - Failure \n"); + checkerr(errhp, status); + } + + if (status = OCIDefineObject(def2hp, errhp, (OCIType *)NULL, + (dvoid **)&s_ref, (ub4 *)0, (dvoid **)0, (ub4)0) != OCI_SUCCESS) + { + printf("OCIDefineObject - Failure \n"); + checkerr(errhp, status); + } + + printf ("Executing the statement:%s\n", displaySql); + if (status = OCIStmtExecute (svchp, stmthp, errhp, (ub4)1, (ub4)0, + (OCISnapshot *)0, (OCISnapshot *)0, OCI_DEFAULT ) != OCI_SUCCESS) + { + printf("OCIStmtExecute - Failure \n"); + checkerr (errhp, status); + } + else + { + printf("OCIStmtExecute - Success\n"); + if (status = OCIObjectPin(envhp, errhp, ref, + (OCIComplexObject *)0, OCI_PIN_ANY, OCI_DURATION_SESSION, + OCI_LOCK_NONE, (dvoid **)&obj) != OCI_SUCCESS) + { + printf("OCIObjectPin - Failure \n"); + checkerr(errhp, status); + } + if (status = OCIObjectPin(envhp, errhp, s_ref, + (OCIComplexObject *)0, OCI_PIN_ANY, OCI_DURATION_SESSION, + OCI_LOCK_NONE, (dvoid **)&s_obj) != OCI_SUCCESS) + { + printf("OCIObjectPin - Failure \n"); + checkerr(errhp, status); + } + printf ("Col2 data\n"); + OCINumberToInt (errhp, &(obj->hno), sizeUB4, + OCI_NUMBER_UNSIGNED, (dvoid *)&hno); + printf("HNO: %d\n", hno); + street = OCIStringPtr(envhp, obj->street); + streetLength = OCIStringSize (envhp, obj->street); + printf("STREET: %.*s\n", streetLength, street); + printf ("Col3 data\n"); + OCINumberToInt (errhp, &(s_obj->_super.hno), sizeUB4, + OCI_NUMBER_UNSIGNED, (dvoid *)&hno); + printf("HNO: %d\n", hno); + street = OCIStringPtr(envhp, s_obj->_super.street); + streetLength = OCIStringSize (envhp, s_obj->_super.street); + printf("STREET: %.*s\n", streetLength, street); + city = OCIStringPtr(envhp, s_obj->city); + cityLength = OCIStringSize (envhp, s_obj->city); + printf("CITY: %.*s\n", cityLength, city); + state = OCIStringPtr(envhp, s_obj->state); + stateLength = OCIStringSize (envhp, s_obj->state); + printf("STATE: %.*s\n", stateLength, state); + } + OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT); +} /* end of displayFunction2() */ + +static void updateFunction(text *getRefSql, text *updateSql) +{ + OCIRef *ref = (OCIRef *)0; + OCIDefine *defhp = (OCIDefine *)0; + ub4 subSize = 0; + OCIBind *bindhp = (OCIBind *)0; + sb4 sizeRef = sizeof (OCIRef *); + OCIHandleAlloc (envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0); + + if ((status = OCIStmtPrepare (stmthp, errhp, (text *)getRefSql, + (ub4)strlen(getRefSql), OCI_NTV_SYNTAX, OCI_DEFAULT)) != OCI_SUCCESS) + { + printf ("OCIStmtPrepare - Fail\n"); + checkerr (errhp, status); + } + if (( status = OCIObjectNew(envhp, errhp, svchp, OCI_TYPECODE_REF, + (OCIType *)0, (dvoid *)0, OCI_DURATION_DEFAULT, FALSE, + (dvoid **) &ref)) != OCI_SUCCESS) + { + printf ("OCIObjectNew - Failure\n"); + checkerr (errhp, status); + } + + if ((status = OCIDefineByPos(stmthp, &defhp, errhp, (ub4) 1, (dvoid *) 0, + (sb4) 0, SQLT_REF, (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) OCI_DEFAULT)) != OCI_SUCCESS) + { + printf ("OCIDefineByPos - Failure \n"); + checkerr (errhp, status); + } + + if ((status = OCIDefineObject(defhp, errhp, (OCIType *) 0, + (dvoid **) &ref, &subSize, (dvoid **) 0, (ub4 *) 0)) != OCI_SUCCESS) + { + printf ("OCIDefineObject - Failure \n"); + checkerr (errhp, status); + } + if (status = OCIStmtExecute (svchp, stmthp, errhp, (ub4)1, (ub4)0, + (OCISnapshot *)0, (OCISnapshot *)0, OCI_DEFAULT ) != OCI_SUCCESS) + { + printf("OCIStmtExecute - Failure \n"); + checkerr (errhp, status); + } + else + { + if ((status = OCIStmtPrepare (stmthp, errhp, (text *)updateSql, + (ub4)strlen(updateSql), OCI_NTV_SYNTAX, OCI_DEFAULT)) != OCI_SUCCESS) + { + printf ("OCIStmtPrepare - Fail\n"); + checkerr (errhp, status); + } + + if ((status = OCIBindByPos(stmthp, &bindhp, errhp, (ub4) 1, (dvoid *) 0, + sizeRef, SQLT_REF, (dvoid *) 0, (ub2 *)0, (ub2 *)0, (ub4)0, + (ub4 *)0, (ub4) OCI_DEFAULT)) != OCI_SUCCESS) + { + printf ("OCIBindByPos - Failure \n"); + checkerr (errhp, status); + } + + if (status = OCIBindObject(bindhp, errhp, (OCIType *)0, (dvoid **) &ref, + (ub4 *) &subSize, (dvoid **)0 , (ub4 *) 0) != OCI_SUCCESS) + { + printf("OCIBindObject - Failure \n"); + checkerr(errhp, status); + } + printf ("Executing the statement:%s\n", updateSql); + if (status = OCIStmtExecute (svchp, stmthp, errhp, (ub4)1, (ub4)0, + (OCISnapshot *)0, (OCISnapshot *)0, OCI_DEFAULT ) != OCI_SUCCESS) + { + printf("OCIStmtExecute - Failure \n"); + checkerr (errhp, status); + } + else + { + printf("OCIStmtExecute - Success\n"); + } + } + OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT); +} /* end of updateFunction(text *, text *) */ + +/* Freeing the allocated handles */ +static void cleanup () +{ + OCISessionEnd (svchp, errhp, sesnhp, OCI_DEFAULT ); + OCIHandleFree((dvoid *) sesnhp, OCI_HTYPE_SESSION); + OCIServerDetach(svrhp, errhp, OCI_DEFAULT ); + OCIHandleFree((dvoid *) svrhp, OCI_HTYPE_SERVER); + OCIHandleFree((dvoid *) svchp, OCI_HTYPE_SVCCTX); + OCIHandleFree((dvoid *) errhp, OCI_HTYPE_ERROR); + return; +}/* End of cleanup() */ + +/* check for the errors */ +void checkerr (OCIError *err, sword status) +{ + text errbuf[514]; + sb4 errcode; + + switch (status) + { + case OCI_SUCCESS : + break; + case OCI_SUCCESS_WITH_INFO : + OCIErrorGet (err, 1, (text *)0, + (sb4 *)&errcode, errbuf, 514, + OCI_HTYPE_ERROR); + printf ("Warning %d : %.*s\n", errcode, 514, errbuf); + break; + case OCI_NO_DATA : + printf ("*** No Data Found *** \n"); + break; + case OCI_INVALID_HANDLE : + printf ("*** Invalid Handle *** \n"); + exit (-5); + case OCI_ERROR : + OCIErrorGet (err, 1, (text *)0, + (sb4 *)&errcode, errbuf, 514, + OCI_HTYPE_ERROR); + printf ("ERROR %d : %.*s\n", errcode, 514, errbuf); + break; + default : + printf ("*** Unknown Status *** \n"); + break; + } +} + diff --git a/cdemoin2.h b/cdemoin2.h new file mode 100644 index 0000000..a9ddcac --- /dev/null +++ b/cdemoin2.h @@ -0,0 +1,63 @@ +/* Copyright (c) Oracle Corporation 1995. All Rights Reserved. */ + +/* + NAME + cdemoin2 - Demo program to perform attribute substitutability. + + DESCRIPTION + This program demonstrates attribute substitutability, wherein a column + which is of REF to a supertype is substituted with a REF to a subtype. + All the data from the table are then displayed. + + NOTES + dependent files : + cdemoin2.c - Source file. + cdemoin2.sql - SQL File to be run before execution of the test. + cdemoin2.tsc - Optional, test script file. + + MODIFIED + rdwajan 08/11/00 Created +*/ + +#ifndef CDEMOIN2_ORACLE +# define CDEMOIN2_ORACLE + +#ifndef OCI_ORACLE +# include +#endif + +typedef OCIRef cdemoin2_sec_address_ref; +typedef OCIRef cdemoin2_address_ref; + +struct cdemoin2_address +{ + OCINumber hno; + OCIString * street; +}; +typedef struct cdemoin2_address cdemoin2_address; + +struct cdemoin2_address_ind +{ + OCIInd _atomic; + OCIInd hno; + OCIInd street; +}; +typedef struct cdemoin2_address_ind cdemoin2_address_ind; + +struct cdemoin2_sec_address +{ + cdemoin2_address _super; + OCIString * city; + OCIString * state; +}; +typedef struct cdemoin2_sec_address cdemoin2_sec_address; + +struct cdemoin2_sec_address_ind +{ + cdemoin2_address _super; + OCIInd city; + OCIInd state; +}; +typedef struct cdemoin2_sec_address_ind cdemoin2_sec_address_ind; + +#endif diff --git a/cdemoin2.sql b/cdemoin2.sql new file mode 100644 index 0000000..6498dc9 --- /dev/null +++ b/cdemoin2.sql @@ -0,0 +1,52 @@ +/* Copyright (c) Oracle Corporation 1995. All Rights Reserved. */ + +/* + NAME + cdemoin2 - Demo program to perform attribute substitutability. + + DESCRIPTION + This program demonstrates attribute substitutability, wherein a column + which is of REF to a supertype is substituted with a REF to a subtype. + All the data from the table are then displayed. + + MODIFIED + rdwajan 08/03/00 Created + +*/ +CONNECT scott/tiger; +DROP TABLE cdemoin2_person_tab; +DROP TABLE cdemoin2_address_tab; +DROP TABLE cdemoin2_sec_address_tab; +DROP TYPE cdemoin2_sec_address; +DROP TYPE cdemoin2_address; + +CREATE TYPE cdemoin2_address AS OBJECT +( hno NUMBER, street VARCHAR2(20) ) NOT FINAL; +/ + +CREATE TYPE cdemoin2_sec_address UNDER cdemoin2_address +( city VARCHAR2(20), state CHAR(20) ); +/ +show errors; +CREATE TABLE cdemoin2_sec_address_tab OF cdemoin2_sec_address; +INSERT INTO cdemoin2_sec_address_tab values +(cdemoin2_sec_address(100, 'MAIN STREET', 'NEW YORK', 'NY')); +INSERT INTO cdemoin2_sec_address_tab values +(cdemoin2_sec_address(200, 'BROADWAY BLVD', 'CHICAGO', 'IL')); + +CREATE TABLE cdemoin2_address_tab OF cdemoin2_address; +INSERT INTO cdemoin2_address_tab values (cdemoin2_address(300, 'SHORE RD')); +INSERT INTO cdemoin2_address_tab values (cdemoin2_address(400, 'ESCONDIDO RD')); + +CREATE TABLE cdemoin2_person_tab +( ssn NUMBER, + vacation_home REF cdemoin2_sec_address, + first_home REF cdemoin2_address +); + +INSERT INTO cdemoin2_person_tab (ssn, vacation_home, first_home) VALUES +(999, (SELECT REF(a) FROM cdemoin2_sec_address_tab a WHERE a.hno = 100), +(SELECT REF(a) FROM cdemoin2_address_tab a WHERE a.hno = 300)); + +COMMIT; + diff --git a/cdemoin3.c b/cdemoin3.c new file mode 100644 index 0000000..b7f58a2 --- /dev/null +++ b/cdemoin3.c @@ -0,0 +1,675 @@ +/* Copyright (c) 1996, 2001, Oracle Corporation. All rights reserved. */ + +/* + + NAME + cdemoin3 - Demo program to describe an object, inherited types, object + table and subtable. + + DESCRIPTION + The program describes an object, an inherited object, methods of an + object, object table and a subtable and prints out the new type level + attributes, the new method level attributes and the new table level + attributes. + + NOTES + dependent files : + cdemoin3.h - Header file + cdemoin3.sql - SQL script to be run before execution + cdemoin3.tsc - test script (optional) + + Program Notes : + + MODIFIED (MM/DD/YY) + rdwajan 08/07/00 - Creation +*/ + +#include "cdemoin3.h" + +static OCIError *errhp = (OCIError *)0; +static OCIEnv *envhp = (OCIEnv *)0; +static OCIServer *svrhp = (OCIServer *)0; +static OCISession *sesnhp = (OCISession *)0; +static OCISvcCtx *svchp = (OCISvcCtx *)0; +static OCIStmt *stmthp = (OCIStmt *)0; + +static text *database =(text *)""; +static text *username =(text *)"scott"; +static text *password =(text *)"tiger"; + +/* Free the allocated handles */ +static void cleanup (void); + +/* Check for errors */ +void checkerr (OCIError *errhp, sword status); + +/* describe a given object */ +void describe_obj ( OCIEnv *envhp, OCISvcCtx *svchp, OCIStmt *stmthp, +OCIError *errhp, text *obj); + +/* describe an object table */ +void describe_tab ( OCIEnv *envhp, OCISvcCtx *svchp, OCIStmt *stmthp, +OCIError *errhp, text *table); + +/* Function to describe the methods of an object */ +void desc_obj_meth (OCIParam *parmhp); + +/* print the type of the enumerated type */ +void printtypename (ub2 type, text *name, ub2 typeSize, ub2 typenameSize); + +sword status = 0; + +int main (void) +{ + printf("cdemoin3 - Demo program for describing objects \n"); + /* Initializing the environment in the Object mode*/ + OCIEnvCreate (&envhp, OCI_OBJECT, (dvoid *)0, (dvoid * (*)()) 0, + (dvoid * (*)()) 0, (dvoid (*)()) 0, 0, (dvoid *)0); + + OCIHandleAlloc (envhp, (dvoid **)&errhp, OCI_HTYPE_ERROR, (size_t)0, + (dvoid **)0); + + OCIHandleAlloc(envhp, (dvoid **)&svrhp, OCI_HTYPE_SERVER, (size_t)0, + (dvoid **)0); + + status = OCIServerAttach(svrhp, errhp, (text *)database, + (sb4)strlen((char *)database), OCI_DEFAULT); + + if (status != OCI_SUCCESS) + { + printf("OCIServerAttach failed \n"); + checkerr(errhp, status); + } + else + printf("OCIServerAttach - Success \n"); + + OCIHandleAlloc(envhp, (dvoid **)&svchp, OCI_HTYPE_SVCCTX, (size_t)0, + (dvoid **)0); + OCIAttrSet(svchp, OCI_HTYPE_SVCCTX, (dvoid *)svrhp, (ub4)0, OCI_ATTR_SERVER, + errhp); + + OCIHandleAlloc(envhp, (dvoid **)&sesnhp, OCI_HTYPE_SESSION, (size_t)0, + (dvoid **)0); + + OCIAttrSet(sesnhp, OCI_HTYPE_SESSION, (dvoid *)username, + (ub4)strlen((char *)username), OCI_ATTR_USERNAME, errhp); + + OCIAttrSet(sesnhp, OCI_HTYPE_SESSION, (dvoid*)password, + (ub4)strlen((char *)password), OCI_ATTR_PASSWORD, errhp); + + printf("Connecting as %s/%s@%s\n",username,password,database); + + status = OCISessionBegin(svchp, errhp, sesnhp, OCI_CRED_RDBMS, OCI_DEFAULT); + if (status != OCI_SUCCESS) + { + printf("Connection failed \n"); + checkerr(errhp, status); + } + else + printf("Connection - Success \n"); + + OCIAttrSet(svchp, OCI_HTYPE_SVCCTX, sesnhp, (ub4)0, OCI_ATTR_SESSION, errhp); + + /* describing the object I_PERSON */ + describe_obj (envhp, svchp, stmthp, errhp, (text *)"I_PERSON"); + + /* describing the object I_STUDENT */ + describe_obj (envhp, svchp, stmthp, errhp, (text *)"I_STUDENT"); + + /* describing the object I_EMPLOYEE */ + describe_obj (envhp, svchp, stmthp, errhp, (text *)"I_EMPLOYEE"); + + /* describing the table I_PERSON_TAB */ + describe_tab ( envhp, svchp, stmthp, errhp, (text*)"I_PERSON_TAB"); + + /* describing the table I_STUDENT_TAB */ + describe_tab ( envhp, svchp, stmthp, errhp, (text*)"I_STUDENT_TAB"); + + /* describing the table I_EMPLOYEE_TAB */ + describe_tab ( envhp, svchp, stmthp, errhp, (text*)"I_EMPLOYEE_TAB"); + + /* describing the table I_PEOPLE_TAB1 */ + describe_tab ( envhp, svchp, stmthp, errhp, (text*)"I_PEOPLE_TAB1"); + + /* describing the table I_PEOPLE_TAB2 */ + describe_tab ( envhp, svchp, stmthp, errhp, (text*)"I_PEOPLE_TAB2"); + + /* describing the storage table of nested table I_PEOPLE_TAB3_NT_TAB */ + describe_tab ( envhp, svchp, stmthp, errhp, (text*)"I_PEOPLE_TAB3_NT_TAB"); + + /* describing the table I_PEOPLE_TAB3 */ + describe_tab ( envhp, svchp, stmthp, errhp, (text*)"I_PEOPLE_TAB3"); + + /* Free the allocated handles */ + cleanup(); + + printf("cdemoin3 - Done\n"); +} /* End of main() */ + +/* describing an object */ +void describe_obj ( OCIEnv *envhp, OCISvcCtx *svchp, OCIStmt *stmthp, +OCIError *errhp, text *obj ) +{ + ub4 objlen = strlen((char *)obj); + OCIParam *parmhp = (OCIParam *)0; /* parameter handle */ + OCIParam *attrlshp = (OCIParam *)0; /* list of attributes */ + OCIParam *attrhp = (OCIParam *)0; /* attributes handle */ + OCIDescribe *deschp = (OCIDescribe *)0; + + ub4 in = 0; /* counter in the loop */ + ub2 numattr = 0; /* To store the number of attributes */ + + ub2 type = 0; /* To get the type of the attribute */ + text *typename; /* To get the typename of the attribute */ + ub2 typeSize = 0; /* To get column size */ + ub4 typenameSize = 0; + ub4 ntynameSize = 0; + text *ntyname = (text *)0; /* To get the typename of the attribute if the + type is SQLT_NTY */ + ub4 sizeSuper = 0; /* To get the size of the Supertype */ + ub4 sizeSchm = 0; /* To get the size of the Supertype schema */ + + ub1 isFinal = 0; /* To check if type is final */ + ub1 isInst = 0; /* To check if type is instantiable */ + ub1 isSubtype = 0; /* To check if type is a subtype */ + ub1 isInhattr = 0; /* To check if attribute is inherited */ + ub4 local_attr = 0; /* To get the number of local attributes */ + ub4 local_meth = 0; /* To get the number of local methods */ + text *superType; /* To get the name of the supertype */ + text *superSchema; /* To get the name of the schema of the supertype */ + + printf ("Describing object %s \n", obj); + + OCIHandleAlloc((dvoid *)envhp, (dvoid **)&deschp, + (ub4)OCI_HTYPE_DESCRIBE, (size_t)0, (dvoid **)0); + + /* get the describe handle for the object */ + if ((status = OCIDescribeAny(svchp, errhp, (dvoid *)obj, objlen, + OCI_OTYPE_NAME, 0, OCI_PTYPE_TYPE, deschp)) != OCI_SUCCESS ) + { + printf ("Describe - Fail\n"); + checkerr (errhp, status); + } + else + printf ("Describe - Success \n"); + + /* get the parameter handle */ + if ((status = OCIAttrGet(deschp, OCI_HTYPE_DESCRIBE, &parmhp, 0, + OCI_ATTR_PARAM, errhp)) != OCI_SUCCESS) + { + printf ("Getting parameter Handle - Fail \n"); + checkerr (errhp, status); + } + + /* get the number of attributes in the object */ + if ( (status = OCIAttrGet(parmhp, OCI_DTYPE_PARAM, &numattr, 0, + OCI_ATTR_NUM_TYPE_ATTRS, errhp)) != OCI_SUCCESS) + { + printf ("Getting the number of attributes - Fail \n"); + checkerr (errhp, status); + } + printf ("Number of attributes = %d \n", numattr); + + /* get whether the type is final*/ + if ( (status = OCIAttrGet(parmhp, OCI_DTYPE_PARAM, &isFinal, 0, + OCI_ATTR_IS_FINAL_TYPE, errhp)) != OCI_SUCCESS) + { + printf ("Getting whether type is final - Fail \n"); + checkerr (errhp, status); + } + if (isFinal) + printf ("Type is Final\n"); + else + printf ("Type is not Final\n"); + + /* get whether the type is instantiable*/ + if ( (status = OCIAttrGet(parmhp, OCI_DTYPE_PARAM, &isInst, 0, + OCI_ATTR_IS_INSTANTIABLE_TYPE, errhp)) != OCI_SUCCESS) + { + printf ("Getting whether type is instantiable - Fail \n"); + checkerr (errhp, status); + } + if (isInst) + printf ("Type is instantiable\n"); + else + printf ("Type is not instantiable\n"); + + /* get whether the type is subtype*/ + if ( (status = OCIAttrGet(parmhp, OCI_DTYPE_PARAM, &isSubtype, 0, + OCI_ATTR_IS_SUBTYPE, errhp)) != OCI_SUCCESS) + { + printf ("Getting whether type is a subtype - Fail \n"); + checkerr (errhp, status); + } + if (isSubtype) + printf ("Type is a subtype\n"); + else + printf ("Type is not a subtype\n"); + + if (isSubtype) + { + /* get the name of the schema of the supertype */ + if ( (status = OCIAttrGet(parmhp, OCI_DTYPE_PARAM, (dvoid *)&superSchema, + (dvoid *)&sizeSchm, OCI_ATTR_SUPERTYPE_SCHEMA_NAME, errhp)) + != OCI_SUCCESS) + { + printf ("Getting the name of the schema of supertype - Fail \n"); + checkerr (errhp, status); + } + printf ("Name of schema of supertype: %.*s\n", sizeSchm, superSchema); + + /* get the name of the supertype */ + if ( (status = OCIAttrGet(parmhp, OCI_DTYPE_PARAM, (dvoid *)&superType, + (dvoid *)&sizeSuper, OCI_ATTR_SUPERTYPE_NAME, errhp)) != OCI_SUCCESS) + { + printf ("Getting the name of the supertype - Fail \n"); + checkerr (errhp, status); + } + printf ("Name of supertype: %.*s\n", sizeSuper, superType); + } + + /* get handle for parameter list */ + if ( (status = OCIAttrGet(parmhp, OCI_DTYPE_PARAM, &attrlshp, 0, + OCI_ATTR_LIST_TYPE_ATTRS, errhp)) != OCI_SUCCESS) + { + printf ("Getting attributes list Handle - Fail \n"); + checkerr (errhp, status); + } + + for (in = 1; in <= numattr; ++in) + { + if (status = OCIParamGet (attrlshp, OCI_DTYPE_PARAM, errhp, + (dvoid **)&attrhp, in) != OCI_SUCCESS) + { + printf ("Getting parameter Handle for the attr - Failed \n"); + checkerr (errhp, status); + } + + if (status = OCIAttrGet ((dvoid *)attrhp, OCI_DTYPE_PARAM, &type, + 0, OCI_ATTR_DATA_TYPE, errhp) != OCI_SUCCESS) + { + printf ("Getting column type - Failed \n"); + checkerr (errhp, status); + } + + if (status = OCIAttrGet ((dvoid *)attrhp, OCI_DTYPE_PARAM, + &typeSize, 0, OCI_ATTR_DATA_SIZE, errhp) != OCI_SUCCESS) + { + printf ("Getting column size - Failed \n"); + checkerr (errhp, status); + } + +#ifdef CDEMOIN3_LATER + /* check if the attribute is inherited */ + if (status = OCIAttrGet ((dvoid *)attrhp, OCI_DTYPE_PARAM, + &isInhattr, 0, OCI_ATTR_IS_INHERITED_ATTR, errhp) != OCI_SUCCESS) + { + printf ("Checking if attribute is inherited - Failed \n"); + checkerr (errhp, status); + } + else + { + if (isInhattr) + printf ("Attribute is inherited \n"); + else + printf ("Attribute is not inherited\n"); + } +#endif /* #ifdef CDEMOIN3_LATER */ + + if (status = OCIAttrGet (attrhp, OCI_DTYPE_PARAM, &typename, + (ub4 *)&typenameSize, OCI_ATTR_NAME, errhp) != OCI_SUCCESS) + { + printf ("Getting attribute name - Failed \n"); + checkerr (errhp, status); + } + else + { + if (type == SQLT_NTY) + { + if (status = OCIAttrGet ((dvoid *)attrhp, OCI_DTYPE_PARAM, &ntyname, + (ub4 *)&ntynameSize, OCI_ATTR_TYPE_NAME, errhp) != OCI_SUCCESS) + { + printf ("Getting type name - Failed \n"); + checkerr (errhp, status); + } + else + { + printf ("%.*s - Named Data Type :", typenameSize, typename); + printf ("%.*s\n", ntynameSize, ntyname); + } + } + else + printtypename (type, typename, typeSize ,typenameSize); + } + } /* end of for loop */ + + /* Calling function to describe the object methods */ + desc_obj_meth(parmhp); +} /* end of describe_obj () */ + +/* Function to describe the methods of an object */ +void desc_obj_meth(OCIParam *parmhp) +{ + OCIParam *methlshp; /* list of methods */ + OCIParam *methhp; /* methods handle */ + + ub4 in = 0; /* Loop counter */ + ub2 nummeth = 111; /* To get the number of methods */ + + ub1 isFinal = 0; /* To check if method is final */ + ub1 isInst = 0; /* To check if method is instantiable */ + ub1 isInhmeth = 0; /* To check if method is inherited */ + + ub4 methSize = 0; /* To get the size of the method name */ + text *methname; /* To get the method name */ + + /* get the number of methods in the object */ + if ( (status = OCIAttrGet(parmhp, OCI_DTYPE_PARAM, &nummeth, 0, + OCI_ATTR_NUM_TYPE_METHODS, errhp)) != OCI_SUCCESS) + { + printf ("Getting the number of methods - Fail \n"); + checkerr (errhp, status); + } + printf ("Number of methods = %d \n", nummeth); + + if (nummeth > 0) + { + /* get handle for parameter list */ + if ( (status = OCIAttrGet(parmhp, OCI_DTYPE_PARAM, &methlshp, 0, + OCI_ATTR_LIST_TYPE_METHODS, errhp)) != OCI_SUCCESS) + { + printf ("Getting methods list Handle - Fail \n"); + checkerr (errhp, status); + } + + for (in = 1; in <= nummeth; ++in) + { + if (status = OCIParamGet (methlshp, OCI_DTYPE_PARAM, errhp, + (dvoid **)&methhp, in) != OCI_SUCCESS) + { + printf ("Getting parameter Handle for the method - Failed \n"); + checkerr (errhp, status); + } + + if (status = OCIAttrGet ((dvoid *)methhp, OCI_DTYPE_PARAM, (dvoid *) + &methname, (ub4 *)&methSize, OCI_ATTR_NAME, errhp) != OCI_SUCCESS) + { + printf ("Getting method name - Failed \n"); + checkerr (errhp, status); + } + else + { + printf ("Method name:%.*s\n", methSize, methname); + } + + /* get whether the method is final*/ + if ((status = OCIAttrGet(methhp, OCI_DTYPE_PARAM, &isFinal, 0, + OCI_ATTR_IS_FINAL_METHOD, errhp)) != OCI_SUCCESS) + { + printf ("Getting whether method is final - Fail \n"); + checkerr (errhp, status); + } + if (isFinal) + printf ("Method is Final\n"); + else + printf ("Method is not Final\n"); + + /* get whether the method is instantiable*/ + if ( (status = OCIAttrGet(methhp, OCI_DTYPE_PARAM, &isInst, 0, + OCI_ATTR_IS_INSTANTIABLE_METHOD, errhp)) != OCI_SUCCESS) + { + printf ("Getting whether method is instantiable - Fail \n"); + checkerr (errhp, status); + } + if (isInst) + printf ("Method is instantiable\n"); + else + printf ("Method is not instantiable\n"); + + /* get whether the method is overriding*/ + if ( (status = OCIAttrGet(methhp, OCI_DTYPE_PARAM, &isInst, 0, + OCI_ATTR_IS_OVERRIDING_METHOD, errhp)) != OCI_SUCCESS) + { + printf ("Getting whether method is overriding - Fail \n"); + checkerr (errhp, status); + } + if (isInst) + printf ("Method is overriding\n"); + else + printf ("Method is not overriding\n"); +#ifdef CDEMOIN3_LATER + /* check if the method is inherited */ + if (status = OCIAttrGet ((dvoid *)methhp, OCI_DTYPE_PARAM, + &isInhmeth, 0, OCI_ATTR_IS_INHERITED_METHOD, errhp) != OCI_SUCCESS) + { + printf ("Checking if method is inherited - Failed \n"); + checkerr (errhp, status); + } + else + { + if (isInhmeth) + printf ("Method is inherited \n"); + else + printf ("Method is not inherited\n"); + } +#endif /* #ifdef CDEMOIN3_LATER */ + } /* end of for loop*/ + } +} /* End of desc_obj_meth (OCIParam *) */ + +/* describe the given table */ +void describe_tab ( OCIEnv *envhp, OCISvcCtx *svchp, OCIStmt *stmthp, +OCIError *errhp, text *table) +{ + ub4 tablen = strlen(table); + OCIParam *parmhp; /* parameter handle */ + OCIParam *agrlshp; /* list of args */ + OCIParam *arg; /* argument handle */ + OCIDescribe *deschp = (OCIDescribe *)0; + + ub4 in = 0; /* Loop counter */ + ub2 numcol = 111; /* To get the number of columns */ + + ub2 type = 111; /* To get the datatype */ + text *typename; /* To get the attribute name */ + ub2 typeSize = 111; + + ub4 len = 0; /*typename length */ + ub1 isSubtable = 0; /* To check if the table is a subtable */ + text superSchema[25]; /* to get the schema name of the super type */ + text superTable[25]; /* to get the name of the super table */ + + if (strcmp(table,(text *)"I_PEOPLE_TAB3_NT_TAB") ==0 ) + printf ("Describing the storage table of a nested table %s\n", table); + else + printf ("Describing the table %s \n", table); + + + OCIHandleAlloc((dvoid *)envhp, (dvoid **)&deschp, + (ub4)OCI_HTYPE_DESCRIBE, (size_t)0, (dvoid **)0); + + /* get the describe handle for the table */ + if ((status = OCIDescribeAny(svchp, errhp, (dvoid *)table, tablen, + OCI_OTYPE_NAME, 0, OCI_PTYPE_TABLE, deschp)) != OCI_SUCCESS ) + checkerr (errhp, status); + else + printf ("Describe - Success \n"); + + /* get the parameter handle */ + if ((status = OCIAttrGet(deschp, OCI_HTYPE_DESCRIBE, &parmhp, 0, + OCI_ATTR_PARAM, errhp)) != OCI_SUCCESS) + checkerr (errhp, status); + + /* get the number of columns in the table */ + if ( (status = OCIAttrGet(parmhp, OCI_DTYPE_PARAM, &numcol, 0, + OCI_ATTR_NUM_COLS, errhp)) != OCI_SUCCESS) + checkerr (errhp, status); + + printf ("Number of Columns:%d \n", numcol); + +#ifdef CDEMOIN3_LATER + /* get whether the table is subtable*/ + if ( (status = OCIAttrGet(parmhp, OCI_DTYPE_PARAM, &isSubtable, 0, + OCI_ATTR_IS_SUBOBJECT, errhp)) != OCI_SUCCESS) + { + printf ("Getting whether table is a subtable - Fail \n"); + checkerr (errhp, status); + } + if (isSubtable) + printf ("Table is a subtable\n"); + else + printf ("Table is not a subtable\n"); + + /* get the name of the schema of the supertable */ + if ( (status = OCIAttrGet(parmhp, OCI_DTYPE_PARAM, (dvoid *)superSchema, 0, + OCI_ATTR_SUPEROBJECT_SCHEMA_NAME, errhp)) != OCI_SUCCESS) + { + printf ("Getting the name of the schema of supertable - Fail \n"); + checkerr (errhp, status); + } + printf ("Name of schema of supertable: %s\n", superSchema); + + /* get the name of the supertable */ + if ( (status = OCIAttrGet(parmhp, OCI_DTYPE_PARAM, (dvoid *)superTable, 0, + OCI_ATTR_SUPEROBJECT_NAME, errhp)) != OCI_SUCCESS) + { + printf ("Getting the name of the supertable - Fail \n"); + checkerr (errhp, status); + } + printf ("Name of supertable: %s\n", superTable); +#endif /* #ifdef CDEMOIN3_LATER */ + + /* get handle for parameter list */ + if ( (status = OCIAttrGet(parmhp, OCI_DTYPE_PARAM, &agrlshp, 0, + OCI_ATTR_LIST_COLUMNS, errhp)) != OCI_SUCCESS) + checkerr (errhp, status); + for (in = 1; in <= numcol; ++in) + { + if (status = OCIParamGet (agrlshp, OCI_DTYPE_PARAM, errhp, + (dvoid **)&arg, in) != OCI_SUCCESS) + { + printf ("Getting parameter Handle for the arguments "); + printf ("- Failed \n"); + checkerr (errhp, status); + } + + if (status = OCIAttrGet ((dvoid *)arg, OCI_DTYPE_PARAM, &type, + 0, OCI_ATTR_DATA_TYPE, errhp) != OCI_SUCCESS) + { + printf ("Getting column type - Failed \n"); + checkerr (errhp, status); + } + + if (status = OCIAttrGet ((dvoid *)arg, OCI_DTYPE_PARAM, + &typeSize, 0, OCI_ATTR_DATA_SIZE, errhp) != OCI_SUCCESS) + { + printf ("Getting column type - Failed \n"); + checkerr (errhp, status); + } + + if (status = OCIAttrGet (arg, OCI_DTYPE_PARAM, &typename, (ub4 *)&len, + OCI_ATTR_NAME, errhp) != OCI_SUCCESS) + { + printf ("Getting type name - Failed \n"); + checkerr (errhp, status); + } + else + printtypename (type, typename, typeSize, len); + } /* end for loop */ +} /* end of describe_tab () */ + +/* printing typenames for given typecodes */ +void printtypename (ub2 type, text *name, ub2 typeSize, ub2 typenameSize) +{ + printf ("%.*s:", typenameSize, name); + switch (type) + { + case SQLT_CHR: printf ("VARCHAR2"); + break; + case SQLT_AFC: printf ("CHAR"); + break; + case SQLT_DAT: printf ("DATE"); + break; + case SQLT_INT: printf ("SIGNED INTEGER"); + break; + case SQLT_UIN: printf ("UNSIGNED INTEGER"); + break; + case SQLT_FLT: printf ("REAL"); + break; + case SQLT_PDN: printf ("PACKED DECIMAL"); + break; + case SQLT_BIN: printf ("BINARY DATA"); + break; + case SQLT_NUM: printf ("NUMBER"); + break; + case SQLT_BLOB : printf ("BLOB"); + break; + case SQLT_CLOB : printf ("CLOB"); + break; + case SQLT_FILE : printf ("BFILE"); + break; + case SQLT_NTY : printf ("NAMED DATA TYPE"); + break; + case SQLT_REF : printf ("REF to a Named Data Type"); + break; + default : printf ("*** UNKNOWN *** "); + break; + } + printf ("(%3d) \n", typeSize); +} /* end of printtypebyname () */ + + +/* cleaning up the allocated handles */ +void cleanup () +{ + if (stmthp) + checkerr(errhp, OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT)); + if (svrhp) + (void) OCIServerDetach( svrhp, errhp, OCI_DEFAULT ); + if (svrhp) + checkerr(errhp, OCIHandleFree((dvoid *) svrhp, OCI_HTYPE_SERVER)); + if (sesnhp) + { + OCISessionEnd (svchp, errhp, sesnhp, OCI_DEFAULT ); + OCIHandleFree((dvoid *) sesnhp, OCI_HTYPE_SESSION); + } + if (svchp) + (void) OCIHandleFree((dvoid *) svchp, OCI_HTYPE_SVCCTX); + if (errhp) + (void) OCIHandleFree((dvoid *) errhp, OCI_HTYPE_ERROR); + return; +} /* end of cleanup () */ + +/* check for the errors */ +void checkerr (OCIError *err, sword status) +{ + text errbuf[514]; + sb4 errcode; + + switch (status) + { + case OCI_SUCCESS : + break; + case OCI_SUCCESS_WITH_INFO : + OCIErrorGet (err, 1, (text *)0, + (sb4 *)&errcode, errbuf, 514, + OCI_HTYPE_ERROR); + printf ("Warning %d : %.*s\n", errcode, 514, errbuf); + break; + case OCI_NO_DATA : + printf ("*** No Data Found *** \n"); + break; + case OCI_INVALID_HANDLE : + printf ("*** Invalid Handle *** \n"); + exit (-5); + case OCI_ERROR : + OCIErrorGet (err, 1, (text *)0, + (sb4 *)&errcode, errbuf, 514, + OCI_HTYPE_ERROR); + printf ("ERROR %d : %.*s\n", errcode, 514, errbuf); + break; + default : + printf ("*** Unknown Status *** \n"); + break; + } +} diff --git a/cdemoin3.h b/cdemoin3.h new file mode 100644 index 0000000..02866cf --- /dev/null +++ b/cdemoin3.h @@ -0,0 +1,31 @@ +/* Copyright (c) Oracle Corporation 1995. All Rights Reserved. */ + +/* + NAME + cdemoin3 - Demo program to describe an object, inherited types, object + table and subtable. + + DESCRIPTION + This program describes an object, an inherited object, methods of an + object, object table and a subtable and prints out the new type level + attributes, the new method level attributes and the new table level + attributes. + + + NOTES + dependent files : + cdemoin3.c - Source file. + cdemoin3.sql - SQL File to be run before execution of the test. + cdemoin3.tsc - Optional, test script file. + + MODIFIED + rdwajan 08/07/00 Created +*/ + +#ifndef CDEMOIN3_ORACLE +# define CDEMOIN3_ORACLE + +#ifndef OCI_ORACLE +# include +#endif +#endif diff --git a/cdemoin3.sql b/cdemoin3.sql new file mode 100644 index 0000000..f649e86 --- /dev/null +++ b/cdemoin3.sql @@ -0,0 +1,84 @@ +/* Copyright (c) Oracle Corporation 1995. All Rights Reserved. */ + +/* + NAME + cdemoin3 - Demo program to describe an object, inherited types, object + table and subtable. + + DESCRIPTION + This program describes an object, an inherited object, methods of an + object, object table and a subtable and prints out the new type level + attributes, the new method level attributes and the new table level + attributes. + + + NOTES + + MODIFIED + rdwajan 08/07/00 Created + +*/ +SET SERVEROUTPUT ON +connect scott/tiger; + +DROP TABLE i_people_tab3; +DROP TABLE i_people_tab2; +DROP TABLE i_people_tab1; +DROP TABLE i_employee_tab; +DROP TABLE i_student_tab; +DROP TABLE i_person_tab; +DROP TYPE i_employee; +DROP TYPE i_student; +DROP TYPE i_person; +DROP TYPE i_address_nest; +DROP TYPE i_address_arr; +DROP TYPE i_address; + +CREATE TYPE i_address AS OBJECT +( hno NUMBER, street VARCHAR2(10) + , MEMBER FUNCTION i_address_fun(arg1 NUMBER) RETURN NUMBER +); +/ + +CREATE TYPE i_address_arr AS VARRAY(3) OF REF i_address; +/ + +CREATE TYPE i_address_nest AS TABLE OF i_address; +/ + +CREATE TYPE i_person AS OBJECT +( ssn NUMBER, adrs i_address + , + NOT INSTANTIABLE + MEMBER PROCEDURE i_person_proc(arg1 NUMBER) +) NOT INSTANTIABLE NOT FINAL; +/ + +CREATE TYPE i_student UNDER i_person +( stud_id NUMBER, stud_add i_address_arr , +OVERRIDING +MEMBER PROCEDURE i_person_proc(arg1 NUMBER) +) NOT FINAL NOT INSTANTIABLE; +/ + +CREATE TYPE i_employee UNDER i_person +( emp_id NUMBER, emp_name VARCHAR2(10) , + FINAL + MEMBER PROCEDURE i_employee_proc(arg1 NUMBER) +) NOT FINAL NOT INSTANTIABLE; +/ + +CREATE TABLE i_person_tab OF i_person; + +CREATE TABLE i_student_tab OF i_student; + +CREATE TABLE i_employee_tab OF i_employee; + +CREATE TABLE i_people_tab1 (region varchar2(10), minister REF i_person); + +CREATE TABLE i_people_tab2 of i_address; + +CREATE TABLE i_people_tab3 (add_col i_address_nest) NESTED TABLE add_col STORE AS +i_people_tab3_nt_tab; + +COMMIT; diff --git a/cdemol2l.c b/cdemol2l.c new file mode 100644 index 0000000..526d16c --- /dev/null +++ b/cdemol2l.c @@ -0,0 +1,1283 @@ +/* Copyright (c) 2001, 2005, Oracle. All rights reserved. */ + +/* + + NAME + cdemol2l.c - OCI demo program for accessing LOBs using LONG API. + + DESCRIPTION + An example program which creates two tables + PERSON_1 (ssn NUMBER, resume LONG), + PERSON_2 (ssn NUMBER, photo LONG RAW). + A series of operations using LONG API: + simple insert/select, piecewise insert/select with polling, + piecewise insert/select with callback, array insert/select + are performed on the two tables respectively. + Then the tables are altered to + PERSON_1 (ssn NUMBER, resume CLOB), + PERSON_2 (ssn NUMBER, photo BLOB). + The same series of operations are performed on altered tables + and the same results are obtained. + + + EXPORT FUNCTION(S) + + + INTERNAL FUNCTION(S) + + + STATIC FUNCTION(S) + + + NOTES + + + MODIFIED (MM/DD/YY) + aliu 02/01/05 - add order by in array select stmt + jchai 07/27/04 - add order by in select stmt + ani 04/30/01 - Merged ani_ocidemo + ani 04/24/01 - Creation + +*/ + +#include +#include +#include +#include + +#define DATA_SIZE 5000 +#define PIECE_SIZE 1000 +#define MAXCOLS 2 +#define MAXROWS 10 +#define NPIECE DATA_SIZE/PIECE_SIZE +#define MAX_IN_ROWS 10 + +typedef struct cdemol2lctx +{ + OCIEnv *envhp; + OCIServer *srvhp; + OCISvcCtx *svchp; + OCIError *errhp; + OCISession *authp; + OCIStmt *stmthp; +} cdemol2lctx; + + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ +static text *username = (text *) "scott"; +static text *password = (text *) "tiger"; + +/*global variable for PIECEWISE operations with CALLBACK*/ +static text nextpiece[DATA_SIZE]; +static ub1 nextpiece2[DATA_SIZE]; +static ub4 len = DATA_SIZE; +static sb2 ind = 0; +static ub2 rc = 0; +static boolean glGetInd = 0; /* global var to control return of ind */ +static boolean glGetRc = 0; /* global var to control return of rc */ +static int column = 1; +static char in1[DATA_SIZE]; +static ub1 in2[DATA_SIZE]; + + +/*--------------------------------------------------------------------------- + STATIC FUNCTION DECLARATIONS + ---------------------------------------------------------------------------*/ +static void initialize(cdemol2lctx *ctxptr); +static void cleanup(cdemol2lctx *ctxptr); +static void checkprint(cdemol2lctx *ctxptr, sword status, ub4 nrows); +static void checkerr(/*_ OCIError *errhp, sword status _*/); +static void sql_stmt_execute(/*_ cdemol2lctx *ctxptx, text *sql_stmt _*/); +static void sql_exec_insert(/*_ cdemol2lctx *ctxptx _*/); +static void insert_piecewise_polling(/*_ cdemol2lctx *ctxptx _*/); +static void insert_piecewise_callback(/*_ cdemol2lctx *ctxptx _*/); +static sb4 cbf_in_data(/*_ dvoid *ctxp, OCIBind *bindp, ub4 iter, + ub4 index, dvoid **bufpp, ub4 *alenpp, + ub1 *piecep, dvoid **indpp _*/); +static void set_piece(/*_ ub1 *piece _*/); +static void sql_array_insert(/*_ cdemol2lctx *ctxptx _*/); +static void sql_exec_select(/*_ cdemol2lctx *ctxptx _*/); +static void select_piecewise_polling(/*_ cdemol2lctx *ctxptx _*/); +static void select_piecewise_callback(/*_ cdemol2lctx *ctxptx _*/); +static void sql_array_select(/*_ cdemol2lctx *ctxptx _*/); +static sb4 cdf_fetch_buffer(/*_ dvoid *ctxp, OCIDefine *defnp, ub4 iter, + dvoid **bufpp, ub4 **alen, ub1 *piecep, + dvoid **indp, ub2 **rcpp _*/); +int main(/*_ int argc, char *argv[] _*/); + + +int main(argc, argv) +int argc; +char *argv[]; +{ + cdemol2lctx ctx; + text *cretab_stmt1 = (text *)"CREATE TABLE PERSON_1 (SSN NUMBER, \ + RESUME LONG)"; + text *cretab_stmt2 = (text *)"CREATE TABLE PERSON_2 (SSN NUMBER, \ + PHOTO LONG RAW)"; + text *alter_stmt1 = (text *)"ALTER TABLE person_1 modify resume CLOB"; + text *alter_stmt2 = (text *)"ALTER TABLE person_2 modify photo BLOB"; + text *drop_stmt1 = (text *)"DROP TABLE PERSON_1"; + text *drop_stmt2 = (text *)"DROP TABLE PERSON_2"; + + printf("\n ######## start DEMO program ############ \n"); + + initialize(&ctx); + + /* execute sql statement */ + printf("\nCREATING TABLE PERSON_1 ... \n"); + sql_stmt_execute(&ctx, cretab_stmt1); + printf("\nCREATING TABLE PERSON_2 ... \n"); + sql_stmt_execute(&ctx, cretab_stmt2); + + /*perform a series of INSERT/SELECT operations */ + sql_exec_insert(&ctx); /*simple insert using LONG api*/ + sql_exec_select(&ctx); /*simple select using LONG api*/ + + insert_piecewise_polling(&ctx); + select_piecewise_polling(&ctx); + + insert_piecewise_callback(&ctx); + select_piecewise_callback(&ctx); + + sql_array_insert(&ctx); + sql_array_select(&ctx); + + printf("\nALTERING TABLE PERSON_1 ... \n"); + sql_stmt_execute(&ctx, alter_stmt1); + printf("\nALTERING TABLE PERSON_2 ... \n"); + sql_stmt_execute(&ctx, alter_stmt2); + + /*perform the same series of operations again*/ + sql_exec_insert(&ctx); + sql_exec_select(&ctx); + + insert_piecewise_polling(&ctx); + select_piecewise_polling(&ctx); + + insert_piecewise_callback(&ctx); + select_piecewise_callback(&ctx); + + sql_array_insert(&ctx); + sql_array_select(&ctx); + + printf("\nDROPPING TABLE PERSON_1 ... \n"); + sql_stmt_execute(&ctx, drop_stmt1); + printf("\nDROPPING TABLE PERSON_2 ... \n"); + sql_stmt_execute(&ctx, drop_stmt2); + + /* clean things up before exhit */ + cleanup(&ctx); + + return 1; + +} /*end main*/ + + +/*execute a single SQL statement */ +void sql_stmt_execute(ctxptr, sql_stmt) +cdemol2lctx *ctxptr; +text *sql_stmt; +{ + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + sql_stmt, (ub4) strlen((char *)sql_stmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, + ctxptr->stmthp, + ctxptr->errhp, (ub4) 1, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); +} /* end of sql_stmt_execute() */ + + +/*perform simple insert using LONG API*/ +void sql_exec_insert(ctxptr) +cdemol2lctx *ctxptr; +{ + text *ins_stmt1 = (text *)"INSERT INTO PERSON_1 VALUES (:1, :2)"; + text *ins_stmt2 = (text *)"INSERT INTO PERSON_2 VALUES (:1, :2)"; + OCIBind *bndp1 = (OCIBind *) NULL; + OCIBind *bndp2 = (OCIBind *) NULL; + + sword ssn= 1, i; + char col2[DATA_SIZE]; + ub1 col3[DATA_SIZE]; + ub2 col2len=DATA_SIZE, col3len=DATA_SIZE; + + for(i=0;ierrhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + ins_stmt1, (ub4) strlen((char *)ins_stmt1), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING SIMPLE INSERT INTO PERSON_1... \n"); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp1, + ctxptr->errhp, (ub4) 1, + (dvoid *) &ssn, (sb4) sizeof(ssn), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp2, + ctxptr->errhp, (ub4) 2, + (dvoid *) col2, (sb4) col2len, SQLT_CHR, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, + ctxptr->stmthp, + ctxptr->errhp, (ub4) 1, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + ins_stmt2, (ub4) strlen((char *)ins_stmt2), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING SIMPLE INSERT INTO PERSON_2... \n"); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp1, + ctxptr->errhp, (ub4) 1, + (dvoid *) &ssn, (sb4) sizeof(ssn), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp2, + ctxptr->errhp, (ub4) 2, + (dvoid *) col3, (sb4) col3len, SQLT_BIN, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, + ctxptr->stmthp, + ctxptr->errhp, (ub4) 1, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); + +} /* end sql_exe_insert() */ + + +/*perform simple select using LONG API */ +void sql_exec_select(ctxptr) +cdemol2lctx *ctxptr; +{ + text *sel_stmt1 = (text *)"SELECT * FROM PERSON_1 ORDER BY SSN"; + text *sel_stmt2 = (text *)"SELECT * FROM PERSON_2 ORDER BY SSN"; + OCIDefine *defnp1 = (OCIDefine *) NULL; + OCIDefine *defnp2 = (OCIDefine *) NULL; + + ub4 i; + sword ssn; + char col2[DATA_SIZE]; + ub1 col3[DATA_SIZE]; + ub2 col2len, col3len; + boolean bufok; + + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + sel_stmt1, (ub4) strlen((char *)sel_stmt1), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING SIMPLE SELECT OF PERSON_1... \n"); + + checkerr(ctxptr->errhp,OCIDefineByPos(ctxptr->stmthp, &defnp1, + ctxptr->errhp, (ub4) 1, (dvoid*) &ssn, + (sb4) sizeof(ssn), (ub2)SQLT_INT, (dvoid*) 0, + (ub2 *) 0, (ub2 *) 0, OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIDefineByPos(ctxptr->stmthp, &defnp2, + ctxptr->errhp, (ub4) 2, (dvoid *) col2, + (sb4) sizeof(col2), (ub2)SQLT_CHR, (dvoid *)0, + (ub2 *)&col2len, (ub2 *)0, (ub4)OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, + ctxptr->stmthp, + ctxptr->errhp, (ub4) 1, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); + + printf("ssn = %d\n", ssn); + printf("col2len = %d\n", col2len); + + bufok = TRUE; + for (i = 0; i < col2len; i++) + if (col2[i] != 'A') + bufok = FALSE; + + if (bufok) + printf("SUCCESS: contents of col2 have expected value\n"); + else + printf("FAILURE: contents of col2 do not have expected value\n"); + + + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + sel_stmt2, (ub4) strlen((char *)sel_stmt2), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING SIMPLE SELECT OF PERSON_2... \n"); + + checkerr(ctxptr->errhp,OCIDefineByPos(ctxptr->stmthp, &defnp1, + ctxptr->errhp, (ub4) 1, (dvoid*) &ssn, + (sb4) sizeof(ssn), (ub2)SQLT_INT, (dvoid*) 0, + (ub2 *) 0, (ub2 *) 0, OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIDefineByPos(ctxptr->stmthp, &defnp2, + ctxptr->errhp, (ub4) 2, (dvoid *) col3, + (sb4) sizeof(col3), (ub2)SQLT_BIN, (dvoid *)0, + (ub2 *)&col3len, (ub2 *)0, (ub4)OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, + ctxptr->stmthp, + ctxptr->errhp, (ub4) 1, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); + + printf("ssn = %d\n", ssn); + printf("col3len = %d\n", col3len); + + bufok = TRUE; + for (i = 0; i < col3len; i++) + if (col3[i] != 'B') + bufok = FALSE; + + if (bufok) + printf("SUCCESS: contents of col3 have expected value\n"); + else + printf("FAILURE: contents of col3 do not have expected value\n"); + +} /* end sql_exe_select() */ + + +/*perform piecewise insert with polling*/ +void insert_piecewise_polling(ctxptr) +cdemol2lctx *ctxptr; +{ + text *ins_stmt1 = (text *)"INSERT INTO PERSON_1 VALUES (:1, :2)"; + text *ins_stmt2 = (text *)"INSERT INTO PERSON_2 VALUES (:1, :2)"; + OCIBind *bndp1 = (OCIBind *) NULL; + OCIBind *bndp2 = (OCIBind *) NULL; + sword status, ssn= 2, i; + char col2[PIECE_SIZE]; + ub1 col3[PIECE_SIZE]; + ub1 piece; + ub4 alenp2 = PIECE_SIZE; + ub2 rcode2; + + for(i=0;ierrhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + ins_stmt1, (ub4) strlen((char *)ins_stmt1), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING PIECEWISE INSERT INTO PERSON_1 WITH POLLING ... \n"); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp1, + ctxptr->errhp, (ub4) 1, + (dvoid *) &ssn, (sb4) sizeof(ssn), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp2, + ctxptr->errhp, (ub4) 2, + (dvoid *) col2, (sb4) DATA_SIZE, SQLT_CHR, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC)); + + while (1) + { + status = OCIStmtExecute(ctxptr->svchp, ctxptr->stmthp, ctxptr->errhp, + (ub4) 1, (ub4) 0, (CONST OCISnapshot*) 0, + (OCISnapshot*) 0, (ub4) OCI_DEFAULT); + switch(status) + { + case OCI_NEED_DATA: + set_piece(&piece); + if (OCIStmtSetPieceInfo((dvoid *)bndp2, + (ub4)OCI_HTYPE_BIND,ctxptr->errhp, (dvoid *)col2, + &alenp2, piece, (dvoid *) 0, &rcode2)) + { + printf("ERROR: OCIStmtSetPieceInfo returned %d \n", status); + break; + } + status = OCI_NEED_DATA; + break; + case OCI_SUCCESS: + break; + default: + printf( "oci exec returned %d \n", status); + checkerr(ctxptr->errhp, status); + status = 0; + } + if (!status) break; + } + + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + ins_stmt2, (ub4) strlen((char *)ins_stmt2), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING PIECEWISE INSERT INTO PERSON_2 WITH POLLING ... \n"); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp1, + ctxptr->errhp, (ub4) 1, + (dvoid *) &ssn, (sb4) sizeof(ssn), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp2, + ctxptr->errhp, (ub4) 2, + (dvoid *) col3, (sb4) DATA_SIZE, SQLT_BIN, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC)); + + while (1) + { + status = OCIStmtExecute(ctxptr->svchp, ctxptr->stmthp, ctxptr->errhp, + (ub4) 1, (ub4) 0, (CONST OCISnapshot*) 0, + (OCISnapshot*) 0, (ub4) OCI_DEFAULT); + switch(status) + { + case OCI_NEED_DATA: + set_piece(&piece); + if (OCIStmtSetPieceInfo((dvoid *)bndp2, + (ub4)OCI_HTYPE_BIND,ctxptr->errhp, (dvoid *)col3, + &alenp2, piece, (dvoid *) 0, &rcode2)) + { + printf("ERROR: OCIStmtSetPieceInfo returned %d \n", status); + break; + } + status = OCI_NEED_DATA; + break; + case OCI_SUCCESS: + break; + default: + printf( "oci exec returned %d \n", status); + checkerr(ctxptr->errhp, status); + status = 0; + } + if (!status) break; + } + +} /* end insert_piecewise_polling() */ + + +/*set piece information for piecewise insert with polling*/ +void set_piece(piecep) +ub1 *piecep; +{ + static sword piece_cnt = 0; + + switch (piece_cnt) + { + case 0: + *piecep = OCI_FIRST_PIECE; + break; + case NPIECE - 1: + *piecep = OCI_LAST_PIECE; + piece_cnt = 0; + return; + default: + *piecep = OCI_NEXT_PIECE; + } + piece_cnt++; + return; +} + + +/*perform piecewise select with polling*/ +void select_piecewise_polling(ctxptr) +cdemol2lctx *ctxptr; +{ + text *sel_stmt1 = (text *)"SELECT * FROM PERSON_1 where ssn=2"; + text *sel_stmt2 = (text *)"SELECT * FROM PERSON_2 where ssn=2"; + OCIDefine *defnp1 = (OCIDefine *) NULL; + OCIDefine *defnp2 = (OCIDefine *) NULL; + ub4 i; + sword status, ssn; + boolean bufok = TRUE; + char buf1[PIECE_SIZE]; + ub1 buf2[PIECE_SIZE]; + ub4 alen = PIECE_SIZE; + ub1 piece = OCI_FIRST_PIECE; + dvoid *hdlptr = (dvoid *) 0; + ub4 hdltype = OCI_HTYPE_DEFINE, iter = 0, idx = 0; + ub1 in_out = 0; + sb2 indptr = 0; + ub2 rcode = 0; + + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + sel_stmt1, (ub4) strlen((char *)sel_stmt1), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING SELECT PIECEWISE WITH POLLING OF PERSON_1 ... \n"); + + checkerr(ctxptr->errhp,OCIDefineByPos(ctxptr->stmthp, &defnp1, + ctxptr->errhp, (ub4) 1, (dvoid*) &ssn, + (sb4) sizeof(ssn), (ub2)SQLT_INT, (dvoid*) 0, + (ub2 *) 0, (ub2 *) 0, OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIDefineByPos(ctxptr->stmthp, &defnp2, + ctxptr->errhp, (ub4) 2, (dvoid *) 0, + (sb4) DATA_SIZE, (ub2)SQLT_CHR, (dvoid *)0, + (ub2 *) 0, (ub2 *)0, (ub4)OCI_DYNAMIC_FETCH)); + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, + ctxptr->stmthp, + ctxptr->errhp, (ub4) 0, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); + + status = OCIStmtFetch(ctxptr->stmthp, ctxptr->errhp, + (ub4) 1, (ub2) OCI_FETCH_NEXT, (ub4) OCI_DEFAULT); + checkerr(ctxptr->errhp, status); + + printf("ssn = %d\n", ssn); + printf("checking contents of RESUME piece by piece\n"); + while (status == OCI_NEED_DATA) + { + checkerr(ctxptr->errhp, OCIStmtGetPieceInfo(ctxptr->stmthp, + ctxptr->errhp, &hdlptr, &hdltype, + &in_out, &iter, &idx, &piece)); + + checkerr(ctxptr->errhp, OCIStmtSetPieceInfo((dvoid *)hdlptr, (ub4)hdltype, + ctxptr->errhp, (dvoid *) &buf1, &alen, piece, + (dvoid *)&indptr, &rcode)); + + status = OCIStmtFetch(ctxptr->stmthp,ctxptr->errhp, (ub4) 1, + (ub2) OCI_FETCH_NEXT, (ub4) OCI_DEFAULT); + + /*verify if fetch results are correct */ + for (i = 0; i < alen; i++) + if (buf1[i] != 'A') + bufok = FALSE; + + if (bufok) + printf("SUCCESS: contents of buf1 have expected value\n"); + else + printf("FAILURE: contents of buf1 do not have expected value\n"); + } + if(status == OCI_SUCCESS) + printf("SUCCESS: fetched all pieces of RESUME CORRECTLY\n"); + + + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + sel_stmt2, (ub4) strlen((char *)sel_stmt2), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING SELECT PIECEWISE WITH POLLING OF PERSON_2 ... \n"); + + checkerr(ctxptr->errhp,OCIDefineByPos(ctxptr->stmthp, &defnp1, + ctxptr->errhp, (ub4) 1, (dvoid*) &ssn, + (sb4) sizeof(ssn), (ub2)SQLT_INT, (dvoid*) 0, + (ub2 *) 0, (ub2 *) 0, OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIDefineByPos(ctxptr->stmthp, &defnp2, + ctxptr->errhp, (ub4) 2, (dvoid *) 0, + (sb4) DATA_SIZE, (ub2)SQLT_BIN, (dvoid *)0, + (ub2 *) 0, (ub2 *)0, (ub4)OCI_DYNAMIC_FETCH)); + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, + ctxptr->stmthp, + ctxptr->errhp, (ub4) 0, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); + + status = OCIStmtFetch(ctxptr->stmthp, ctxptr->errhp, + (ub4) 1, (ub2) OCI_FETCH_NEXT, (ub4) OCI_DEFAULT); + checkerr(ctxptr->errhp, status); + + printf("ssn = %d\n", ssn); + printf("checking contents of PHOTO piece by piece\n"); + while (status == OCI_NEED_DATA) + { + checkerr(ctxptr->errhp, OCIStmtGetPieceInfo(ctxptr->stmthp, + ctxptr->errhp, &hdlptr, &hdltype, + &in_out, &iter, &idx, &piece)); + + checkerr(ctxptr->errhp, OCIStmtSetPieceInfo((dvoid *)hdlptr, (ub4)hdltype, + ctxptr->errhp, (dvoid *) &buf2, &alen, piece, + (dvoid *)&indptr, &rcode)); + + status = OCIStmtFetch(ctxptr->stmthp,ctxptr->errhp, (ub4) 1, + (ub2) OCI_FETCH_NEXT, (ub4) OCI_DEFAULT); + + /*verify if fetch results are correct */ + bufok = TRUE; + for (i = 0; i < alen; i++) + if (buf2[i] != 'B') + bufok = FALSE; + + if (bufok) + printf("SUCCESS: contents of buf2 have expected value\n"); + else + printf("FAILURE: contents of buf2 do not have expected value\n"); + } + if(status == OCI_SUCCESS) + printf("SUCCESS: fetched all pieces of PHOTO CORRECTLY\n"); +} /* end of select_piecewise_polling() */ + + +/*perform piecewise insert with callback*/ +void insert_piecewise_callback(ctxptr) +cdemol2lctx *ctxptr; +{ + text *ins_stmt1 = (text *)"INSERT INTO PERSON_1 VALUES (:1, :2)"; + text *ins_stmt2 = (text *)"INSERT INTO PERSON_2 VALUES (:1, :2)"; + OCIBind *bndp1 = (OCIBind *) NULL; + OCIBind *bndp2 = (OCIBind *) NULL; + sword status, ssn= 3, i; + ub4 pos[MAXCOLS]; + + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + ins_stmt1, (ub4) strlen((char *)ins_stmt1), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING PIECEWISE INSERT INTO PERSON_1 WITH CALLBACK ... \n"); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp1, + ctxptr->errhp, (ub4) 1, + (dvoid *) &ssn, (sb4) sizeof(ssn), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp2, + ctxptr->errhp, (ub4) 2, + (dvoid *) 0, (sb4) DATA_SIZE, SQLT_LNG, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC)); + + for (i = 0; i < MAXCOLS; i++) + pos[i] = i+1; + + checkerr(ctxptr->errhp, OCIBindDynamic(bndp2, ctxptr->errhp, + (dvoid *) &pos[0], cbf_in_data, + (dvoid *) 0, (OCICallbackOutBind) 0)); + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, + ctxptr->stmthp, + ctxptr->errhp, (ub4) 1, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); + + + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + ins_stmt2, (ub4) strlen((char *)ins_stmt2), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING PIECEWISE INSERT INTO PERSON_2 WITH CALLBACK ... \n"); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp1, + ctxptr->errhp, (ub4) 1, + (dvoid *) &ssn, (sb4) sizeof(ssn), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp2, + ctxptr->errhp, (ub4) 2, + (dvoid *) 0, (sb4) DATA_SIZE, SQLT_BIN, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC)); + + checkerr(ctxptr->errhp, OCIBindDynamic(bndp2, ctxptr->errhp, + (dvoid *) &pos[1], cbf_in_data, + (dvoid *) 0, (OCICallbackOutBind) 0)); + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, + ctxptr->stmthp, + ctxptr->errhp, (ub4) 1, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); +} /* end insert_piecewise_callback() */ + + +/* ----------------------------------------------------------------- */ +/* Inbind callback to specify input data. */ +/* ----------------------------------------------------------------- */ +static sb4 cbf_in_data(ctxp, bindp, iter, index, bufpp, alenpp, piecep, indpp) +dvoid *ctxp; +OCIBind *bindp; +ub4 iter; +ub4 index; +dvoid **bufpp; +ub4 *alenpp; +ub1 *piecep; +dvoid **indpp; +{ + sword j; + ub4 inpos = *((ub4 *)ctxp); + + switch(inpos) + { + case 1: + memset((void *)in1, (int) 'A', (size_t) DATA_SIZE); + *bufpp = (dvoid *) in1; + *alenpp = sizeof(in1); + break; + case 2: + memset((void *)in2, (int) 'B', (size_t) DATA_SIZE); + *bufpp = (dvoid *) in2; + *alenpp = sizeof(in2); + break; + default: + *bufpp = (dvoid *) 0; + *alenpp = 0; + printf("ERROR: invalid position number: %d\n", inpos); + } + + *indpp = (dvoid *) 0; + *piecep = OCI_ONE_PIECE; + + return OCI_CONTINUE; +} + + +/*perform piecewise select with callback*/ +void select_piecewise_callback(ctxptr) +cdemol2lctx *ctxptr; +{ + text *sel_stmt1 = (text *)"SELECT * FROM PERSON_1 where ssn=3"; + text *sel_stmt2 = (text *)"SELECT * FROM PERSON_2 where ssn=3"; + OCIDefine *defnp1 = (OCIDefine *) NULL; + OCIDefine *defnp2 = (OCIDefine *) NULL; + sword status, ssn; + char buf1[DATA_SIZE]; + ub1 buf2[DATA_SIZE]; + char *buf1p = buf1; + ub1 *buf2p = buf2; + boolean bufok = TRUE; + int i; + + column = 1; + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + sel_stmt1, (ub4) strlen((char *)sel_stmt1), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING SELECT PIECEWISE WITH CALLBACK OF PERSON_1... \n"); + + checkerr(ctxptr->errhp,OCIDefineByPos(ctxptr->stmthp, &defnp1, + ctxptr->errhp, (ub4) 1, (dvoid*) &ssn, + (sb4) sizeof(ssn), (ub2)SQLT_INT, (dvoid*) 0, + (ub2 *) 0, (ub2 *) 0, OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIDefineByPos(ctxptr->stmthp, &defnp2, + ctxptr->errhp, (ub4) 2, (dvoid *) 0, + (sb4) DATA_SIZE, (ub2)SQLT_CHR, (dvoid *)0, + (ub2 *) 0, (ub2 *)0, (ub4)OCI_DYNAMIC_FETCH)); + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, + ctxptr->stmthp, + ctxptr->errhp, (ub4) 0, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIDefineDynamic(defnp2, ctxptr->errhp, + (dvoid *) &buf1p, (OCICallbackDefine) cdf_fetch_buffer)); + + status = OCIStmtFetch(ctxptr->stmthp, ctxptr->errhp, (ub4) 1, + (ub2) OCI_FETCH_NEXT, (ub4) OCI_DEFAULT); + + checkerr(ctxptr->errhp, status); + + /* check the contents of the last piece */ + for(i=0;ierrhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + sel_stmt2, (ub4) strlen((char *)sel_stmt2), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING SELECT PIECEWISE WITH CALLBACK OF PERSON_2... \n"); + + checkerr(ctxptr->errhp,OCIDefineByPos(ctxptr->stmthp, &defnp1, + ctxptr->errhp, (ub4) 1, (dvoid*) &ssn, + (sb4) sizeof(ssn), (ub2)SQLT_INT, (dvoid*) 0, + (ub2 *) 0, (ub2 *) 0, OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIDefineByPos(ctxptr->stmthp, &defnp2, + ctxptr->errhp, (ub4) 2, (dvoid *) 0, + (sb4) DATA_SIZE, (ub2)SQLT_BIN, (dvoid *)0, + (ub2 *) 0, (ub2 *)0, (ub4)OCI_DYNAMIC_FETCH)); + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, + ctxptr->stmthp, + ctxptr->errhp, (ub4) 0, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIDefineDynamic(defnp2, ctxptr->errhp, + (dvoid *) &buf2p, (OCICallbackDefine) cdf_fetch_buffer)); + + status = OCIStmtFetch(ctxptr->stmthp, ctxptr->errhp, (ub4) 1, + (ub2) OCI_FETCH_NEXT, (ub4) OCI_DEFAULT); + + checkerr(ctxptr->errhp, status); + + /* check the contents of the last piece */ + bufok = TRUE; + for(i=0;ierrhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + ins_stmt1, (ub4) strlen((char *)ins_stmt1), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING ARRAY INSERT INTO PERSON_1... \n"); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp1, + ctxptr->errhp, (ub4) 1, (dvoid *) &data1[0].ssn, + (sb4) sizeof(data1[0].ssn), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp2, + ctxptr->errhp, (ub4) 2, (dvoid *) data1[0].buf1, + (sb4) sizeof(data1[0].buf1), SQLT_CHR, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)); + + if (OCIBindArrayOfStruct(bndp1,ctxptr->errhp,valsk1, indsk, rlsk, rcsk) + || OCIBindArrayOfStruct(bndp2,ctxptr->errhp,valsk1, indsk, rlsk, rcsk)) + { + printf("FAILED: OCIBindeArrayOfStruct()\n"); + return; + } + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, ctxptr->stmthp, + ctxptr->errhp, (ub4) MAX_IN_ROWS, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); + + printf("\nBEGINING ARRAY INSERT INTO PERSON_2... \n"); + + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + ins_stmt2, (ub4) strlen((char *)ins_stmt2), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp1, + ctxptr->errhp, (ub4) 1, (dvoid *) &data2[0].ssn, + (sb4) sizeof(data2[0].ssn), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIBindByPos(ctxptr->stmthp, &bndp2, + ctxptr->errhp, (ub4) 2, (dvoid *) data2[0].buf2, + (sb4) sizeof(data2[0].buf2), SQLT_BIN, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)); + + if (OCIBindArrayOfStruct(bndp1,ctxptr->errhp,valsk2, indsk, rlsk, rcsk) + || OCIBindArrayOfStruct(bndp2,ctxptr->errhp,valsk2, indsk, rlsk, rcsk)) + { + printf("FAILED: OCIBindeArrayOfStruct()\n"); + return; + } + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, ctxptr->stmthp, + ctxptr->errhp, (ub4) MAX_IN_ROWS, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); +} /* end sql_array_insert() */ + + +/*perform array select*/ +void sql_array_select(ctxptr) +cdemol2lctx *ctxptr; +{ + text *sel_stmt1 = (text *)"SELECT * FROM PERSON_1 where ssn>3 ORDER BY SSN"; + text *sel_stmt2 = (text *)"SELECT * FROM PERSON_2 where ssn>3 ORDER BY SSN"; + OCIDefine *defnp1 = (OCIDefine *) NULL; + OCIDefine *defnp2 = (OCIDefine *) NULL; + ub2 buflen1, buflen2; + boolean buf1ok = TRUE, buf2ok = TRUE; + ub4 i,j; + + typedef struct { + sword ssn; + char buf1[DATA_SIZE]; + } person_1; + + typedef struct { + sword ssn; + ub1 buf2[DATA_SIZE]; + } person_2; + + person_1 data1[MAX_IN_ROWS]; + person_2 data2[MAX_IN_ROWS]; + ub4 valsk1 = (ub4) sizeof(person_1); /* value skip */ + ub4 valsk2 = (ub4) sizeof(person_2); /* value skip */ + ub4 indsk = 0; /* indicator skips */ + ub4 rlsk = 0; /* return length skips */ + ub4 rcsk = 0; /* return code skips */ + + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + sel_stmt1, (ub4) strlen((char *)sel_stmt1), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING ARRAY SELECT OF PERSON_1... \n"); + + checkerr(ctxptr->errhp,OCIDefineByPos(ctxptr->stmthp, &defnp1, + ctxptr->errhp, (ub4) 1, (dvoid*) &data1[0].ssn, + (sb4) sizeof(data1[0].ssn), (ub2)SQLT_INT, (dvoid*) 0, + (ub2 *) 0, (ub2 *) 0, OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIDefineByPos(ctxptr->stmthp, &defnp2, + ctxptr->errhp, (ub4) 2, (dvoid *) data1[0].buf1, + (sb4) sizeof(data1[0].buf1), (ub2)SQLT_CHR, (dvoid *)0, + (ub2 *) &buflen1, (ub2 *)0, (ub4)OCI_DEFAULT)); + + if (OCIDefineArrayOfStruct(defnp1,ctxptr->errhp,valsk1, indsk, rlsk, rcsk) + || OCIDefineArrayOfStruct(defnp2,ctxptr->errhp,valsk1, indsk, rlsk, rcsk)) + { + printf("FAILED: OCIDefineArrayOfStruct()\n"); + return; + } + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, ctxptr->stmthp, + ctxptr->errhp, (ub4) MAXROWS, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); + + + checkerr(ctxptr->errhp, OCIStmtPrepare(ctxptr->stmthp, ctxptr->errhp, + sel_stmt2, (ub4) strlen((char *)sel_stmt2), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + + printf("\nBEGINING ARRAY SELECT OF PERSON_2... \n"); + + checkerr(ctxptr->errhp,OCIDefineByPos(ctxptr->stmthp, &defnp1, + ctxptr->errhp, (ub4) 1, (dvoid*) &data2[0].ssn, + (sb4) sizeof(data2[0].ssn), (ub2)SQLT_INT, (dvoid*) 0, + (ub2 *) 0, (ub2 *) 0, OCI_DEFAULT)); + + checkerr(ctxptr->errhp, OCIDefineByPos(ctxptr->stmthp, &defnp2, + ctxptr->errhp, (ub4) 2, (dvoid *) data2[0].buf2, + (sb4) sizeof(data2[0].buf2), (ub2)SQLT_BIN, (dvoid *)0, + (ub2 *) &buflen2, (ub2 *)0, (ub4)OCI_DEFAULT)); + + if (OCIDefineArrayOfStruct(defnp1,ctxptr->errhp,valsk2, indsk, rlsk, rcsk) + || OCIDefineArrayOfStruct(defnp2,ctxptr->errhp,valsk2, indsk, rlsk, rcsk)) + { + printf("FAILED: OCIDefineArrayOfStruct()\n"); + return; + } + + checkerr(ctxptr->errhp, OCIStmtExecute(ctxptr->svchp, ctxptr->stmthp, + ctxptr->errhp, (ub4) MAXROWS, (ub4)0, + (OCISnapshot *) NULL, (OCISnapshot *) NULL, + OCI_DEFAULT)); + + /*check output */ + for(i=0;ienvhp, + (ub4)OCI_THREADED|OCI_OBJECT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0, + (size_t) 0, (dvoid **) 0 )) + printf("FAILED: OCIEnvCreate()\n"); + + + printf("\n ######## Connect to server ############# \n"); + + if (OCIHandleAlloc((dvoid *) ctxptr->envhp, + (dvoid **) &ctxptr->errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + printf("FAILED: OCIHandleAlloc() on ctxptr->errhp\n"); + + if (OCIHandleAlloc((dvoid *) ctxptr->envhp, + (dvoid **) &ctxptr->srvhp, + (ub4) OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0)) + printf("FAILED: OCIHandleAlloc() on ctxptr->srvhp\n"); + + if (OCIHandleAlloc((dvoid *) ctxptr->envhp, + (dvoid **) &ctxptr->svchp, + (ub4) OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0)) + printf("FAILED: OCIHandleAlloc() on ctxptr->svchp\n"); + + if (OCIHandleAlloc((dvoid *) ctxptr->envhp, + (dvoid **) &ctxptr->authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0)) + printf("FAILED: OCIHandleAlloc() on ctxptr->authp\n"); + + if (OCIServerAttach(ctxptr->srvhp, ctxptr->errhp, + (text *) "", (sb4) strlen((char *) ""), + (ub4) OCI_DEFAULT)) + printf("FAILED: OCIServerAttach()\n"); + + if (OCIAttrSet((dvoid *) ctxptr->svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) ctxptr->srvhp, (ub4) 0, + (ub4) OCI_ATTR_SERVER, ctxptr->errhp)) + printf("FAILED: OCIAttrSet() server attribute\n"); + + /*begin log_on part */ + if (OCIAttrSet((dvoid *) ctxptr->authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) username, (ub4) strlen((char *) username), + (ub4) OCI_ATTR_USERNAME, ctxptr->errhp)) + printf("FAILED: OCIAttrSet() userid\n"); + + if (OCIAttrSet((dvoid *) ctxptr->authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) password, (ub4) strlen((char *) password), + (ub4) OCI_ATTR_PASSWORD, ctxptr->errhp)) + printf("FAILED: OCIAttrSet() passwd\n"); + + printf("Logging on as %s ....\n", username); + + checkerr(ctxptr->errhp, OCISessionBegin((dvoid *)ctxptr->svchp, + ctxptr->errhp, ctxptr->authp, + (ub4) OCI_CRED_RDBMS,(ub4) OCI_DEFAULT )); + + printf("%s logged on.\n", username); + + if (OCIAttrSet((dvoid *) ctxptr->svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) ctxptr->authp, (ub4) 0, (ub4) OCI_ATTR_SESSION, + ctxptr->errhp)) + printf("FAILED: OCIAttrSet() session\n"); + /* end log_on part */ + + /* alocate stmt handle for sql queries */ + + if (OCIHandleAlloc((dvoid *)ctxptr->envhp, (dvoid **) &ctxptr->stmthp, + (ub4)OCI_HTYPE_STMT, (CONST size_t) 0, (dvoid **) 0)) + printf("FAILED: alloc statement handle\n"); + +} /* end initialize() */ + + +/*check status and print error information*/ +void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", 512, errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} /* end checkerr() */ + + +/*clean up envionment*/ +void cleanup(ctxptr) +cdemol2lctx *ctxptr; +{ + printf("\n ########## clean up ############ \n"); + + if (OCISessionEnd(ctxptr->svchp, ctxptr->errhp, + ctxptr->authp, (ub4) 0)) + printf("FAILED: OCISessionEnd()\n"); + + printf("%s Logged off.\n", username); + + if (OCIServerDetach(ctxptr->srvhp, ctxptr->errhp, + (ub4) OCI_DEFAULT)) + printf("FAILED: OCIServerDetach()\n"); + + printf("Detached from server.\n"); + + printf("Freeing handles ...\n"); + if (ctxptr->stmthp) + OCIHandleFree((dvoid *) ctxptr->stmthp, (ub4) OCI_HTYPE_STMT); + if (ctxptr->errhp) + OCIHandleFree((dvoid *) ctxptr->errhp, (ub4) OCI_HTYPE_ERROR); + if (ctxptr->srvhp) + OCIHandleFree((dvoid *) ctxptr->srvhp, (ub4) OCI_HTYPE_SERVER); + if (ctxptr->svchp) + OCIHandleFree((dvoid *) ctxptr->svchp, (ub4) OCI_HTYPE_SVCCTX); + if (ctxptr->authp) + OCIHandleFree((dvoid *) ctxptr->authp, (ub4) OCI_HTYPE_SESSION); + if (ctxptr->envhp) + OCIHandleFree((dvoid *) ctxptr->envhp, (ub4) OCI_HTYPE_ENV); + +} /* end cleanup() */ + + +/* end of file cdemol2l.c */ + diff --git a/cdemolb.c b/cdemolb.c new file mode 100644 index 0000000..2085f3e --- /dev/null +++ b/cdemolb.c @@ -0,0 +1,585 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemolb.c 05-apr-2005.11:49:19 lzhao Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1996, 2005, Oracle. All rights reserved. +*/ + +/* + + NAME + cdemolb.c - C Demo program to illustrate the OCI Lob interface. + + DESCRIPTION + This C file contains code to demonstrate the use of the OCI LOB + (Large OBject) interface. It provides a typical example of how + OCI programs can be used to create/insert lob data, and then + access and manipulate (read, write,copy, append, trim) the data. + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + EX_SUCCESS - if the program terminates succesfully. + EX_FAILURE - if it encounters any error. + + NOTES + In the beta-1 release only Lob reads and writes (OCILobRead(), + OCILobWrite()) with no callbacks have been demonstrated. + More examples will be added in future releases. + + Before executing this program execute the following sql program: + cdemolb.sql + Executing this sql program will delete any earlier tables created + by this demo and create new tables. Each time the demo program runs + successfully it adds row to tables. So it might be a good idea to run + the sql program after several runs of the demo program. + + MODIFIED (MM/DD/YY) + lzhao 04/04/05 - bug4184359 + ani 02/19/02 - initialize OCIInd variables. + ani 01/16/02 - add indicator variable to DefineByPos using SQLT_CHR + dchatter 05/09/00 - lob read as char + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 10/01/98 - include stdlib.h - bug 714175 + svedala 09/09/98 - lines longer than 79 chars reformatted - bug 722491 + svedala 02/17/98 - OCI obsoletion changes + cchau 03/03/97 - change functions to long names + azhao 01/31/97 - removed isnull + azhao 01/30/97 - fix lint error + echen 01/03/97 - OCI beautification + pshah 10/11/96 - + kosinski 09/24/96 - Merge Win32 changes into base development + aroy 07/22/96 - Demonstrate the OCI Lob interface. + aroy 07/22/96 - Creation + +*/ + +/*---------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include + +int main () +{ + ldemodef *ctx; + sword retval = 0; + ub2 i; + OCILobLocator *lobp; + + /* allocate and initialise ctx structure */ + ctx = alloc_handles(); + + /* allocate lob descriptor */ + alloc_lob_desc(ctx, &lobp); + + /* Allocate statement/bind/define handles */ + alloc_stmt_handles (ctx, ctx->s1, 0, 0); /* for the insert statement */ + alloc_stmt_handles (ctx, ctx->s2, 0, 2); /* Selecting lob descriptor */ + + /* Authenticate the user (connect to server) */ + authenticate_user(ctx); + + /* Insert/Select Lob locator */ + insert_select_loc(ctx, lobp); + + /* Write Data into Lob Locator */ + Write_to_loc(ctx, lobp); + + + /* Read data from Lob Locator using OCILobRead() */ + Read_from_loc(ctx, lobp); + + /* free lob locator */ + (void) OCIDescriptorFree((dvoid *) lobp, (ub4) OCI_DTYPE_LOB); + + /* Read data from Lob Column using Char type */ + select_loc_data(ctx); + + /* Deauthenticate (logout) user */ + deauthenticate(ctx); + + /* Clean up */ + cleanup(ctx); + return(EX_SUCCESS); +} + +/* --------------------------------------------------------------------- */ +/* Write data into the selected lob locator +*/ +void Write_to_loc(ctx, lobp) +ldemodef *ctx; +OCILobLocator *lobp; +{ + FILE *fp; + ub1 buf[BUFSIZE+1]; + ub4 offset; + ub4 amtp; + ub4 lenp; + sb4 err; + + if ((fp = fopen (CDEMOLB_TEXT_FILE, "r"))==NULL) + { + COMMENT ("Cannot open file for reading"); + exit (EX_FAILURE); + } + + offset = 1; /* Offset for Lobs start at 1 */ + + while (!feof(fp)) + { + /* Read the data from file */ + memset ((void *)buf, '\0', BUFSIZE); + fread((void *)buf, BUFSIZE, 1, fp); + buf[BUFSIZE]='\0'; + /* printf("%s",buf); */ + + /*Write it into the locator */ + amtp = BUFSIZE; /* IN/OUT : IN - amount if data to write */ + err = OCILobWrite (ctx->svchp, ctx->errhp, lobp, &amtp, offset, + (dvoid *) buf, (ub4) BUFSIZE, OCI_ONE_PIECE, + (dvoid *)0, (sb4 (*)()) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT); + if (err == OCI_SUCCESS) + { + printf("Written some data...\n"); + offset += amtp; + } + else + { + fclose(fp); + errrpt (ctx, (text *) "Write_to_loc : OCILobWrite"); + } + } + + COMMENT("Write Successful"); + /* Length of the Lob */ + err = OCILobGetLength(ctx->svchp, ctx->errhp, lobp, &lenp); + if (err != OCI_SUCCESS) + printf (" get lob length fails. err = %d\n\n", err); + else + printf (" Written %d bytes into Locator Successfully.\n\n", lenp); + + fclose (fp); +} + +/* --------------------------------------------------------------------- */ +/* Read data from the lob locator +*/ +void Read_from_loc(ctx, lobp) +ldemodef *ctx; +OCILobLocator *lobp; +{ + ub1 buf[BUFSIZE+1]; + ub4 offset; + ub4 amtp; + ub4 lenp=0; + sb4 err; + + COMMENT("Read from the locator."); + /* Length of the Lob */ + if (OCILobGetLength(ctx->svchp, ctx->errhp, lobp, &lenp) != OCI_SUCCESS) + errrpt(ctx, "Read_from_loc: OCILobGetLength"); + else + { + printf(" Length of Locator is %d\n", lenp); + } + + printf ("Enter the offset to read from (starting at 1): "); + scanf("%d", &offset); + printf ("Enter amount to read: "); + scanf("%d", &amtp); + + if ((offset + amtp - 1) > lenp) + { + printf ("Error: Trying to get more data than available!\n"); + exit (EX_FAILURE); + } + printf( + "\n------------------------------------------------------------------\n"); + + /* Read the locator */ + do + { + memset ((dvoid *)buf, '\0', BUFSIZE); + err = OCILobRead(ctx->svchp, ctx->errhp, lobp, &amtp, offset, + (dvoid *) buf, (ub4)BUFSIZE , (dvoid *) 0, + (OCICallbackLobRead) 0, (ub2) 0, (ub1) SQLCS_IMPLICIT); + if (err == OCI_SUCCESS || err == OCI_NEED_DATA) + { + buf[BUFSIZE] = '\0'; + printf ("%s", buf); + offset +=amtp; + } + else + errrpt(ctx, "Read_from_loc : OCILobRead"); + } + while (err == OCI_NEED_DATA); + printf( + "\n------------------------------------------------------------------\n"); + printf("\n"); +} + +/* --------------------------------------------------------------------- */ +/* insert one row into table and select the lob descriptor. +*/ +static +void alloc_stmt_handles (ctx, sptr, nbnd, ndfn) +ldemodef *ctx; +stmtdef *sptr; +sb2 nbnd; +sb2 ndfn; +{ + sb2 i; + + /* Get statement handles */ + if (OCIHandleAlloc( (dvoid *)(ctx->envhp), (dvoid **) &(sptr->stmhp), + (ub4) OCI_HTYPE_STMT, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS ) + { + COMMENT("Fail to OCIHandleAlloc for statement handle"); + cleanup(ctx); + exit(EX_FAILURE); + } + + /* Get bind handles */ + +/* + for (i=0; istmhp), (dvoid **) &(sptr->bndhp[i]), + (ub4) OCI_HTYPE_BIND, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS ) + { + COMMENT("Fail to OCIHandleAlloc for bind handle"); + cleanup(ctx); + exit(EX_FAILURE); + } + } +*/ + + /* Get define handles */ + +/* + for (i=0; istmhp), (dvoid **) &(sptr->dfnhp[i]), + (ub4) OCI_HTYPE_DEFINE, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS ) + { + COMMENT("Fail to OCIHandleAlloc for define handle"); + cleanup(ctx); + exit(EX_FAILURE); + } + } +*/ + +} + +/* --------------------------------------------------------------------- */ +/* insert one row into table and select the lob descriptor. +*/ +static +void insert_select_loc(ctx, lobsrc) +ldemodef *ctx; +dvoid *lobsrc; +{ + + /* Insert an empty locator */ + if (OCIStmtPrepare (ctx->s1->stmhp, ctx->errhp, + insstmt[0], (ub4)strlen ((char *)insstmt[0])+1, + OCI_NTV_SYNTAX, OCI_DEFAULT) != OCI_SUCCESS) + errrpt (ctx, "insert_select_loc: OCIStmtPrepare"); + + if (OCIStmtExecute (ctx->svchp, ctx->s1->stmhp, ctx->errhp, 1, 0, 0, 0, + OCI_DEFAULT)) + errrpt (ctx, "insert_select_loc: OCIStmtExecute") ; + + printf("Inserted...\n"); + + /* Now select the locator */ + if (OCIStmtPrepare (ctx->s2->stmhp, ctx->errhp, + selstmt[0], (ub4)strlen ((char *)selstmt[0])+1, + OCI_NTV_SYNTAX, OCI_DEFAULT)) + errrpt (ctx, "insert_select_loc: OCIStmtPrepare"); + + + /* Call define for each column of interest */ + if (OCIDefineByPos (ctx->s2->stmhp, &(ctx->s2->dfnhp[1]), ctx->errhp, 1, + (dvoid *)&lobsrc, 0 , SQLT_CLOB, + (dvoid *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT)) + errrpt (ctx, "insert_select_loc: ocidefn"); + + printf("About to select locator...\n"); + + if (OCIStmtExecute (ctx->svchp, ctx->s2->stmhp, ctx->errhp, 1, 0, 0, 0, + OCI_DEFAULT)) + errrpt (ctx, "insert_select_loc: OCIStmtExecute") ; + +} + +/* --------------------------------------------------------------------- */ +/* select the lob data. +*/ + +static void select_loc_data(ctx) +ldemodef *ctx; +{ + + ub1 essay[1024]; + ub4 status = 0; + sb2 outind = 0; + + printf ("\nSelect Locator Data as SQLT_CHR\n"); + printf ("Reading first 1000 bytes\n\n"); + + memset ((void*)essay, 0, 1024); + + /* Now select the locator */ + if (OCIStmtPrepare (ctx->s2->stmhp, ctx->errhp, + selstmt[1], (ub4)strlen ((char *)selstmt[1])+1, + OCI_NTV_SYNTAX, OCI_DEFAULT)) + errrpt (ctx, "select_loc_data: OCIStmtPrepare"); + + /* Call define for each column of interest */ + if (OCIDefineByPos (ctx->s2->stmhp, &(ctx->s2->dfnhp[1]), ctx->errhp, 1, + (dvoid *)essay, 1000, SQLT_CHR, + (dvoid *) &outind, (ub2 *)0, (ub2 *)0, OCI_DEFAULT)) + errrpt (ctx, "select_loc_data: OCIDefineByPos"); + + + if (OCIStmtExecute (ctx->svchp, ctx->s2->stmhp, ctx->errhp, 0, 0, 0, 0, + OCI_DEFAULT)) + errrpt (ctx, "select_loc_data: OCIStmtExecute") ; + + do + { + status = OCIStmtFetch(ctx->s2->stmhp, ctx->errhp, (ub4) 1, + (ub4) OCI_FETCH_NEXT, (ub4) OCI_DEFAULT); + + if(outind !=0) + printf("Normal data not fetched, Output Indicator Value is %d\n",outind); + + if(status == OCI_SUCCESS || status == OCI_SUCCESS_WITH_INFO) + printf ("Essay %s\n", essay); + else + { + if (status != OCI_NO_DATA) + errrpt (ctx, "on fetching the lob as char"); + break; + } + }while(0); + + printf ("End of Reading Locator as SQLT_CHR\n\n"); +} + + +/*-------------------------------------------------------------------------*/ +/* Authenticate users and connect to server +*/ +static void authenticate_user(ctx) +ldemodef *ctx; +{ + COMMENT ("Authentication for scott is progress..."); + + if (OCIServerAttach(ctx->srvhp, ctx->errhp, (CONST OraText *)"", + 0, 0) != OCI_SUCCESS ) + errrpt(ctx, "conn2serv - OCIServerAttach"); + + /* Set the server handle in service handle */ + if (OCIAttrSet (ctx->svchp, OCI_HTYPE_SVCCTX, ctx->srvhp, 0, + OCI_ATTR_SERVER, ctx->errhp) != OCI_SUCCESS) + errrpt(ctx, "conn2serv - OCIAttrSet"); + + /* set the username/password in user handle */ + if (OCIAttrSet(ctx->authp, OCI_HTYPE_SESSION, "scott", 5, + OCI_ATTR_USERNAME, ctx->errhp) != OCI_SUCCESS) + errrpt(ctx, "conn2serv - OCIAttrSet"); + + if (OCIAttrSet(ctx->authp, OCI_HTYPE_SESSION, "tiger", 5, + OCI_ATTR_PASSWORD, ctx->errhp) != OCI_SUCCESS) + errrpt(ctx, "conn2serv - OCIAttrSet"); + + /* Authenticate */ + if (OCISessionBegin (ctx->svchp, ctx->errhp, ctx->authp, + OCI_CRED_RDBMS, OCI_DEFAULT) != OCI_SUCCESS) + errrpt(ctx, "conn2serv - ocisauth"); + + COMMENT ("Authentication for scott successful."); + + /* Set the Authentication handle in the service handle */ + if (OCIAttrSet(ctx->svchp, OCI_HTYPE_SVCCTX, ctx->authp, 0, + OCI_ATTR_SESSION, ctx->errhp) != OCI_SUCCESS) + errrpt(ctx, "conn2serv - OCIAttrSet"); +} + +/*-------------------------------------------------------------------------*/ +/* create all tables. +*/ +static void deauthenticate(ctx) +ldemodef *ctx; +{ + COMMENT ("Logging off...\n"); + if (OCISessionEnd(ctx->svchp, ctx->errhp, ctx->authp, (ub4) 0)) + { + errrpt(ctx, (CONST text *)"logout: ologof"); + } + COMMENT("Logged off.\n"); +} + +/*---------------------------------------------------------------*/ +/* +** Allocate and initialise global and local context structures. +*/ + +static ldemodef *alloc_handles() +{ + ldemodef * csptr; + int i; + + csptr = (ldemodef *) malloc(sizeof(ldemodef)); + if (csptr == (ldemodef *) 0) + { + COMMENT("Unable To Allocate Memory for ldemodef ..."); + exit(EX_FAILURE); + } + memset ((void *) csptr, '\0', sizeof(ldemodef)); + + if (OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0, (dvoid * (*)()) 0, + (dvoid * (*)())0, (void (*)()) 0 ) != OCI_SUCCESS) + { + COMMENT("Fail to OCIInitialize..."); + /* cleanup(csptr); */ + exit(EX_FAILURE); + } + + if (OCIEnvInit( (OCIEnv **) &csptr->envhp, (ub4) OCI_DEFAULT, + (size_t) 0, (dvoid **) 0 ) != OCI_SUCCESS) + { + COMMENT("Fail to OCIEnvInit for service handle..."); + cleanup(csptr); + exit(EX_FAILURE); + } + + /* Get Error Handle */ + if (OCIHandleAlloc( (dvoid *) csptr->envhp, (dvoid **) &csptr->errhp, + (ub4) OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS) + { + COMMENT("Fail to OCIHandleAlloc for error handle..."); + cleanup(csptr); + exit(EX_FAILURE); + } + + /* server context */ + if (OCIHandleAlloc( (dvoid *) csptr->envhp, (dvoid **) &csptr->srvhp, + (ub4) OCI_HTYPE_SERVER, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS) + { + COMMENT("Fail to OCIHandleAlloc for server handle..."); + cleanup(csptr); + exit(EX_FAILURE); + } + + /* Service Context */ + if (OCIHandleAlloc( (dvoid *) csptr->envhp, (dvoid **) &csptr->svchp, + (ub4) OCI_HTYPE_SVCCTX, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS ) + { + COMMENT("Fail to OCIHandleAlloc for service handle..."); + cleanup(csptr); + exit(EX_FAILURE); + } + + /* Auth Context */ + if (OCIHandleAlloc( (dvoid *) csptr->envhp, (dvoid **) &csptr->authp, + (ub4) OCI_HTYPE_SESSION, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS ) + { + COMMENT("Fail to OCIHandleAlloc for user handle..."); + cleanup(csptr); + exit(EX_FAILURE); + } + + /*Stmtdef structures */ + csptr->s1 = (stmtdef *) malloc(sizeof(stmtdef)); + if (csptr->s1 == (stmtdef *) 0) + { + COMMENT("Unable To Allocate Memory for stmtdef ..."); + exit(EX_FAILURE); + } + memset ((void *) csptr->s1, '\0', sizeof(stmtdef)); + + csptr->s2 = (stmtdef *) malloc(sizeof(stmtdef)); + if (csptr->s2 == (stmtdef *) 0) + { + COMMENT("Unable To Allocate Memory for stmtdef ..."); + exit(EX_FAILURE); + } + memset ((void *) csptr->s2, '\0', sizeof(stmtdef)); + return (csptr); + +} + +/* -------------------------------------------------------------- */ +/* Allocate lob descriptors. +*/ +static void alloc_lob_desc(ctx, lobsrc) + ldemodef *ctx; + OCILobLocator **lobsrc; +{ + if (OCIDescriptorAlloc((dvoid *) ctx->envhp, (dvoid **) lobsrc, + (ub4) OCI_DTYPE_LOB, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS ) + { + errrpt(ctx, (CONST text *) "OCIDescriptorAlloc"); + cleanup(ctx); + exit(EX_FAILURE); + } +} + +/* -------------------------------------------------------------- */ +/* Clean up all structures used. +*/ + +static void cleanup(ctx) +ldemodef *ctx; +{ + (void) OCIHandleFree((dvoid *) ctx->srvhp, (ub4) OCI_HTYPE_SERVER); + (void) OCIHandleFree((dvoid *) ctx->svchp, (ub4) OCI_HTYPE_SVCCTX); + (void) OCIHandleFree((dvoid *) ctx->errhp, (ub4) OCI_HTYPE_ERROR); + (void) OCIHandleFree((dvoid *) ctx->authp, (ub4) OCI_HTYPE_SESSION); + (void) OCIHandleFree((dvoid *) ctx->s1, (ub4) OCI_HTYPE_STMT); + (void) OCIHandleFree((dvoid *) ctx->s2, (ub4) OCI_HTYPE_STMT); +} + +/* ------------------------------------------------------------------------- */ + +/* +** Format the output error message and obtain error string from Oracle +** given the error code +*/ +void errrpt(ctx, op) + ldemodef *ctx; + CONST text *op; +{ + text msgbuf[LONGTEXTLENGTH]; + sb4 errcode = 0; + + fprintf(stdout,"ORACLE error during %s\n", op); + OCIErrorGet ((dvoid *) ctx->errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + fprintf(stdout,"ERROR CODE = %d\n", errcode); + fprintf(stdout,"%s\n", msgbuf); + exit(EX_FAILURE); +} + +/* end of file cdemolb.c */ + diff --git a/cdemolb.dat b/cdemolb.dat new file mode 100644 index 0000000..cfaad80 --- /dev/null +++ b/cdemolb.dat @@ -0,0 +1,771 @@ +Photographic Lenses Tutorial + +By David Jacobson jacobson@hpl.hp.com + +Summary: + This posting contains a summary of optical facts for photographers. It is + more detailed that a FAQ file, but less so than a text book. It covers + focusing, apertures, bellows correction, depth of field, hyperfocal + distance, diffraction, the Modulation Transfer Function and illumination. + +Archive-name: rec-photo/lenses/tutorial +Last-modified 1994/3/19 +Version: 1.3 + +Lens Tutorial +by David M. Jacobson +jacobson@hpl.hp.com +Revised March 19, 1995 + +This note gives a tutorial on lenses and gives some common lens formulas. I +attempted to make it between an FAQ (just simple facts) and a textbook. I +generally give the starting point of an idea, and then skip to the results, +leaving out all the algebra. If any part of it is too detailed, just skip ahead +to the result and go on. + +It is in 6 parts. The first gives formulas relating subject and image distances +and magnification, the second discusses f-stops, the third discusses depth of +field, the fourth part discusses diffraction, the fifth part discusses the +Modulation Transfer Function, and the sixth illumination. The sixth part is +authored by John Bercovitz. Sometime in the future I will edit it to have all +parts use consistent notation and format. + +The theory is simplified to that for lenses with the same medium (eg air) front +and rear: the theory for underwater or oil immersion lenses is a bit more +complicated. + +Subject distance, image distance, and magnification + +In lens formulas it is convenient to measure distances from a set of points +called "principal points". There are two of them, one for the front of the lens +and one for the rear, more properly called the primary principal point and the +secondary principal point. While most lens formulas expect the subject distance +to be measured from the front principal point, most focusing scales are +calibrated to read the distance from the subject to the film plane. So you +can't use the distance on your focusing scale in most calculations, unless you +only need an approximate distance. Another interpretation of principal points +is that a (probably virtual) object at the primary principal point formed by +light entering from the front will appear from the rear to as a (probably +virtual) image at the secondary principal point with magnification exactly one. + +"Nodal points" are the two points such that a light ray entering the front of +the lens and headed straight toward the front nodal point will emerge going a +straight way from the rear nodal point at exactly the same angle to the lens's +axis as the entering ray had. The nodal points are equivalent to the principal +points when the front and rear media are the same, eg air, so for practical +purposes the terms can be used interchangeably. And again, the more proper +terms are primary nodal point and secondary nodal point. + +In simple double convex lenses the two principal points are somewhere inside +the lens (actually 1/n-th the way from the surface to the center, where n is +the index of refraction), but in a complex lens they can be almost anywhere, +including outside the lens, or with the rear principal point in front of the +front principal point. In a lens with elements that are fixed relative to each +other, the principal points are fixed relative to the glass. In zoom or +internal focusing lenses the principal points may move relative to the glass +and each other when zooming or focusing. + +When the lens is focused at infinity, the rear principal point is exactly one +focal length in front of the film. To find the front principal point, take the +lens off the camera and let light from a distant object pass through it +"backwards". Find the point where the image is formed, and measure toward the +lens one focal length. With some lenses, particularly ultra wides, you can't do +this, since the image is not formed in front of the front element. (This all +assumes that you know the focal length. I suppose you can trust the +manufacturers numbers enough for educational purposes.) + +So + subject (object) to front principal point distance. +Si + rear principal point to image distance +f + focal length +M + magnification + +1/So + 1/Si = 1/f +M = Si/So +(So-f)*(Si-f) = f^2 +M = f/(So-f) = (Si-f)/f + +If we interpret Si-f as the "extension" of the lens beyond infinity focus, then +we see that it is inversely proportional to a similar "extension" of the +subject. + +For rays close to and nearly parallel to the axis (these are called "paraxial" +rays) we can approximately model most lenses with just two planes perpendicular +to the optic axis and located at the principal points. "Nearly parallel" means +that for the angles involved, theta ~= sin(theta) ~= tan(theta). ("~=" means +approximately equal.) These planes are called principal planes. + +The light can be thought of as proceeding to the front principal plane, then +jumping to a point in the rear principal plane exactly the same displacement +from the axis and simultaneously being refracted (bent). The angle of +refraction is proportional the distance from the center at which the ray +strikes the plane and inversely proportional to the focal length of the lens. +(The "front principal plane" is the one associated with the front of the lens. +I could be behind the rear principal plane.) + +Apertures, f-stop, bellows correction factor, pupil magnification + +We define more symbols + +D + diameter of the entrance pupil, i.e. diameter of the aperture as seen from + the front of the lens +N + f-number (or f-stop) D = f/N, as in f/5.6 +Ne + effective f-number (corrected for "bellows factor", but not absorption) + +Light from a subject point spreads out in a cone whose base is the entrance +pupil. (The entrance pupil is the virtual image of the diaphragm formed by the +lens elements in front of the diaphragm.) The fraction of the total light +coming from the point that reaches the film is proportional to the solid angle +subtended by the cone. If the entrance pupil is distance y in front of the +front nodal point, this is approximately proportional to D^2/(So-y)^2. (Usually +we can ignore y.) If the magnification is M, the light from a tiny subject +patch of unit area gets spread out over an area M^2 on the film, and so the +brightness on the film is inversely proportional to M^2. With some algebraic +manipulation and assuming y=0 it can be shown that the relative brightness is + +(D/So)^2/M^2 = 1/(N^2 * (1+M)^2). + +Thus in the limit as So -> infinity and thus M -> 0, which is the usual case, +the brightness on the film is inversely proportional to the square of the +f-stop, N, and independent of the focal length. + +n For larger magnifications, M, the intensity on the film in is somewhat less +then what is indicated by just 1/N^2, and the correction is called bellows +factor. The short answer is that bellows factor when y=0 is just (1+M)^2. We +will first consider the general case when y != 0. + +n Let us go back to the original formula for the relative brightness on the +film. + +(D/(So-y))^2/M^2 + +The distance, y, that the aperture is in front of the front nodal point, +however, is not readily measurable. It is more convenient to use "pupil +magnification". Analogous to the entrance pupil is the exit pupil, which is the +virtual image of the diaphragm formed by any lens elements behind the +diaphragm. The pupil magnification is the ratio of exit pupil diameter to the +entrance pupil diameter. + +p + pupil magnification (exit_pupil_diameter/entrance_pupil_diameter) + +For all symmetrical lenses and most normal lenses the aperture appears the same +from front and rear, so p~=1. Wide angle lenses frequently have p>1, while true +telephoto lenses usually have p<1. It can be shown that y = f*(1-1/p), and +substituting this into the above equation and carrying out some algebraic +manipulation yields that the relative brightness on the film is proportional to + +1/(N^2 ( 1 + M/p)^2) + +Let us define Ne, the effective f-number, to be an f-number with the lens +focused at infinity (M=0) that would give the same relative brightness on the +film (ignoring light loss due to absorption and reflection) as the actual +f-number N does with magnification M. + +Ne = N*(1+M/p) + +n An alternate, but less fundamental, explanation of bellows correction is just +the inverse square law applied to the exit pupil to film distance. Ne is +exit_pupil_to_film_distance/exit_pupil_diameter. + +It is convenient to think of the correction in terms of f-stops (powers of +two). The correction in powers of two (stops) is 2*Log2(1+M/p) = 6.64386 +Log10(1+M/p). Note that for most normal lenses y=0 and thus p=1, so the M/p can +be replaced by just M in the above equations. + +Circle of confusion, depth of field and hyperfocal distance. + +The light from a single subject point passing through the aperture is converged +by the lens into a cone with its tip at the film (if the point is perfectly in +focus) or slightly in front of or behind the film (if the subject point is +somewhat out of focus). In the out of focus case the point is rendered as a +circle where the film cuts the converging cone or the diverging cone on the +other side of the image point. This circle is called the circle of confusion. +The farther the tip of the cone, ie the image point, is away from the film, the +larger the circle of confusion. + +Consider the situation of a "main subject" that is perfectly in focus, and an +"alternate subject point" this is in front of or behind the subject. + +Soa + alternate subject point to front principal point distance +Sia + rear principal point to alternate image point distance +h + hyperfocal distance +C + diameter of circle of confusion +c + diameter of largest acceptable circle of confusion +N + f-stop (focal length divided by diameter of entrance pupil) +Ne + effective f-stop Ne = N * (1+M/p) +D + the aperture (entrance pupil) diameter (D=f/N) +M + magnification (M=f/(So-f)) + +The diameter of the circle of confusion can be computed by similar triangles, +and then solved in terms of the lens parameters and subject distances. For a +while let us assume unity pupil magnification, i.e. p=1. + +When So is finite +C = D*(Sia-Si)/Sia = f^2*(So/Soa-1)/(N*(So-f)) +When So = Infinity, +C = f^2/(N Soa) + +Note that in this formula C is positive when the alternate image point is +behind the film (i.e. the alternate subject point is in front of the main +subject) and negative in the opposite case. In reality, the circle of confusion +is always positive and has a diameter equal to Abs(C). + +If the circle of confusion is small enough, given the magnification in printing +or projection, the optical quality throughout the system, etc., the image will +appear to be sharp. Although there is no one diameter that marks the boundary +between fuzzy and clear, .03 mm is generally used in 35mm work as the diameter +of the acceptable circle of confusion. (I arrived at this by observing the +depth of field scales or charts on/with a number of lenses from Nikon, Pentax, +Sigma, and Zeiss. All but the Zeiss lens came out around .03mm. The Zeiss lens +appeared to be based on .025 mm.) Call this diameter c. + +If the lens is focused at infinity (so the rear principal point to film +distance equals the focal length), the distance to closest point that will be +acceptably rendered is called the hyperfocal distance. + +h = f^2/(N*c) + +If the main subject is at a finite distance, the closest alternative point that +is acceptably rendered is at at distance + +Sclose = h So/(h + (So-F)) + +and the farthest alternative point that is acceptably rendered is at distance + +Sfar = h So/(h - (So - F)) + +except that if the denominator is zero or negative, Sfar = infinity. + +We call Sfar-So the rear depth of field and So-Sclose the front depth field. + +A form that is exact, even when P != 1, is + +depth of field = + =c Ne / (M^2 * (1 +or- (So-f)/h1)) + = c N (1+M/p) / (M^2 * (1 +or- (N c)/(f M)) + +where h1 = f^2/(N c), ie the hyperfocal distance given c, N, and f and assuming +P=1. Use + for front depth of field and - for rear depth of field. If the +denominator goes zero or negative, the rear depth of field is infinity. + +This is a very nice equation. It shows that for distances short with respect to +the hyperfocal distance, the depth of field is very close to just c*Ne/M^2. As +the distance increases, the rear depth of field gets larger than the front +depth of field. The rear depth of field is twice the front depth of field when +So-f is one third the hyperfocal distance. And when So-f = h1, the rear depth +of field extends to infinity. + +If we frame a subject the same way with two different lenses, i.e. M is the +same both both situations, the shorter focal length lens will have less front +depth of field and more rear depth of field at the same effective f-stop. (To a +first approximation, the depth of field is the same in both cases.) + +Another important consideration when choosing a lens focal length is how a +distant background point will be rendered. Points at infinity are rendered as +circles of size + +C = f M / N + +So at constant subject magnification a distant background point will be blurred +in direct proportion to the focal length. + +This is illustrated by the following example, in which lenses of 50mm and 100 +mm focal lengths are both set up to get a magnification of 1/10. Both lenses +are set to f/8. The graph shows the circle of confusions for points as a +function of the distance behind the subject. + +circle of confusion (mm) + # + # *** 100mm f/8 + # ... 50mm f/8 + 0.8 # ******* + # ********* + # ********* + # **** + # ***** + # **** + 0.6 # **** + # ***** ....... + # *** .................. + # ** ............. + 0.4 # **** ......... + # *** .... + # ** ..... + # * .... + # **.. + 0.2 # **. + # .*. + # ** + #* + *###################################################################### + 0 # + 250 500 750 1000 1250 1500 1750 2000 + distance behind subject (mm) + +The standard .03mm circle of confusion criterion is clear down in the ascii +fuzz. The slope of both graphs is the same near the origin, showing that to a +first approximation both lenses have the same depth of field. However, the +limiting size of the circle of confusion as the distance behind the subject +goes to infinity is twice as large for the 100mm lens as for the 50mm lens. + +Diffraction + +When a beam of parallel light passes through a circular aperture it spreads out +a little, a phenomenon known as diffraction. The smaller the aperture, the more +the spreading. The field strength (of the electric or magnetic field) at angle +phi from the axis is proportional to + +lambda/(phi Pi R) * BesselJ1(2 phi Pi R/lambda), + +where R is the radius of the aperture, lambda is the wavelength of the light, +and BesselJ1 is the first order Bessel function. The power (intensity) is +proportional to the square of this. + +n The field strength function forms a bell-shaped curve, but unlike the classic +E^(-x^2) one, it eventually oscillates about zero. Its first zero at 1.21967 +lambda/(2 R). There are actually an infinite number of lobes after this, but +about 86% of the power is in the circle bounded by the first zero. + + Relative field strength + + *** + 1 # **** + # ** + 0.8 # * + # ** + # * + # ** + # * + 0.6 # * + # * + # * + 0.4 # * + # * + # ** + 0.2 # ** + # ** + # ** ***************** + ###############################*###################*****################### + # ***** ****** + # 0.5 1 1.5****** 2 2.5 3 + + + Angle from axis (relative to lambda/diameter_of_aperture) + +Approximating the diaphragm to film distance as f and making use of the fact +that the aperture has diameter f/N, it follows directly that the diameter of +the first zero of the diffraction pattern is 2.43934*N*lambda. Applying this in +a normal photographic situation is difficult, since the light contains a whole +spectrum of colors. We really need to integrate over the visible spectrum. The +eye has maximum sensitive around 555 nm, in the yellow green. If, for +simplicity, we take 555 nm as the wavelength, the diameter of the first zero, +in mm, comes out to be 0.00135383 N. + +As was mentioned above, the normally accepted circle of confusion for depth of +field is .03 mm, but .03/0.00135383 = 22.1594, so we can see that at f/22 the +diameter of the first zero of the diffraction pattern is as large is the +acceptable circle of confusion. + +A common way of rating the resolution of a lens is in line pairs per mm. It is +hard to say when lines are resolvable, but suppose that we use a criterion that +the center of the dark area receive no more than 80% of the light power +striking the center of the lightest areas. Then the resolution is 0.823 +/(lambda*N) lpmm. If we again assume 555 nm, this comes out to 1482/N lpmm, +which is in close agreement with the widely used rule of thumb that the +resolution is diffraction limited to 1500/N lpmm. However, note that the MTF, +discussed below, provides another view of this subject. + +Modulation Transfer Function + +The modulation transfer function is a measure of the extent to which a lens, +film, etc., can reproduce detail in an image. It is the spatial analog of +frequency response in an electrical system. The exact definition of the +modulation transfer function and the related optical transfer function varies +slightly amongst different authorities. + +The 2-dimensional Fourier transform of the point spread function is known as +the optical transfer function (OTF). The value of this function along any +radius is the fourier transform of the line spread function in the same +direction. The modulation transfer function is the absolute value of the +fourier transform of the line spread function. + +Equivalently, the modulation transfer function of a lens is the ratio of +relative image contrast divided by relative subject contrast of a subject with +sinusoidally varying brightness as a function of spatial frequency (e.g. cycles +per mm). Relative contrast is defined as (Imax-Imin)/(Imax+Imin). MTF can also +be used for film, but since film has a non-linear characteristic curve, the +density is first transformed back to the equivalent intensity by applying the +inverse of the characteristic curve. + +For a lens the MTF can vary with almost every conceivable parameter, including +f-stop, subject distance, distance of the point from the center, direction of +modulation, and spectral distribution of the light. The two standard directions +are radial (also known as saggital) and tangential. + +The MTF for an an ideal diffraction-free lens is a constant 1 from 0 to +infinity at every point and direction. For a practical lens it starts out near +1, and falls off with increasing spatial frequency, with the falloff being +worse at the edges than at the center. Flare would make the MTF of a lens be +less than one even at zero spatial frequency. Adjacency effects in film can +make the MTF of film be greater than 1 in certain frequency ranges. + +An advantage of the MTF as a measure of performance is that under some +circumstances the MTF of the system is the product (frequency by frequency) of +the (properly scaled) MTFs of its components. Such multiplication is always +allowed when each step accepts as input solely the intensity of the output of +the previous state, or some function of that intensity. Thus it is legitimate +to multiply lens and film MTFs or the MTFs of a two lens system with a diffuser +in the middle. However, the MTFs of cascaded ordinary lenses can legitimately +be multiplied only when a set of quite restrictive and technical conditions is +satisfied. + +As an example of some OTF/MTF functions, below are the OTFs of pure diffraction +for an f/22 aperture, and the OTF induced by a .03mm circle of confusion of a +de-focused but otherwise perfect and diffraction free lens. (Note that these +cannot be multiplied.) + +Let lambda be the wavelength of the light, and spf the spatial frequency in +cycles per mm. + +For diffraction the formulas is + +OTF(lambda,N,spf) = + = ArcCos(lambda*N*spf) -lambda*N*spf*Sqrt(1-(lambda*N*spf)^2), + if lambda*N*spf <=1 + = 0, + if lambda*N*spf >=1 + +Note that for lambda = 555 nm, the OTF is zero at spatial frequencies of 1801/N +cycles per mm and beyond. + +For a circle of confusion of diameter C, + +OTF(C,spf) = 2 * BesselJ1(Pi C spf)/(Pi C spf) + +This goes negative at certain frequencies. Physically, this would mean that if +the test pattern were lighter right on the optical center then nearby, the +image would be darker right on the optical center than nearby. The MTF is the +absolute value of this function. Some authorities use the term "spurious +resolution" for spatial frequencies beyond the first zero. + +Here is a graph of the OTF of both a .03mm circle of confusion and an f/22 +diffraction limit. + + OTF + + # + 1 *** + #..** + # ..** + # ..* *** .03 mm circle of confusion + 0.8 # .* ... 555nm f/22 diffraction + # *. + # *.. + # * .. + 0.6 # * . + # * . + # * .. + # * ... + 0.4 # * .. + # * .. + # * .. + # * ... + 0.2 # * ... + # * ... + # * ... + # ** .. ********** + #########################*##################.*****..........*****........## + # ** *** ******** + # 20 40 *** 60**** 80 100 120 + # ******** + # + spatial frequency (cycles/mm) + +Although this graph is linear in both axes, the typical MTF is presented in a +log-log plot. + +Illumination + +(by John Bercovitz) + +The Photometric System + +Light flux, for the purposes of illumination engineering, is measured in +lumens. A lumen of light, no matter what its wavelength (color), appears +equally bright to the human eye. The human eye has a stronger response to some +wavelengths of light than to other wavelengths. The strongest response for the +light-adapted eye (when scene luminance > .001 Lambert) comes at a wavelength +of 555 nm. A light-adapted eye is said to be operating in the photopic region. +A dark-adapted eye is operating in the scotopic region (scene luminance +Last modified: Mon Mar 27 18:10:03 1995 diff --git a/cdemolb.h b/cdemolb.h new file mode 100644 index 0000000..746f6c7 --- /dev/null +++ b/cdemolb.h @@ -0,0 +1,129 @@ +/* + * $Header: cdemolb.h 14-jul-99.12:45:58 mjaeger Exp $ + */ + +/* Copyright (c) 1996, 1999,, 2000 Oracle Corporation. All rights reserved. +*/ + +/* NOTE: See 'header_template.doc' in the 'doc' dve under the 'forms' + directory for the header file template that includes instructions. +*/ + +/* + NAME + cdemolb.h - header file for cdemolb.c + + DESCRIPTION + see cdemolb.c + + RELATED DOCUMENTS + + INSPECTION STATUS + Inspection date: + Inspection status: + Estimated increasing cost defects per page: + Rule sets: + + ACCEPTANCE REVIEW STATUS + Review date: + Review status: + Reviewers: + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + EXAMPLES + + NOTES + see cdemolb.c + + MODIFIED (MM/DD/YY) + dchatter 05/09/00 - lob read as char + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 09/09/98 - lines longer than 79 chars reformatted - bug 722491 + azhao 01/31/97 - don't include orastd.h + azhao 01/30/97 - fix lint error + echen 01/03/97 - OCI beautification + pshah 10/11/96 - + aroy 07/22/96 - header file for cdemolb.c + aroy 07/22/96 - Creation + +*/ + + +#ifndef cdemolb +# define cdemolb + +#ifndef OCI_ORACLE +#include +#endif + +/*--------------------------------------------------------------------------- + TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ +#define LFCOUNT 2 +#define STMTLEN 100 + +#define LONGTEXTLENGTH 1024 +#define BUFSIZE 1024 + +#define EX_FAILURE 1 +#define EX_SUCCESS 0 + +#define CDEMOLB_TEXT_FILE "cdemolb.dat" + +static CONST text insstmt[LFCOUNT][STMTLEN] = + { + "INSERT INTO CLBTAB VALUES ( 'Jack', EMPTY_CLOB())", + "" + }; + +static CONST text selstmt[LFCOUNT][STMTLEN] = + { + "SELECT essay FROM CLBTAB WHERE name = 'Jack' for update", + "SELECT essay FROM CLBTAB WHERE name = 'Jack'" + }; + +typedef struct { /* statement bind/define handles */ + OCIStmt *stmhp; + OCIBind *bndhp[2]; + OCIDefine *dfnhp[2]; +} stmtdef; + +typedef struct { /* GLOBAL STRUCTURE */ + OCIEnv *envhp; /* Environment handle */ + OCISvcCtx *svchp; /* Service handle */ + OCIServer *srvhp; /* Server handles */ + OCIError *errhp; /* Error handle */ + OCISession *authp; /* Authentication handle */ + stmtdef *s1; /*Statement handle 1 - for inserting*/ + stmtdef *s2; /* Handle for -select update */ +} ldemodef; + +/* define macros to be used in tests */ +#define COMMENT(x) (void) fprintf(stdout,"\nCOMMENT: %s\n", x) + +/*--------------------------------------------------------------------------- + FUNCTIONS + ---------------------------------------------------------------------------*/ +static void alloc_lob_desc(/*_ ldemodef *ctx, OCILobLocator **lobsrc _*/); +static ldemodef *alloc_handles(/*_ void _*/); +static void cleanup(/*_ ldemodef *ctx _*/); +static void errrpt(/*_ ldemodef *ctx, const text *op _*/); +static void authenticate_user(/*_ ldemodef *ctx _*/); +static void alloc_stmt_handles(/*_ ldemodef *ctx, stmtdef *sptr, + sb2 nbnd, sb2 ndfn _*/); +static void insert_select_loc (/*_ ldemodef *ctx, dvoid *lobsrc _*/); + +static void select_loc_data (/*_ ldemodef *ctx _*/); + +static void Write_to_loc(/*_ ldemodef *ctx, OCILobLocator *lobp _*/); +static void Read_from_loc(/*_ ldemodef *ctx, OCILobLocator *lobp _*/); +static void deauthenticate(/*_ ldemodef *ctx _*/); + + +#endif /* cdemolb */ + diff --git a/cdemolb.sql b/cdemolb.sql new file mode 100644 index 0000000..362c770 --- /dev/null +++ b/cdemolb.sql @@ -0,0 +1,27 @@ +rem +rem $Header: cdemolb.sql 14-jul-99.13:52:13 mjaeger Exp $ +rem +rem cdemolb.sql +rem +rem Copyright (c) 1996, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem cdemolb.sql - +rem +rem DESCRIPTION +rem +rem +rem NOTES +rem +rem +rem MODIFIED (MM/DD/YY) +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem aroy 07/22/96 - SQL program to create tables for cdemolb +rem aroy 07/22/96 - Created +rem + +connect scott/tiger; +DROP TABLE CLBTAB; +CREATE TABLE CLBTAB (name char(20), essay CLOB); +exit; + diff --git a/cdemolb2.c b/cdemolb2.c new file mode 100644 index 0000000..af66db8 --- /dev/null +++ b/cdemolb2.c @@ -0,0 +1,962 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemolb2.c 10-oct-2006.14:39:58 azhao Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1996, 2006, Oracle. All rights reserved. +*/ + +/* + + NAME + cdemolb2.c - Demonstrates writing and reading of CLOB/BLOB columns + with stream mode and with callback functions. + + DESCRIPTION + This program takes 2 input files (the first a text file and the + second a binary file) and stores the files into CLOB, BLOB columns. + + On output, the program reads the newly populated CLOB/BLOB columns + and writes them to the output files (txtfile1.log, binfile1.log, + txtfile2.log, binfile2.log), where + + txtfile1.log -- created for stream reading CLOB contents to it + binfile1.log -- created for stream reading BLOB contents to it + + txtfile2.log -- created for callback reading CLOB contents to it + binfile2.log -- created for callback reading BLOB contents to it + + + Sample usage: cdemolb2 cdemolb.dat giffile.dat + + cdemolb.dat -- a text file in the demo directory + giffile.dat -- a gif file in the demo directory + + After successful execution of the program, the files, cdemolb.dat, + txtfile1.log, and txtfile2.log should be identical. giffile.dat, + binfile1.log, and binfile2.log should be identical. + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + + + NOTES + + + MODIFIED (MM/DD/YY) + azhao 10/10/06 - case-senstive password change + aliu 02/17/05 - fix lint issues + aliu 02/16/05 - fix bug 4184372 + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 09/09/98 - lines longer than 79 chars reformatted - bug 722491 + azhao 08/19/97 - replace OCIStmtBindByPos with OCIBindByPos + azhao 06/25/97 - use rb, wb when opening bin file + cchau 03/03/97 - change functions to long names + azhao 01/31/97 - return OCI_ERROR if OCIStmtBindByPos fails + azhao 01/30/97 - fix lint error + azhao 12/31/96 - correct typo + azhao 12/31/96 - Creation + +*/ + +#include +#include +#include + +static sb4 init_handles(/*_ void _*/); +static sb4 log_on(/*_ void _*/); +static sb4 setup_table(/*_ void _*/); +static sb4 select_locator(/*_ int rowind _*/); +static ub4 file_length(/*_ FILE *fp _*/); +static sb4 test_file_to_lob(/*_ int rowind, char *tfname, char *bfname _*/); +static void test_lob_to_file(/*_ int rowind _*/); +static void stream_write_lob(/*_ int rowind, OCILobLocator *lobl, + FILE *fp, ub4 filelen _*/); +static void callback_write_lob(/*_ int rowind, OCILobLocator *lobl, + FILE *fp, ub4 filelen _*/); +static void stream_read_lob(/*_ int rowind, OCILobLocator *lobl, FILE *fp _*/); +static void callback_read_lob(/*_ int rowind, OCILobLocator *lobl, + FILE *fp _*/); +static sb4 cbk_fill_buffer(/*_ dvoid *ctxp, dvoid *bufxp, ub4 *lenp, + ub1 *piece _*/); +static sb4 cbk_write_buffer(/*_ dvoid *ctxp, CONST dvoid *bufxp, ub4 lenp, + ub1 piece _*/); + +static void logout(/*_ void _*/); +static void drop_table(/*_ void _*/); +static void report_error(/*_ void _*/); + +int main(/*_ int argc, char *argv[] _*/); + +#define TRUE 1 +#define FALSE 0 + +#define MAXBUFLEN 5000 + +static OCIEnv *envhp; +static OCIServer *srvhp; +static OCISvcCtx *svchp; +static OCIError *errhp; +static OCISession *authp; +static OCIStmt *stmthp; +static OCILobLocator *clob, *blob; +static OCIDefine *defnp1 = (OCIDefine *) 0, *defnp2 = (OCIDefine *) 0; +static OCIBind *bndhp = (OCIBind *) 0; + +static FILE *fp1, *fp2; + +static ub4 txtfilelen = 0; +static ub4 binfilelen = 0; + +static boolean istxtfile; +static boolean tab_exists = FALSE; + +/*------------------------end of Inclusions-----------------------------*/ + +int main(argc, argv) +int argc; +char *argv[]; +{ + int rowind; + + if (argc != 3) + { + (void) printf("Usage: %s txtfilename binfilename\n", argv[0]); + return 0; + } + + if (init_handles()) + { + (void) printf("FAILED: init_handles()\n"); + return OCI_ERROR; + } + + if (log_on()) + { + (void) printf("FAILED: log_on()\n"); + return OCI_ERROR; + } + + if (setup_table()) + { + (void) printf("FAILED: setup_table()\n"); + logout(); + return OCI_ERROR; + } + + tab_exists = TRUE; + + for (rowind = 1; rowind <= 2; rowind++) + { + if (select_locator(rowind)) + { + (void) printf("FAILED: select_locator()\n"); + logout(); + return OCI_ERROR; + } + + if (test_file_to_lob(rowind, argv[1], argv[2])) + { + (void) printf("FAILED: load files to lobs\n"); + logout(); + return OCI_ERROR; + } + + test_lob_to_file(rowind); + } + + logout(); + + return OCI_SUCCESS; +} + + + + +/* ----------------------------------------------------------------- */ +/* initialize environment, allocate handles, etc. */ +/* ----------------------------------------------------------------- */ + +sb4 init_handles() +{ + if (OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 )) + { + (void) printf("FAILED: OCIInitialize()\n"); + return OCI_ERROR; + } + + /* initialize environment handle */ + if (OCIEnvInit((OCIEnv **) &envhp, (ub4) OCI_DEFAULT, + (size_t) 0, (dvoid **) 0 )) + { + (void) printf("FAILED: OCIEnvInit()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &stmthp, + (ub4) OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIDescriptorAlloc((dvoid *) envhp, (dvoid **) &clob, + (ub4)OCI_DTYPE_LOB, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIDescriptorAlloc()\n"); + return OCI_ERROR; + } + + /* allocate the lob locator variables */ + if (OCIDescriptorAlloc((dvoid *) envhp, (dvoid **) &blob, + (ub4)OCI_DTYPE_LOB, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIDescriptorAlloc()\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + + +/* ----------------------------------------------------------------- */ +/* attach to the server and log on as SCOTT/TIGER */ +/* ----------------------------------------------------------------- */ + +sb4 log_on() +{ + text *uid = (text *)"SCOTT"; + text *pwd = (text *)"tiger"; + text *cstring = (text *) ""; + + /* attach to the server */ + if (OCIServerAttach(srvhp, errhp, (text *) cstring, + (sb4) strlen((char *)cstring), (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIServerAttach()\n"); + return OCI_ERROR; + } + + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) uid, (ub4) strlen((char *)uid), + (ub4) OCI_ATTR_USERNAME, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) pwd, (ub4) strlen((char *)pwd), + (ub4) OCI_ATTR_PASSWORD, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + /* set the server attribute in the service context */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, (ub4) OCI_ATTR_SERVER, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + /* log on */ + if (OCISessionBegin(svchp, errhp, authp, (ub4) OCI_CRED_RDBMS, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCISessionBegin()\n"); + return OCI_ERROR; + } + + /* set the session attribute in the service context */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, (dvoid *) authp, + (ub4) 0, (ub4) OCI_ATTR_SESSION, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; + +} + + +/* ----------------------------------------------------------------- */ +/* Create table FOO with CLOB, BLOB columns and insert one row. */ +/* Both columns are empty lobs, not null lobs. */ +/* ----------------------------------------------------------------- */ + +sb4 setup_table() +{ + int colc; + + text *crtstmt = (text *) "CREATE TABLE FOO (A CLOB, B BLOB, C INTEGER)"; + text *insstmt = + (text *) "INSERT INTO FOO VALUES (EMPTY_CLOB(), EMPTY_BLOB(), :1)"; + + if (OCIStmtPrepare(stmthp, errhp, crtstmt, (ub4) strlen((char *) crtstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() crtstmt\n"); + return OCI_ERROR; + } + + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) 0, (OCISnapshot *) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() crtstmt\n"); + return OCI_ERROR; + } + + if (OCIStmtPrepare(stmthp, errhp, insstmt, (ub4) strlen((char *) insstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() insstmt\n"); + return OCI_ERROR; + } + + if (OCIBindByPos(stmthp, &bndhp, errhp, (ub4) 1, + (dvoid *) &colc, (sb4) sizeof(colc), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIBindByPos()\n"); + return OCI_ERROR; + } + + for (colc = 1; colc <= 2; colc++) + { + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) 0, (OCISnapshot *) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() insstmt\n"); + return OCI_ERROR; + } + } + + (void) OCITransCommit(svchp, errhp, (ub4)0); + + return OCI_SUCCESS; +} + + + +/*---------------------------------------------------------------------*/ +/* Select lob locators from the CLOB, BLOB columns. */ +/* We need the 'FOR UPDATE' clause since we need to write to the lobs. */ +/*---------------------------------------------------------------------*/ + +sb4 select_locator(int rowind) +{ + int colc = rowind; + text *sqlstmt = (text *)"SELECT A, B FROM FOO WHERE C = :1 FOR UPDATE"; + + if (OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4) strlen((char *)sqlstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() sqlstmt\n"); + return OCI_ERROR; + } + + if (OCIBindByPos(stmthp, &bndhp, errhp, (ub4) 1, + (dvoid *) &colc, (sb4) sizeof(colc), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIBindByPos()\n"); + return OCI_ERROR; + } + + if (OCIDefineByPos(stmthp, &defnp1, errhp, (ub4) 1, + (dvoid *) &clob, (sb4) -1, (ub2) SQLT_CLOB, + (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) OCI_DEFAULT) + || OCIDefineByPos(stmthp, &defnp2, errhp, (ub4) 2, + (dvoid *) &blob, (sb4) -1, (ub2) SQLT_BLOB, + (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIDefineByPos()\n"); + return OCI_ERROR; + } + + /* execute the select and fetch one row */ + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() sqlstmt\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + + +/* ----------------------------------------------------------------- */ +/* Read operating system files into local buffers and then write the */ +/* buffers to lobs. */ +/* ----------------------------------------------------------------- */ + +sb4 test_file_to_lob(int rowind, char *txtfile, char *binfile) +{ + (void) printf("\n===> Testing loading files into lobs .....\n\n"); + + fp1 = fopen((const char *)txtfile, (const char *) "r"); + fp2 = fopen((const char *)binfile, (const char *) "rb"); + + if ( !(fp1 && fp2)) + { + (void) printf("ERROR: Failed to open file(s).\n"); + return -1; + } + + txtfilelen = file_length(fp1); + binfilelen = file_length(fp2); + + switch (rowind) + { + case 1: + stream_write_lob(rowind, clob, fp1, txtfilelen); + stream_write_lob(rowind, blob, fp2, binfilelen); + break; + case 2: + istxtfile = TRUE; + callback_write_lob(rowind, clob, fp1, txtfilelen); + istxtfile = FALSE; + callback_write_lob(rowind, blob, fp2, binfilelen); + break; + default: + (void) printf("ERROR: Invalid row indicator.\n"); + break; + } + + (void) fclose(fp1); + (void) fclose(fp2); + + return 0; +} + + +/* ----------------------------------------------------------------- */ +/* get the length of the input file. */ +/* ----------------------------------------------------------------- */ + +ub4 file_length(FILE *fp) +{ + fseek(fp, 0, SEEK_END); + return (ub4) (ftell(fp)); +} + + +/* ----------------------------------------------------------------- */ +/* Read operating system files into local buffers and then write the */ +/* buffers to lobs using stream mode. */ +/* ----------------------------------------------------------------- */ + +void stream_write_lob(int rowind, OCILobLocator *lobl, FILE *fp, ub4 filelen) +{ + ub4 offset = 1; + ub4 loblen = 0; + ub1 bufp[MAXBUFLEN]; + ub4 amtp = filelen; + ub1 piece; + sword retval; + int readval; + ub4 len = 0; + ub4 nbytes; + ub4 remainder = filelen; + + (void) printf("--> To do streamed write lob, amount = %d\n", filelen); + + (void) OCILobGetLength(svchp, errhp, lobl, &loblen); + (void) printf("Before stream write, LOB length = %d\n\n", loblen); + + (void) fseek(fp, 0, 0); + + if (filelen > MAXBUFLEN) + nbytes = MAXBUFLEN; + else + nbytes = filelen; + + if (fread((void *)bufp, (size_t)nbytes, 1, fp) != 1) + { + (void) printf("ERROR: read file.\n"); + return; + } + + remainder -= nbytes; + + if (remainder == 0) /* exactly one piece in the file */ + { + (void) printf("Only one piece, no need for stream write.\n"); + if (retval = OCILobWrite(svchp, errhp, lobl, &amtp, offset, (dvoid *) bufp, + (ub4) nbytes, OCI_ONE_PIECE, (dvoid *)0, + (OCICallbackLobWrite) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT) != OCI_SUCCESS) + { + (void) printf("ERROR: OCILobWrite(), retval = %d\n", retval); + return; + } + } + else /* more than one piece */ + { + if (OCILobWrite(svchp, errhp, lobl, &amtp, offset, (dvoid *) bufp, + (ub4) MAXBUFLEN, OCI_FIRST_PIECE, (dvoid *)0, + (OCICallbackLobWrite) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT) != OCI_NEED_DATA) + { + (void) printf("ERROR: OCILobWrite().\n"); + return; + } + + piece = OCI_NEXT_PIECE; + + do + { + if (remainder > MAXBUFLEN) + nbytes = MAXBUFLEN; + else + { + nbytes = remainder; + piece = OCI_LAST_PIECE; + } + + if (fread((void *)bufp, (size_t)nbytes, 1, fp) != 1) + { + (void) printf("ERROR: read file.\n"); + piece = OCI_LAST_PIECE; + } + + retval = OCILobWrite(svchp, errhp, lobl, &amtp, offset, (dvoid *) bufp, + (ub4) nbytes, piece, (dvoid *)0, + (OCICallbackLobWrite) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT); + remainder -= nbytes; + + } while (retval == OCI_NEED_DATA && !feof(fp)); + } + + if (retval != OCI_SUCCESS) + { + (void) printf("Error: stream writing LOB.\n"); + return; + } + + (void) OCILobGetLength(svchp, errhp, lobl, &loblen); + (void) printf("After stream write, LOB length = %d\n\n", loblen); + + return; +} + + +/* ----------------------------------------------------------------- */ +/* Read operating system files into local buffers and then write the */ +/* buffers to lobs using callback function. */ +/* ----------------------------------------------------------------- */ + +void callback_write_lob(int rowind, OCILobLocator *lobl, FILE *fp, ub4 filelen) +{ + ub4 offset = 1; + ub4 loblen = 0; + ub1 bufp[MAXBUFLEN]; + ub4 amtp = filelen; + ub4 nbytes; + sword retval; + + (void) printf("--> To do callback write lob, amount = %d\n", filelen); + + (void) OCILobGetLength(svchp, errhp, lobl, &loblen); + (void) printf("Before callback write, LOB length = %d\n\n", loblen); + + (void) fseek(fp, 0, 0); + + if (filelen > MAXBUFLEN) + nbytes = MAXBUFLEN; + else + nbytes = filelen; + + if (fread((void *)bufp, (size_t)nbytes, 1, fp) != 1) + { + (void) printf("ERROR: read file.\n"); + return; + } + + if (filelen < MAXBUFLEN) /* exactly one piece in the file */ + { + (void) printf("Only one piece, no need for callback write.\n"); + if (retval = OCILobWrite(svchp, errhp, lobl, &amtp, offset, (dvoid *) bufp, + (ub4) nbytes, OCI_ONE_PIECE, (dvoid *)0, + (OCICallbackLobWrite) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT) != OCI_SUCCESS) + { + (void) printf("ERROR: OCILobWrite().\n"); + return; + } + } + else /* more than one piece */ + { + if (retval = OCILobWrite(svchp, errhp, lobl, &amtp, offset, (dvoid *)bufp, + (ub4)nbytes, OCI_FIRST_PIECE, (dvoid *)0, + cbk_fill_buffer, (ub2) 0, (ub1) SQLCS_IMPLICIT)) + { + (void) printf("ERROR: OCILobWrite().\n"); + report_error(); + return; + } + } + + (void) OCILobGetLength(svchp, errhp, lobl, &loblen); + (void) printf("After callback write, LOB length = %d\n\n", loblen); + + return; +} + + + +/* ----------------------------------------------------------------- */ +/* callback function to read the file into buffer. */ +/* ----------------------------------------------------------------- */ + +sb4 cbk_fill_buffer(ctxp, bufxp, lenp, piece) + dvoid *ctxp; + dvoid *bufxp; + ub4 *lenp; + ub1 *piece; +{ + FILE *fp = (istxtfile ? fp1 : fp2); + ub4 filelen = (istxtfile ? txtfilelen : binfilelen); + ub4 nbytes; + static ub4 len = MAXBUFLEN; /* because 1st piece has been written */ + + + if ((filelen - len) > MAXBUFLEN) + nbytes = MAXBUFLEN; + else + nbytes = filelen - len; + + *lenp = nbytes; + + if (fread((void *)bufxp, (size_t)nbytes, 1, fp) != 1) + { + (void) printf("ERROR: read file. Abort callback fill buffer\n"); + *piece = OCI_LAST_PIECE; + len = MAXBUFLEN; /* reset it for the next callback_write_lob() */ + return OCI_CONTINUE; + } + + len += nbytes; + + if (len == filelen) /* entire file has been read */ + { + *piece = OCI_LAST_PIECE; + len = MAXBUFLEN; /* reset it for the next callback_write_lob() */ + } + else + *piece = OCI_NEXT_PIECE; + + return OCI_CONTINUE; +} + + +/* ----------------------------------------------------------------- */ +/* Read lobs into local buffers and then write them to operating */ +/* system files. */ +/* ----------------------------------------------------------------- */ + +void test_lob_to_file(int rowind) +{ + ub4 offset = 1; + ub4 loblen = 0; + ub1 bufp[MAXBUFLEN]; + ub4 amtp = MAXBUFLEN; + text txtfilename[20], binfilename[20]; + + (void) sprintf((char *) txtfilename, (char *)"txtfile%d.log", rowind); + (void) sprintf((char *) binfilename, (char *)"binfile%d.log", rowind); + + (void) printf("\n===> Testing writing lobs to files .....\n\n"); + + fp1 = fopen((char *)txtfilename, (const char *) "w"); + fp2 = fopen((char *)binfilename, (const char *) "wb"); + + if ( !(fp1 && fp2)) + { + (void) printf("ERROR: Failed to open file(s).\n"); + return; + } + + switch (rowind) + { + case 1: + stream_read_lob(rowind, clob, fp1); + stream_read_lob(rowind, blob, fp2); + break; + case 2: + istxtfile = TRUE; + callback_read_lob(rowind, clob, fp1); + + istxtfile = FALSE; + callback_read_lob(rowind, blob, fp2); + break; + default: + (void) printf("ERROR: Invalid row indicator.\n"); + break; + } + + (void) fclose(fp1); + (void) fclose(fp2); + + return; +} + + +/* ----------------------------------------------------------------- */ +/* Read lobs using stream mode into local buffers and then write */ +/* them to operating system files. */ +/* ----------------------------------------------------------------- */ + +void stream_read_lob(int rowind, OCILobLocator *lobl, FILE *fp) +{ + ub4 offset = 1; + ub4 loblen = 0; + ub1 bufp[MAXBUFLEN]; + ub4 amtp = 0; + sword retval; + ub4 piece = 0; + ub4 remainder; /* the number of bytes for the last piece */ + + (void) OCILobGetLength(svchp, errhp, lobl, &loblen); + amtp = loblen; + + (void) printf("--> To stream read LOB, loblen = %d.\n", loblen); + + memset((void *)bufp, '\0', MAXBUFLEN); + + retval = OCILobRead(svchp, errhp, lobl, &amtp, offset, (dvoid *) bufp, + (loblen < MAXBUFLEN ? loblen : MAXBUFLEN), (dvoid *)0, + (OCICallbackLobRead) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT); + + switch (retval) + { + case OCI_SUCCESS: /* only one piece */ + (void) printf("stream read %d th piece\n", ++piece); + (void) fwrite((void *)bufp, (size_t)loblen, 1, fp); + break; + case OCI_ERROR: + report_error(); + break; + case OCI_NEED_DATA: /* there are 2 or more pieces */ + + remainder = loblen; + + (void) fwrite((void *)bufp, MAXBUFLEN, 1, fp); /* full buffer to write */ + + do + { + memset((void *)bufp, '\0', MAXBUFLEN); + amtp = 0; + + remainder -= MAXBUFLEN; + + retval = OCILobRead(svchp, errhp, lobl, &amtp, offset, (dvoid *) bufp, + (ub4) MAXBUFLEN, (dvoid *)0, + (OCICallbackLobRead) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT); + + /* the amount read returned is undefined for FIRST, NEXT pieces */ + (void) printf("stream read %d th piece, amtp = %d\n", ++piece, amtp); + + if (remainder < MAXBUFLEN) /* last piece not a full buffer piece */ + (void) fwrite((void *)bufp, (size_t)remainder, 1, fp); + else + (void) fwrite((void *)bufp, MAXBUFLEN, 1, fp); + + } while (retval == OCI_NEED_DATA); + break; + default: + (void) printf("Unexpected ERROR: OCILobRead() LOB.\n"); + break; + } + + return; +} + + +/* ----------------------------------------------------------------- */ +/* Read lobs using callback function into local buffers and */ +/* then write them to operating system files. */ +/* ----------------------------------------------------------------- */ + +void callback_read_lob(int rowind, OCILobLocator *lobl, FILE *fp) +{ + ub4 offset = 1; + ub4 loblen = 0; + ub1 bufp[MAXBUFLEN]; + ub4 amtp = 0; + sword retval; + + (void) OCILobGetLength(svchp, errhp, lobl, &loblen); + amtp = loblen; + + (void) printf("--> To callback read LOB, loblen = %d.\n", loblen); + + if (retval = OCILobRead(svchp, errhp, lobl, &amtp, offset, (dvoid *) bufp, + (ub4) MAXBUFLEN, (dvoid *) bufp, + (OCICallbackLobRead) cbk_write_buffer, + (ub2) 0, (ub1) SQLCS_IMPLICIT)) + { + (void) printf("ERROR: OCILobRead() LOB.\n"); + report_error(); + } + + return; +} + + +/* ----------------------------------------------------------------- */ +/* callback function to write buffer to the file. */ +/* ----------------------------------------------------------------- */ + +sb4 cbk_write_buffer(ctxp, bufxp, lenp, piece) + dvoid *ctxp; + CONST dvoid *bufxp; + ub4 lenp; + ub1 piece; +{ + static ub4 piece_count = 0; + FILE *fp = (istxtfile ? fp1 : fp2); + + piece_count++; + + switch (piece) + { + case OCI_LAST_PIECE: + (void) fwrite((void *)bufxp, (size_t)lenp, 1, fp); + (void) printf("callback read the %d th piece\n\n", piece_count); + piece_count = 0; + return OCI_CONTINUE; + + case OCI_FIRST_PIECE: + case OCI_NEXT_PIECE: + (void) fwrite((void *)bufxp, (size_t)lenp, 1, fp); + break; + default: + (void) printf("callback read error: unkown piece = %d.\n", piece); + return OCI_ERROR; + } + + (void) printf("callback read the %d th piece\n", piece_count); + + return OCI_CONTINUE; +} + + +/*-------------------------------------------------------------------*/ +/* Drop table FOO before logging off from the server. */ +/*-------------------------------------------------------------------*/ + +void drop_table() +{ + text *sqlstmt = (text *) "DROP TABLE FOO"; + + if (OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4) strlen((char *) sqlstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() sqlstmt\n"); + return; + } + + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) 0, (OCISnapshot *) 0, + (ub4) OCI_DEFAULT)) + (void) printf("FAILED: OCIStmtExecute() sqlstmt\n"); + + return; +} + +/*-------------------------------------------------------------------*/ +/* Logoff and disconnect from the server. Free handles. */ +/*-------------------------------------------------------------------*/ + +void logout() +{ + if (tab_exists) + drop_table(); + + (void) OCISessionEnd(svchp, errhp, authp, (ub4) 0); + (void) OCIServerDetach(srvhp, errhp, (ub4) OCI_DEFAULT); + + (void) printf("Logged off and detached from server.\n"); + + (void) OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER); + (void) OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX); + (void) OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR); + (void) OCIHandleFree((dvoid *) authp, (ub4) OCI_HTYPE_SESSION); + (void) OCIDescriptorFree((dvoid *) clob, (ub4) OCI_DTYPE_LOB); + (void) OCIDescriptorFree((dvoid *) blob, (ub4) OCI_DTYPE_LOB); + (void) OCIHandleFree((dvoid *) stmthp, (ub4) OCI_HTYPE_STMT); + + (void) printf("All handles freed\n"); + return; +} + + +/* ----------------------------------------------------------------- */ +/* retrieve error message and print it out. */ +/* ----------------------------------------------------------------- */ +void report_error() +{ + text msgbuf[512]; + sb4 errcode = 0; + + (void) OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + (void) printf("ERROR CODE = %d\n", errcode); + (void) printf("%.*s\n", 512, msgbuf); + return; +} + + +/* end of file cdemolb2.c */ + diff --git a/cdemolbs.c b/cdemolbs.c new file mode 100644 index 0000000..407108b --- /dev/null +++ b/cdemolbs.c @@ -0,0 +1,1012 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemolbs.c 10-oct-2006.14:39:58 azhao Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1997, 2006, Oracle. All rights reserved. +*/ + +/* + + NAME + cdemolbs.c - Demonstrates reading and writing to LOBs through + the LOB Buffering Subsystem. + + DESCRIPTION + This program reads from an input binary/text file, writing into an + initialized B/CLOB column in buffered mode. It then reads in buffered + mode from the B/CLOB column and populates an output file. After building + the executable (assume it is called cdemolbs), run the program as follows: + cdemolbs src.txt src.bin dst.txt dst.bin + where src.txt and src.bin are text and binary files of size <= 512Kbytes. + IMPORTANT: . This program works only for single-byte CLOBs. + . Before running this program, ensure that the database is + started up and a table FOO does not exist in the SCOTT/ + TIGER sample account. + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + + + NOTES + + + MODIFIED (MM/DD/YY) + azhao 10/10/06 - case-senstive password change + gtarora 10/18/99 - Correct parameters to printf + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ramkrish 03/06/98 - 546944: add/modify output statements for debug mode + skotsovo 08/07/97 - modified lbs buffer size so max read allowed changed + azhao 07/15/97 - fix reading files + azhao 05/30/97 - Use OCIBindByPos + azhao 05/27/97 - add savepoint code + ramkrish 05/01/97 - Creation + +*/ + +#include +#include +#include + +/*--------------------- Public Constants and Variables ----------------------*/ + +/* Constants */ +#define TRUE 1 +#define FALSE 0 +#define MAXBUFLEN 32768 +/* the size of the lob buffer depends on the usable chunk size. For + * this example, the maximum amount of lob data that can be read in + * one call is 508928. + */ +#define MAXLBSLEN 508928 + +/* OCI Handles */ +static OCIEnv *envhp; +static OCIServer *srvhp; +static OCISvcCtx *svchp; +static OCIError *errhp; +static OCISession *authp; +static OCIStmt *stmthp; +static OCILobLocator *clob, *blob; +static OCIDefine *defnp1 = (OCIDefine *) 0, *defnp2 = (OCIDefine *) 0; +static OCIBind *bndhp = (OCIBind *) 0; + +/* Misellaneous */ +static FILE *fp1, *fp2; +static ub4 txtfilelen = 0; +static ub4 binfilelen = 0; +static boolean istxtfile; +static boolean tab_exists = FALSE; + +/*--------------------- Public functions - Specification --------------------*/ + +int main (/*_ int argc, char *argv[] _*/); + +static sb4 init_handles (/*_ void _*/); +static sb4 init_table (/*_ void _*/); +static sb4 log_on (/*_ void _*/); +static void log_off (/*_ void _*/); +static sb4 write_lobs (/*_ int rowind, char *txtfile, char *binfile _*/); +static sb4 read_lobs (/*_ int rowind, char *txtfile, char *binfile _*/); + +/*--------------------- Private functions - Specification -------------------*/ + +static sb4 select_clob (/*_ int rowind _*/); +static sb4 select_blob (/*_ int rowind _*/); +static sb4 select_lobs (/*_ int rowind _*/); +static sb4 buf_write_lob (/*_ int rowind, OCILobLocator *locator, FILE *fp, + ub4 filelen _*/); +static sb4 buf_read_lob (/*_ int rowind, OCILobLocator *locator, + FILE *fp _*/); +static void drop_table (/*_ void _*/); +static void report_error (/*_ void _*/); +static ub4 file_length (/*_ FILE *fp _*/); + +/*----------------------------- Public functions ----------------------------*/ + +/*---------------------------------- main -----------------------------------*/ + +/* main driver */ +int main(argc, argv) +int argc; +char *argv[]; +{ + int rowind; + + /* validate input arguments */ + if (argc != 5) + { + (void) printf("Usage: %s srctxtfile srcbinfile desttxtfile destbinfile\n", + argv[0]); + return 0; + } + /* initialize OCI handles */ + if (init_handles()) + { + (void) printf("FAILED: init_handles()\n"); + return OCI_ERROR; + } + /* log on to server */ + if (log_on()) + { + (void) printf("FAILED: log_on()\n"); + return OCI_ERROR; + } + /* init demo table */ + if (init_table()) + { + (void) printf("FAILED: init_table()\n"); + log_off(); + return OCI_ERROR; + } + /* write to LOBs in row 1 thro buffering subsystem, reading from src files */ + rowind = 1; + if (write_lobs(rowind, argv[1], argv[2])) + { + (void) printf("FAILED: write files to lobs\n"); + log_off(); + return OCI_ERROR; + } + /* read from LOBs in row 1 thro buffering subsystem, writing to dest files */ + rowind = 1; + if (read_lobs(rowind, argv[3], argv[4])) + { + (void) printf("FAILED: write lobs to files\n"); + log_off(); + return OCI_ERROR; + } + /* clean up and log off from server */ + log_off(); + + return OCI_SUCCESS; +} + +/*----------------------------- init_handles --------------------------------*/ + +/* initialize environment, and allocate all handles */ +sb4 init_handles() +{ + if (OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 )) + { + (void) printf("FAILED: OCIInitialize()\n"); + return OCI_ERROR; + } + /* initialize environment handle */ + if (OCIEnvInit((OCIEnv **) &envhp, (ub4) OCI_DEFAULT, + (size_t) 0, (dvoid **) 0 )) + { + (void) printf("FAILED: OCIEnvInit()\n"); + return OCI_ERROR; + } + /* initialize service context */ + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + /* initialize error handle */ + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + /* initialize statement handle */ + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &stmthp, + (ub4) OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + /* initialize server handle */ + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + /* initialize session/authentication handle */ + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + /* allocate the lob locator variables */ + if (OCIDescriptorAlloc((dvoid *) envhp, (dvoid **) &clob, + (ub4)OCI_DTYPE_LOB, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIDescriptorAlloc()\n"); + return OCI_ERROR; + } + if (OCIDescriptorAlloc((dvoid *) envhp, (dvoid **) &blob, + (ub4)OCI_DTYPE_LOB, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIDescriptorAlloc()\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + +/*------------------------------- init_table --------------------------------*/ + +/* create table FOO with initialized CLOB, BLOB columns, and insert two rows */ +sb4 init_table() +{ + int colc; + text *crtstmt = (text *) "CREATE TABLE FOO (C1 CLOB, C2 BLOB, C3 INTEGER)"; + text *insstmt = + (text *) "INSERT INTO FOO VALUES (EMPTY_CLOB(), EMPTY_BLOB(), :1)"; + + /* prepare create statement */ + if (OCIStmtPrepare(stmthp, errhp, crtstmt, (ub4) strlen((char *) crtstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() crtstmt\n"); + return OCI_ERROR; + } + /* execute create statement */ + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) 0, (OCISnapshot *) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() crtstmt\n"); + return OCI_ERROR; + } + /* prepare insert statement */ + if (OCIStmtPrepare(stmthp, errhp, insstmt, (ub4) strlen((char *) insstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() insstmt\n"); + return OCI_ERROR; + } + /* associate variable colc with bind placeholder #1 in the SQL statement */ + if (OCIBindByPos(stmthp, &bndhp, errhp, (ub4) 1, + (dvoid *) &colc, (sb4) sizeof(colc), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIBindByPos()\n"); + return OCI_ERROR; + } + /* insert two rows */ + for (colc = 1; colc <= 2; colc++) + { + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) 0, (OCISnapshot *) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() insstmt\n"); + return OCI_ERROR; + } + } + + /* commit the Xn */ + (void) OCITransCommit(svchp, errhp, (ub4)0); + + /* set flag to be used by log_off() to drop the table */ + tab_exists = TRUE; + + return OCI_SUCCESS; +} + +/*---------------------------------- log_on ---------------------------------*/ + +/* attach to the server and log on as SCOTT/TIGER */ +sb4 log_on() +{ + text *uid = (text *)"SCOTT"; + text *pwd = (text *)"tiger"; + text *cstring = (text *)""; + + /* attach to the server */ + if (OCIServerAttach(srvhp, errhp, (text *) cstring, + (sb4) strlen((char *)cstring), (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIServerAttach()\n"); + return OCI_ERROR; + } + + /* set username and password attributes of the server handle */ + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) uid, (ub4) strlen((char *)uid), + (ub4) OCI_ATTR_USERNAME, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) pwd, (ub4) strlen((char *)pwd), + (ub4) OCI_ATTR_PASSWORD, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + /* set the server attribute in the service context */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, (ub4) OCI_ATTR_SERVER, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + /* log on */ + if (OCISessionBegin(svchp, errhp, authp, (ub4) OCI_CRED_RDBMS, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCISessionBegin()\n"); + return OCI_ERROR; + } + + /* set the session attribute in the service context */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, (dvoid *) authp, + (ub4) 0, (ub4) OCI_ATTR_SESSION, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + return OCI_SUCCESS; +} + +/*------------------------------------ logoff -------------------------------*/ + +/* Logoff and disconnect from the server. Free handles */ +void log_off() +{ + if (tab_exists) + drop_table(); + + (void) OCISessionEnd(svchp, errhp, authp, (ub4) 0); + (void) OCIServerDetach(srvhp, errhp, (ub4) OCI_DEFAULT); + + (void) printf("\n\nLogged off and detached from server.\n"); + + (void) OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER); + (void) OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX); + (void) OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR); + (void) OCIHandleFree((dvoid *) authp, (ub4) OCI_HTYPE_SESSION); + (void) OCIDescriptorFree((dvoid *) clob, (ub4) OCI_DTYPE_LOB); + (void) OCIDescriptorFree((dvoid *) blob, (ub4) OCI_DTYPE_LOB); + (void) OCIHandleFree((dvoid *) stmthp, (ub4) OCI_HTYPE_STMT); + + (void) printf("\nAll handles freed\n"); + return; +} + +/*-------------------------------- write_lobs -------------------------------*/ + +/* write from files to LOBs */ +sb4 write_lobs (rowind, txtfile, binfile) +int rowind; +char *txtfile; +char *binfile; +{ + ub4 loblen = 0; + text *svptstmt = (text *)"SAVEPOINT cdemolbs_svpt"; + text *rlbkstmt = (text *)"ROLLBACK TO SAVEPOINT cdemolbs_svpt"; + ub4 txtfilelen = 0; + ub4 binfilelen = 0; + + /* validate row indicator */ + if (!rowind || (rowind > 2)) + { + (void) printf("ERROR: Invalid row indicator.\n"); + return OCI_ERROR; + } + /* open source files */ + fp1 = fopen((CONST char *)txtfile, (CONST char *) "r"); + fp2 = fopen((CONST char *)binfile, (CONST char *) "rb"); + if (!(fp1 && fp2)) + { + (void) printf("ERROR: Failed to open file(s).\n"); + return -1; + } + if ((txtfilelen = file_length(fp1)) > MAXLBSLEN) + { + (void) printf("ERROR: %s - length > 512Kbytes", txtfile); + return -1; + } + if ((binfilelen = file_length(fp2)) > MAXLBSLEN) + { + (void) printf("ERROR: %s - length > 512Kbytes", binfile); + return -1; + } + + /* reset file pointers to start of file */ + (void) fseek(fp1, 0, 0); + (void) fseek(fp2, 0, 0); + + /* set savepoint for Xn before commencing buffered mode operations */ + if (OCIStmtPrepare(stmthp, errhp, svptstmt, (ub4) strlen((char *)svptstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() svptstmt\n"); + return OCI_ERROR; + } + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() svptstmt\n"); + report_error(); + return OCI_ERROR; + } + + (void) printf("\n===> Writing CLOB from txtfile in buffered mode.....\n\n"); + + /* fetch the CLOB's locator from the table for update */ + if (select_clob(rowind)) + { + (void) printf("FAILED: select_clob()\n"); + log_off(); + return OCI_ERROR; + } + + /* report CLOB length before buffered write begins */ + (void) OCILobGetLength(svchp, errhp, clob, &loblen); + (void) printf("\nBefore buffered write, CLOB length = %d\n\n", loblen); + + /* enable the CLOB locator for buffering operations */ + if (OCILobEnableBuffering(svchp, errhp, clob)) + { + (void) printf("FAILED: OCILobEnableBuffering() CLOB\n"); + return OCI_ERROR; + } + + /* write the text file contents into CLOB through the buffering subsystem */ + if (buf_write_lob(rowind, clob, fp1, txtfilelen) == OCI_ERROR) + { + /* if buffered write operation failed, rollback Xn to savepoint & exit */ + if (OCIStmtPrepare(stmthp, errhp, rlbkstmt, (ub4) strlen((char *)rlbkstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() rlbkstmt\n"); + return OCI_ERROR; + } + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() rlbkstmt\n"); + report_error(); + return OCI_ERROR; + } + + (void) printf("FAILED: buf_write_lob() CLOB\n"); + return OCI_ERROR; + } + + /* commit the Xn if the CLOB's buffer was flushed successfully */ + (void) OCITransCommit(svchp, errhp, (ub4)0); + + /* disable CLOB locator from buffering */ + if (OCILobDisableBuffering(svchp, errhp, clob)) + { + (void) printf("FAILED: OCILobDisableBuffering() CLOB\n"); + return OCI_ERROR; + } + + (void) printf("\n===> Writing BLOB from binfile in buffered mode.....\n\n"); + + /* fetch the BLOB's locator from the table for update */ + if (select_blob(rowind)) + { + (void) printf("FAILED: select_blob()\n"); + log_off(); + return OCI_ERROR; + } + + /* report LOB length before buffered write begins */ + (void) OCILobGetLength(svchp, errhp, blob, &loblen); + (void) printf("\nBefore buffered write, BLOB length = %d\n\n", loblen); + + /* enable the BLOB locator for buffering operations */ + if (OCILobEnableBuffering(svchp, errhp, blob)) + { + (void) printf("FAILED: OCILobEnableBuffering() BLOB\n"); + return OCI_ERROR; + } + + /* write the bin file contents into BLOB through the buffering subsystem */ + if (buf_write_lob(rowind, blob, fp2, binfilelen) > 0) + { + /* if buffered write operation failed, rollback Xn to savepoint & exit */ + if (OCIStmtPrepare(stmthp, errhp, rlbkstmt, (ub4) strlen((char *)rlbkstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() rlbkstmt\n"); + return OCI_ERROR; + } + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() rlbkstmt\n"); + report_error(); + return OCI_ERROR; + } + + (void) printf("FAILED: buf_write_lob() BLOB\n"); + return OCI_ERROR; + } + + /* commit the Xn if the BLOB's buffer was flushed successfully */ + (void) OCITransCommit(svchp, errhp, (ub4)0); + + /* disable BLOB locator from buffering */ + if (OCILobDisableBuffering(svchp, errhp, blob)) + { + (void) printf("FAILED: OCILobDisableBuffering() BLOB\n"); + return OCI_ERROR; + } + + /* close input files */ + (void) fclose(fp1); + (void) fclose(fp2); + + return OCI_SUCCESS; +} + +/*-------------------------------- read_lobs --------------------------------*/ + +/* read from LOBs into files */ +sb4 read_lobs (rowind, txtfile, binfile) +int rowind; +char *txtfile; +char *binfile; +{ + ub4 loblen = 0; + text *svptstmt = (text *)"SAVEPOINT cdemolbs_svpt"; + text *rlbkstmt = (text *)"ROLLBACK TO SAVEPOINT cdemolbs_svpt"; + + if (!rowind || (rowind > 2)) + { + (void) printf("ERROR: Invalid row indicator.\n"); + return -1; + } + + /* open destination files */ + fp1 = fopen((CONST char *)txtfile, (CONST char *) "w"); + fp2 = fopen((CONST char *)binfile, (CONST char *) "wb"); + if (!(fp1 && fp2)) + { + (void) printf("ERROR: Failed to open file(s).\n"); + return -1; + } + + /* reset file pointers to start of file */ + (void) fseek(fp1, 0, 0); + (void) fseek(fp2, 0, 0); + + /* fetch both the LOB locators from the table for reads */ + if (select_lobs(rowind)) + { + (void) printf("FAILED: select_lobs()\n"); + log_off(); + return OCI_ERROR; + } + + /* report CLOB length before buffered read begins */ + (void) OCILobGetLength(svchp, errhp, clob, &loblen); + (void) printf("\n\nBefore buffered read, CLOB length = %d\n\n", loblen); + + /* report BLOB length before buffered read begins */ + (void) OCILobGetLength(svchp, errhp, blob, &loblen); + (void) printf("\nBefore buffered read, BLOB length = %d\n\n", loblen); + + /* set savepoint for Xn before commencing buffered mode operations */ + if (OCIStmtPrepare(stmthp, errhp, svptstmt, (ub4) strlen((char *)svptstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() svptstmt\n"); + return OCI_ERROR; + } + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() svptstmt\n"); + report_error(); + return OCI_ERROR; + } + + /* enable the locators for buffering operations */ + if (OCILobEnableBuffering(svchp, errhp, clob)) + { + (void) printf("FAILED: OCILobEnableBuffering() CLOB\n"); + return OCI_ERROR; + } + if (OCILobEnableBuffering(svchp, errhp, blob)) + { + (void) printf("FAILED: OCILobEnableBuffering() BLOB\n"); + return OCI_ERROR; + } + + (void) printf("\n===> Reading CLOB into dst.txt in buffered mode...\n\n"); + + /* read the CLOB into buffer and write the contents to a text file */ + if (buf_read_lob(rowind, clob, fp1) == OCI_ERROR) + { + /* if buffered read operation failed, rollback Xn to savepoint & exit */ + if (OCIStmtPrepare(stmthp, errhp, rlbkstmt, (ub4) strlen((char *)rlbkstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() rlbkstmt\n"); + return OCI_ERROR; + } + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() rlbkstmt\n"); + report_error(); + return OCI_ERROR; + } + + (void) printf("FAILED: buf_read_lob() CLOB\n"); + return OCI_ERROR; + } + + (void) printf("\n===> Reading BLOB into dst.bin in buffered mode...\n\n"); + + /* read the BLOB into buffer and write the contents to a binary file */ + if (buf_read_lob(rowind, blob, fp2) > 0) + { + /* if buffered read operation failed, rollback Xn to savepoint & exit */ + if (OCIStmtPrepare(stmthp, errhp, rlbkstmt, (ub4) strlen((char *)rlbkstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() rlbkstmt\n"); + return OCI_ERROR; + } + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() rlbkstmt\n"); + report_error(); + return OCI_ERROR; + } + + (void) printf("FAILED: buf_read_clob()\n"); + return OCI_ERROR; + } + + /* commit the Xn if buffered reads went off successfully */ + (void) OCITransCommit(svchp, errhp, (ub4)0); + + /* disable locator for buffering */ + if (OCILobDisableBuffering(svchp, errhp, clob)) + { + (void) printf("FAILED: OCILobDisableBuffering() \n"); + return OCI_ERROR; + } + if (OCILobDisableBuffering(svchp, errhp, blob)) + { + (void) printf("FAILED: OCILobDisableBuffering() \n"); + return OCI_ERROR; + } + + /* close output files */ + (void) fclose(fp1); + (void) fclose(fp2); + + /* report output file sizes */ + printf("\n\nInput and Output file sizes should be the same.\n"); + printf("Please verify using OS commands\n"); + + return OCI_SUCCESS; +} + +/*----------------------------- Public functions ----------------------------*/ + +/*------------------------------- select_clob -------------------------------*/ + +/* select locator from the CLOB column */ +sb4 select_clob(rowind) +int rowind; +{ + int colc = rowind; + text *sqlstmt = (text *)"SELECT C1 FROM FOO WHERE C3 = :1 FOR UPDATE"; + /* we need the 'FOR UPDATE' clause since we need to write to the lobs */ + + /* prepare select statement */ + if (OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4) strlen((char *)sqlstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() sqlstmt\n"); + return OCI_ERROR; + } + /* associate variable colc with bind placeholder #1 in the SQL statement */ + if (OCIBindByPos(stmthp, &bndhp, errhp, (ub4) 1, + (dvoid *) &colc, (sb4) sizeof(colc), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIBindByPos()\n"); + return OCI_ERROR; + } + /* associate clob var with its define handle */ + if (OCIDefineByPos(stmthp, &defnp1, errhp, (ub4) 1, + (dvoid *) &clob, (sb4) -1, (ub2) SQLT_CLOB, + (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIDefineByPos() CLOB\n"); + return OCI_ERROR; + } + /* execute the select and fetch one row */ + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() sqlstmt\n"); + return OCI_ERROR; + } + return OCI_SUCCESS; +} + +/*------------------------------- select_blob -------------------------------*/ + +/* select locator from the BLOB column */ +sb4 select_blob(rowind) +int rowind; +{ + int colc = rowind; + text *sqlstmt = (text *)"SELECT C2 FROM FOO WHERE C3 = :1 FOR UPDATE"; + /* we need the 'FOR UPDATE' clause since we need to write to the lobs */ + + /* prepare select statement */ + if (OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4) strlen((char *)sqlstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() sqlstmt\n"); + return OCI_ERROR; + } + /* associate variable colc with bind placeholder #1 in the SQL statement */ + if (OCIBindByPos(stmthp, &bndhp, errhp, (ub4) 1, + (dvoid *) &colc, (sb4) sizeof(colc), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIBindByPos()\n"); + return OCI_ERROR; + } + /* associate blob var with its define handle */ + if (OCIDefineByPos(stmthp, &defnp2, errhp, (ub4) 1, + (dvoid *) &blob, (sb4) -1, (ub2) SQLT_BLOB, + (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIDefineByPos()\n"); + return OCI_ERROR; + } + /* execute the select and fetch one row */ + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() sqlstmt\n"); + return OCI_ERROR; + } + return OCI_SUCCESS; +} + +/*------------------------------- select_lobs -------------------------------*/ + +/* select lob locators from the CLOB, BLOB columns */ +sb4 select_lobs(rowind) +int rowind; +{ + int colc = rowind; + text *sqlstmt = (text *)"SELECT C1, C2 FROM FOO WHERE C3 = :1"; + /* we don't need the 'FOR UPDATE' clause since we are just reading the LOBs*/ + + /* prepare select statement */ + if (OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4) strlen((char *)sqlstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() sqlstmt\n"); + return OCI_ERROR; + } + /* associate variable colc with bind placeholder #1 in the SQL statement */ + if (OCIBindByPos(stmthp, &bndhp, errhp, (ub4) 1, + (dvoid *) &colc, (sb4) sizeof(colc), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIBindByPos()\n"); + return OCI_ERROR; + } + /* associate clob and blob vars with their define handles */ + if (OCIDefineByPos(stmthp, &defnp1, errhp, (ub4) 1, + (dvoid *) &clob, (sb4) -1, (ub2) SQLT_CLOB, + (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) OCI_DEFAULT) + || OCIDefineByPos(stmthp, &defnp2, errhp, (ub4) 2, + (dvoid *) &blob, (sb4) -1, (ub2) SQLT_BLOB, + (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIDefineByPos()\n"); + return OCI_ERROR; + } + /* execute the select and fetch one row */ + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() sqlstmt\n"); + return OCI_ERROR; + } + return OCI_SUCCESS; +} + +/*------------------------------- buf_write_lob -----------------------------*/ + +/* + * Read operating system files into local buffers and then write these local + * buffers to LOBs using buffering system. + */ +sb4 buf_write_lob(rowind, locator, fp, filelen) +int rowind; +OCILobLocator *locator; +FILE *fp; +ub4 filelen; +{ + ub4 offset = 1; + ub1 bufp[MAXBUFLEN]; + ub4 amtp, nbytes; + ub4 remainder = filelen; + + while (remainder > 0 && !feof(fp)) + { + amtp = nbytes = (remainder > MAXBUFLEN) ? MAXBUFLEN : remainder; + + if (fread((void *)bufp, (size_t)nbytes, (size_t)1, fp) != 1) + { + (void) printf("ERROR: read file.\n"); + return OCI_ERROR; + } + + if (OCILobWrite(svchp, errhp, locator, &amtp, offset, (dvoid *) bufp, + (ub4) nbytes, OCI_ONE_PIECE, (dvoid *)0, + (sb4 (*)(dvoid *, dvoid *, ub4 *, ub1 *)) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT) != OCI_SUCCESS) + { + (void) printf("ERROR: OCILobWrite()\n"); + report_error(); + return OCI_ERROR; + } + + (void) printf("Wrote %d of %d bytes starting at offset %d;; ", + amtp, filelen, offset); + + remainder -= nbytes; + offset += nbytes; + (void) printf("%d remaining\n\n", remainder); + } + + /* flush the buffers back to the server */ + (void) printf("\nFlush LOB's buffer to server\n"); + if (OCILobFlushBuffer(svchp, errhp, locator, OCI_LOB_BUFFER_NOFREE)) + { + (void) printf("FAILED: OCILobFlushBuffer() \n"); + return OCI_ERROR; + } + (void) printf("\n\nBuffered Write done\n\n"); + return OCI_SUCCESS; +} + +/*--------------------------------- buf_read_lob ----------------------------*/ + +/* + * Read LOBs using buffered mode into local buffers and writes them into + * operating system files. + */ +sb4 buf_read_lob(rowind, locator, fp) +int rowind; +OCILobLocator *locator; +FILE *fp; +{ + ub4 offset = 1; + ub1 bufp[MAXBUFLEN]; + ub4 amtp = 0; + ub4 nbytes = 0; + ub4 filelen = 0; + ub4 total = 0; + + /* + * read from CLOB and write to text file (in the process, populating upto + * 16 pages in the buffering subsystem). + */ + + /* set amount to be read per iteration */ + amtp = nbytes = MAXBUFLEN; + + while (amtp) + { + if (OCILobRead(svchp, errhp, locator, &amtp, (ub4) offset, (dvoid *) bufp, + (ub4) nbytes, (dvoid *)0, + (sb4 (*)(dvoid *, CONST dvoid *, ub4, ub1)) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT)) + { + (void) printf("FAILED: OCILobRead() \n"); + report_error(); + return OCI_ERROR; + } + + if (amtp > 0) + { + total += amtp; + (void) printf("Read %d bytes starting at offset %d; Total %d\n\n", + amtp, offset, total); + (void) fwrite((void *)bufp, (size_t)amtp, (size_t)1, fp); + offset += nbytes; + } + else + break; + } + printf("\n\nBuffered Read Done\n\n"); + return OCI_SUCCESS; +} + +/*--------------------------------- drop_table ------------------------------*/ + +/* Drop table FOO before logging off from the server */ +void drop_table() +{ + text *dropstmt = (text *) "DROP TABLE FOO"; + + /* prepare drop statement */ + if (OCIStmtPrepare(stmthp, errhp, dropstmt, (ub4) strlen((char *) dropstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() dropstmt\n"); + return; + } + /* execute drop statement */ + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) 0, (OCISnapshot *) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() dropstmt\n"); + return; + } + return; +} + +/*-------------------------------- report_error -----------------------------*/ + +/* retrieve error message and print it out */ +void report_error() +{ + text msgbuf[512]; + sb4 errcode = 0; + + (void) OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + (void) printf("ERROR CODE = %d\n", errcode); + (void) printf("%.*s\n", 512, msgbuf); + return; +} + +/*-------------------------------- file_length ------------------------------*/ + +/* get the length of the input file */ +ub4 file_length(fp) +FILE *fp; +{ + fseek(fp, 0, SEEK_END); + return (ub4) (ftell(fp)); +} + +/* end of file cdemolbs.c */ diff --git a/cdemoplb.c b/cdemoplb.c new file mode 100644 index 0000000..33f2b72 --- /dev/null +++ b/cdemoplb.c @@ -0,0 +1,807 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemoplb.c 14-jul-99.13:14:39 mjaeger Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1998, 1999, Oracle Corporation. All rights reserved. +*/ + +/* + + NAME + cdemoplb.c - C Demo program - using LOBs in partitioned tables. + + DESCRIPTION + This program demonstrates using LOBs in partitioned tables. + A partitioned table is created with one BLOB and two CLOB columns + and LOB storage clause is specified to store lobs in different + tablespaces based on value of column A and if the LOB in question + is column B, C or D. + + Two data files, a text file and a binary file are expected as + arguments. + + The program creates six log files: + binfile1.log + txtfile2.log + txtfile3.log + binfile11.log + txtfile12.log + txtfile13.log + + MODIFIED (MM/DD/YY) + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 07/22/98 - Creation + +*/ + +#include +#include + +static sb4 init_handles(/*_ void _*/); +static sb4 log_on(/*_ void _*/); +static sb4 create_table(/*_ void _*/); +static sb4 select_locator(/*_ int rowind _*/); +static ub4 file_length(/*_ FILE *fp _*/); +static sb4 test_file_to_lob(/*_ int rowind, char *tfname, char *bfname _*/); +static void test_lob_to_file(/*_ int rowind _*/); +static void stream_write_lob(/*_ int rowind, OCILobLocator *lobl, + FILE *fp, ub4 filelen _*/); +static void stream_read_lob(/*_ int rowind, OCILobLocator *lobl, FILE *fp _*/); +static sb4 cbk_fill_buffer(/*_ dvoid *ctxp, dvoid *bufxp, ub4 *lenp, + ub1 *piece _*/); +static sb4 cbk_write_buffer(/*_ dvoid *ctxp, CONST dvoid *bufxp, ub4 lenp, + ub1 piece _*/); + +static void logout(/*_ void _*/); +static void report_error(/*_ void _*/); + +int main(/*_ int argc, char *argv[] _*/); + +#define TRUE 1 +#define FALSE 0 + +#define MAXBUFLEN 5000 + +static OCIEnv *envhp; +static OCIServer *srvhp; +static OCISvcCtx *svchp; +static OCIError *errhp; +static OCISession *authp; +static OCIStmt *stmthp; +static OCILobLocator *lob; +static OCIDefine *defnp1 = (OCIDefine *) 0, *defnp2 = (OCIDefine *) 0; +static OCIBind *bndhp = (OCIBind *) 0; + +static FILE *fp1; + +static ub4 filelen = 0; + +static boolean istxtfile; + +/*------------------------end of Inclusions-----------------------------*/ + +int main(argc, argv) +int argc; +char *argv[]; +{ + int rowind; + + if (argc != 3) + { + (void) printf("Usage: %s txtfilename binfilename\n", argv[0]); + return 0; + } + + if (init_handles()) + { + (void) printf("FAILED: init_handles()\n"); + return OCI_ERROR; + } + + if (log_on()) + { + (void) printf("FAILED: log_on()\n"); + return OCI_ERROR; + } + + if (create_table()) + { + (void) printf("FAILED: create_table()\n"); + logout(); + return OCI_ERROR; + } + + /************************************************ + ** First three inserts will go into partition P1 + ** column A = 1, column B into tablespace tbs_2 + ** column A = 2, column C into tablespace tbs_4 + ** column A = 3, column D into tablesapce tbs_2 + */ + for (rowind = 1; rowind <= 3; rowind++) + { + if (insert_record(rowind)) + { + (void) printf("FAILED: insert_record()\n"); + logout(); + return OCI_ERROR; + } + + if (select_locator(rowind)) + { + (void) printf("FAILED: select_locator()\n"); + logout(); + return OCI_ERROR; + } + + if (test_file_to_lob(rowind, argv[1], argv[2])) + { + (void) printf("FAILED: load files to lobs\n"); + logout(); + return OCI_ERROR; + } + + test_lob_to_file(rowind); + } + + /************************************************ + ** First three inserts will go into partition P1 + ** column A = 11, column B into tablespace tbs_3 + ** column A = 12, column C into tablespace tbs_3 + ** column A = 13, column D into tablesapce tbs_3 + */ + for (rowind = 11; rowind <= 13; rowind++) + { + if (insert_record(rowind)) + { + (void) printf("FAILED: insert_record()\n"); + logout(); + return OCI_ERROR; + } + + if (select_locator(rowind)) + { + (void) printf("FAILED: select_locator()\n"); + logout(); + return OCI_ERROR; + } + + if (test_file_to_lob(rowind, argv[1], argv[2])) + { + (void) printf("FAILED: load files to lobs\n"); + logout(); + return OCI_ERROR; + } + + test_lob_to_file(rowind); + } + + logout(); + + return OCI_SUCCESS; +} + + + + +/* ----------------------------------------------------------------- */ +/* initialize environment, allocate handles, etc. */ +/* ----------------------------------------------------------------- */ + +sb4 init_handles() +{ + if (OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 )) + { + (void) printf("FAILED: OCIInitialize()\n"); + return OCI_ERROR; + } + + /* initialize environment handle */ + if (OCIEnvInit((OCIEnv **) &envhp, (ub4) OCI_DEFAULT, + (size_t) 0, (dvoid **) 0 )) + { + (void) printf("FAILED: OCIEnvInit()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &stmthp, + (ub4) OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIDescriptorAlloc((dvoid *) envhp, (dvoid **) &lob, + (ub4)OCI_DTYPE_LOB, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIDescriptorAlloc()\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + + +/* ----------------------------------------------------------------- */ +/* attach to the server and log on as SCOTT/TIGER */ +/* ----------------------------------------------------------------- */ + +sb4 log_on() +{ + text *uid = (text *)"CDEMOPLB"; + text *pwd = (text *)"CDEMOPLB"; + text *cstring = (text *) ""; + + /* attach to the server */ + if (OCIServerAttach(srvhp, errhp, (text *) cstring, + (sb4) strlen((char *)cstring), (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIServerAttach()\n"); + return OCI_ERROR; + } + + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) uid, (ub4) strlen((char *)uid), + (ub4) OCI_ATTR_USERNAME, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) pwd, (ub4) strlen((char *)pwd), + (ub4) OCI_ATTR_PASSWORD, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + /* set the server attribute in the service context */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, (ub4) OCI_ATTR_SERVER, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + /* log on */ + if (OCISessionBegin(svchp, errhp, authp, (ub4) OCI_CRED_RDBMS, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCISessionBegin()\n"); + return OCI_ERROR; + } + + /* set the session attribute in the service context */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, (dvoid *) authp, + (ub4) 0, (ub4) OCI_ATTR_SESSION, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; + +} + + +/* ----------------------------------------------------------------- */ +/* Create table FOO with CLOB, BLOB columns and insert one row. */ +/* Both columns are empty lobs, not null lobs. */ +/* ----------------------------------------------------------------- */ + +sb4 create_table() +{ + int colc; + + text *crtstmt = (text *) + "CREATE TABLE PT1 (A NUMBER, B BLOB, C CLOB, D CLOB) " + "PARTITION BY RANGE (A)" + " (PARTITION P1 VALUES LESS THAN (10) TABLESPACE TBS_1" + " LOB (B,D) STORE AS (TABLESPACE TBS_2)," + " PARTITION P2 VALUES LESS THAN (MAXVALUE)" + " LOB (B,C,D) STORE AS (TABLESPACE TBS_3)" + " ) TABLESPACE TBS_4"; + + if (OCIStmtPrepare(stmthp, errhp, crtstmt, (ub4) strlen((char *) crtstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() crtstmt\n"); + return OCI_ERROR; + } + + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) 0, (OCISnapshot *) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() crtstmt\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/* ----------------------------------------------------------------- */ +/* Insert record into table PT1 with empty_blob() and empty_clob() */ +/* as values for columns b, c or d */ +/* ----------------------------------------------------------------- */ + +sb4 insert_record(int rowind) +{ + int colc; + + text insstmt[100]; + + switch (rowind) + { + case 1: + case 11: + sprintf(insstmt, "INSERT INTO PT1 (A, B) VALUES (:1, EMPTY_BLOB())"); + break; + case 2: + case 12: + sprintf(insstmt, "INSERT INTO PT1 (A, C) VALUES (:1, EMPTY_CLOB())"); + break; + case 3: + case 13: + sprintf(insstmt, "INSERT INTO PT1 (A, D) VALUES (:1, EMPTY_CLOB())"); + break; + default: + (void) printf("ERROR: Invalid row indicator.\n"); + break; + } + + if (OCIStmtPrepare(stmthp, errhp, insstmt, (ub4) strlen((char *) insstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() insstmt\n"); + return OCI_ERROR; + } + + if (OCIBindByPos(stmthp, &bndhp, errhp, (ub4) 1, + (dvoid *) &colc, (sb4) sizeof(colc), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIBindByPos()\n"); + return OCI_ERROR; + } + + colc = rowind; + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) 0, (OCISnapshot *) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() insstmt\n"); + return OCI_ERROR; + } + + (void) OCITransCommit(svchp, errhp, (ub4)0); + + return OCI_SUCCESS; +} + +/*---------------------------------------------------------------------*/ +/* Select lob locators from the CLOB, BLOB columns. */ +/* We need the 'FOR UPDATE' clause since we need to write to the lobs. */ +/*---------------------------------------------------------------------*/ + +sb4 select_locator(int rowind) +{ + int colc = rowind; + text sqlstmt[100]; + + switch(rowind) + { + case 1: + case 11: + sprintf(sqlstmt, "SELECT B FROM PT1 WHERE A = :1 FOR UPDATE"); + break; + case 2: + case 12: + sprintf(sqlstmt, "SELECT C FROM PT1 WHERE A = :1 FOR UPDATE"); + break; + case 3: + case 13: + sprintf(sqlstmt, "SELECT D FROM PT1 WHERE A = :1 FOR UPDATE"); + break; + default: + (void) printf("ERROR: Invalid row indicator.\n"); + break; + } + + if (OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4) strlen((char *)sqlstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtPrepare() sqlstmt\n"); + return OCI_ERROR; + } + + if (OCIBindByPos(stmthp, &bndhp, errhp, (ub4) 1, + (dvoid *) &colc, (sb4) sizeof(colc), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIBindByPos()\n"); + return OCI_ERROR; + } + + switch (rowind) + { + case 1: + case 11: + if (OCIDefineByPos(stmthp, &defnp2, errhp, (ub4) 1, + (dvoid *) &lob, (sb4) -1, (ub2) SQLT_BLOB, + (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIDefineByPos() - BLOB\n"); + return OCI_ERROR; + } + break; + case 2: + case 3: + case 12: + case 13: + if (OCIDefineByPos(stmthp, &defnp1, errhp, (ub4) 1, + (dvoid *) &lob, (sb4) -1, (ub2) SQLT_CLOB, + (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIDefineByPos() - CLOB\n"); + return OCI_ERROR; + } + break; + default: + (void) printf("ERROR: Invalid row indicator.\n"); + break; + } + + /* execute the select and fetch one row */ + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIStmtExecute() sqlstmt\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + + +/* ----------------------------------------------------------------- */ +/* Read operating system files into local buffers and then write the */ +/* buffers to lobs. */ +/* ----------------------------------------------------------------- */ + +sb4 test_file_to_lob(int rowind, char *txtfile, char *binfile) +{ + (void) printf("\n===> Testing loading files into lobs .....\n\n"); + + if (rowind == 1 || rowind == 11) + { + fp1 = fopen((const char *)binfile, (const char *) "rb"); + } + else + { + fp1 = fopen((const char *)txtfile, (const char *) "r"); + } + + if (!fp1) + { + (void) printf("ERROR: Failed to open file(s).\n"); + return -1; + } + + filelen = file_length(fp1); + + stream_write_lob(rowind, lob, fp1, filelen); + + (void) fclose(fp1); + + return 0; +} + + +/* ----------------------------------------------------------------- */ +/* get the length of the input file. */ +/* ----------------------------------------------------------------- */ + +ub4 file_length(FILE *fp) +{ + fseek(fp, 0, SEEK_END); + return (ub4) (ftell(fp)); +} + + +/* ----------------------------------------------------------------- */ +/* Read operating system files into local buffers and then write the */ +/* buffers to lobs using stream mode. */ +/* ----------------------------------------------------------------- */ + +void stream_write_lob(int rowind, OCILobLocator *lobl, FILE *fp, ub4 filelen) +{ + ub4 offset = 1; + ub4 loblen = 0; + ub1 bufp[MAXBUFLEN]; + ub4 amtp = filelen; + ub1 piece; + sword retval; + int readval; + ub4 len = 0; + ub4 nbytes; + ub4 remainder = filelen; + + (void) printf("--> To do streamed write lob, amount = %d\n", filelen); + + (void) OCILobGetLength(svchp, errhp, lobl, &loblen); + (void) printf("Before stream write, LOB length = %d\n\n", loblen); + + (void) fseek(fp, 0, 0); + + if (filelen > MAXBUFLEN) + nbytes = MAXBUFLEN; + else + nbytes = filelen; + + if (fread((void *)bufp, (size_t)nbytes, 1, fp) != 1) + { + (void) printf("ERROR: read file.\n"); + return; + } + + remainder -= nbytes; + + if (remainder == 0) /* exactly one piece in the file */ + { + (void) printf("Only one piece, no need for stream write.\n"); + if (retval = OCILobWrite(svchp, errhp, lobl, &amtp, offset, (dvoid *) bufp, + (ub4) nbytes, OCI_ONE_PIECE, (dvoid *)0, + (sb4 (*)(dvoid *, dvoid *, ub4 *, ub1 *)) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT) != OCI_SUCCESS) + { + (void) printf("ERROR: OCILobWrite(), retval = %d\n", retval); + return; + } + } + else /* more than one piece */ + { + if (OCILobWrite(svchp, errhp, lobl, &amtp, offset, (dvoid *) bufp, + (ub4) MAXBUFLEN, OCI_FIRST_PIECE, (dvoid *)0, + (sb4 (*)(dvoid *, dvoid *, ub4 *, ub1 *)) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT) != OCI_NEED_DATA) + { + (void) printf("ERROR: OCILobWrite().\n"); + return; + } + + piece = OCI_NEXT_PIECE; + + do + { + if (remainder > MAXBUFLEN) + nbytes = MAXBUFLEN; + else + { + nbytes = remainder; + piece = OCI_LAST_PIECE; + } + + if (fread((void *)bufp, (size_t)nbytes, 1, fp) != 1) + { + (void) printf("ERROR: read file.\n"); + piece = OCI_LAST_PIECE; + } + + retval = OCILobWrite(svchp, errhp, lobl, &amtp, offset, (dvoid *) bufp, + (ub4) nbytes, piece, (dvoid *)0, + (sb4 (*)(dvoid *, dvoid *, ub4 *, ub1 *)) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT); + remainder -= nbytes; + + } while (retval == OCI_NEED_DATA && !feof(fp)); + } + + if (retval != OCI_SUCCESS) + { + (void) printf("Error: stream writing LOB.\n"); + return; + } + + (void) OCILobGetLength(svchp, errhp, lobl, &loblen); + (void) printf("After stream write, LOB length = %d\n\n", loblen); + + return; +} + + + +/* ----------------------------------------------------------------- */ +/* Read lobs into local buffers and then write them to operating */ +/* system files. */ +/* ----------------------------------------------------------------- */ + +void test_lob_to_file(int rowind) +{ + ub4 offset = 1; + ub4 loblen = 0; + ub1 bufp[MAXBUFLEN]; + ub4 amtp = MAXBUFLEN; + text filename[20]; + + if (rowind == 1 || rowind == 11) + { + (void) sprintf((char *) filename, (char *)"binfile%d.log", rowind); + fp1 = fopen((char *)filename, (const char *) "wb"); + } + else + { + (void) sprintf((char *) filename, (char *)"txtfile%d.log", rowind); + fp1 = fopen((char *)filename, (const char *) "w"); + } + + (void) printf("\n===> Testing writing lobs to files .....\n\n"); + + if (!fp1) + { + (void) printf("ERROR: Failed to open file(s).\n"); + return; + } + + stream_read_lob(rowind, lob, fp1); + + (void) fclose(fp1); + + return; +} + + +/* ----------------------------------------------------------------- */ +/* Read lobs using stream mode into local buffers and then write */ +/* them to operating system files. */ +/* ----------------------------------------------------------------- */ + +void stream_read_lob(int rowind, OCILobLocator *lobl, FILE *fp) +{ + ub4 offset = 1; + ub4 loblen = 0; + ub1 bufp[MAXBUFLEN]; + ub4 amtp = 0; + sword retval; + ub4 piece = 0; + ub4 remainder; /* the number of bytes for the last piece */ + + (void) OCILobGetLength(svchp, errhp, lobl, &loblen); + amtp = loblen; + + (void) printf("--> To stream read LOB, loblen = %d.\n", loblen); + + memset(bufp, '\0', MAXBUFLEN); + + retval = OCILobRead(svchp, errhp, lobl, &amtp, offset, (dvoid *) bufp, + (loblen < MAXBUFLEN ? loblen : MAXBUFLEN), (dvoid *)0, + (sb4 (*)(dvoid *, const dvoid *, ub4, ub1)) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT); + + switch (retval) + { + case OCI_SUCCESS: /* only one piece */ + (void) printf("stream read %d th piece\n", ++piece); + (void) fwrite((void *)bufp, (size_t)loblen, 1, fp); + break; + case OCI_ERROR: + report_error(); + break; + case OCI_NEED_DATA: /* there are 2 or more pieces */ + + remainder = loblen; + + /* a full buffer to write */ + (void) fwrite((void *)bufp, MAXBUFLEN, 1, fp); + + do + { + memset(bufp, '\0', MAXBUFLEN); + amtp = 0; + + remainder -= MAXBUFLEN; + + retval = OCILobRead(svchp, errhp, lobl, &amtp, offset, (dvoid *) bufp, + (ub4) MAXBUFLEN, (dvoid *)0, + (sb4 (*)(dvoid *, const dvoid *, ub4, ub1)) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT); + + /* the amount read returned is undefined for FIRST, NEXT pieces */ + (void) printf("stream read %d th piece, amtp = %d\n", ++piece, amtp); + + if (remainder < MAXBUFLEN) /* last piece not a full buffer piece */ + (void) fwrite((void *)bufp, (size_t)remainder, 1, fp); + else + (void) fwrite((void *)bufp, MAXBUFLEN, 1, fp); + + } while (retval == OCI_NEED_DATA); + break; + default: + (void) printf("Unexpected ERROR: OCILobRead() LOB.\n"); + break; + } + + return; +} + + +/*-------------------------------------------------------------------*/ +/* Logoff and disconnect from the server. Free handles. */ +/*-------------------------------------------------------------------*/ + +void logout() +{ + + (void) OCISessionEnd(svchp, errhp, authp, (ub4) 0); + (void) OCIServerDetach(srvhp, errhp, (ub4) OCI_DEFAULT); + + (void) printf("Logged off and detached from server.\n"); + + (void) OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER); + (void) OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX); + (void) OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR); + (void) OCIHandleFree((dvoid *) authp, (ub4) OCI_HTYPE_SESSION); + (void) OCIDescriptorFree((dvoid *) lob, (ub4) OCI_DTYPE_LOB); + (void) OCIHandleFree((dvoid *) stmthp, (ub4) OCI_HTYPE_STMT); + + (void) printf("All handles freed\n"); + return; +} + + +/* ----------------------------------------------------------------- */ +/* retrieve error message and print it out. */ +/* ----------------------------------------------------------------- */ +void report_error() +{ + text msgbuf[512]; + sb4 errcode = 0; + + (void) OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + (void) printf("ERROR CODE = %d\n", errcode); + (void) printf("%.*s\n", 512, msgbuf); + return; +} + + +/* end of file cdemolb2.c */ + diff --git a/cdemoqc.c b/cdemoqc.c new file mode 100644 index 0000000..4a278e8 --- /dev/null +++ b/cdemoqc.c @@ -0,0 +1,544 @@ +/* Copyright (c) 2007, 2008, Oracle and/or its affiliates. + All rights reserved. */ + +/* + NAME + cdemoqc - Basic OCI Query Cache(result cache) functionality + + DESCRIPTION + This program uses multiple sessions to demonstrate the working of Query + cache. To use the query cache feature (and hence this program), database + should have been brought up with client side result cache enabled. To bring + the database with result cache enabled, add the following lines in + initialization parameter file, + client_result_cache_size= + client_result_cache_lag= + compatible=11.0.0.0.0 + and bring up the database. + + After this, when the result cache hint is specified, fetched data will be + cached locally. When the same query is executed again, data will be fetched + from this local client cache rather than fetching the data from the server. + Hence there will be substantial improvement in the performance if this + feature is used on the transactions where the same query is executed + multiple times on the tables which will be rarely updated. + + When the contents of the table is changed, the next fetch statement will + fetch the data from the server and also the local cache will be updated. + This updated cache will be used thereafter. + + NOTE: + 1.To check the performance improvement with this feature measure the time + taken by this program using your operating specific commands. For example + in Linux, "time cdemoqc" will give you the time taken by this program for + completion. After this repeat the same program without result_cache hint + and measure the time taken. You should able to see some difference in these + times and this difference will be remarkable when the server is running + remotely. + 2.print_stats() will query the stats table. This function can be used to + check the cache usage statistics. The call to this funtion has been + commented out. If you want to see this statistics info please uncomment the + corresponding lines in main(). + For getting this statistics, user needs to login as SYSDBA. Hence if you + uncomment this call, the program will prompt for sys user password. scanf() + has been used for fetching the password from user and you may want to + replace it with your platform specific function to hide the echoing of + password. + + MODIFIED (MM/DD/YY) + dgopal 12/19/07 - Updated + dgopal 05/08/07 - Created + +*/ + +#if defined(WIN32COMMON) || defined(WIN32) || defined(_WIN32) +#include +#define sleep(x) Sleep(1000*(x)) +#endif + +# include + +# include +# include +# include + +#if !defined(WIN32COMMON) && !defined(WIN32) && !defined(_WIN32) +#include +#endif + +#define EMPLOYEE 0 +#define HR 1 + +/* Function prototypes */ +static void query_tab(ub4 idx); +static void upd_table(ub4 idx); +static void print_stats(); +static void dbLogon(); +static void dbLogoff(); +static void Checkerr(OCIError *errhp, sword status, text *msg); + +int main(); + +static sword status = 0; +static OCISvcCtx *svchp[2]; +static OCIError *errhp; +static OCIEnv *envhp; +static OCIAuthInfo *authhp; + +/* Queries with result cache hints */ +static text *cache_query= +(text *)"SELECT /*+ result_cache */ empno, ename, sal FROM qctable"; + +static text *upd_stmt= +(text *)"UPDATE qctable SET sal=sal+50 WHERE empno=1"; + +/* - main -------------------------------------------------------------------*/ +int main () +{ + printf ("Query cache is enabled by using result_cache hints\n\n"); + + /* Logging on to multiple sessions */ + dbLogon (); + + /* + Querying same table from different sessions. For the same queries result + cache will be shared across sessions. + */ + printf ("Employee: Execute will fetch rows from server\n"); + query_tab(EMPLOYEE); + printf ("Employee: Execute will fetch rows from local cache\n"); + query_tab(EMPLOYEE); + + printf ("HR: Execute will cause a roundtrip during first execute, but the " + "same result \n\tset created in Employee Session will be shared " + "thereafter\n"); + query_tab(HR); + printf ("HR: Execute will fetch rows from local cache\n"); + query_tab(HR); + + /* + Updating the table. This will invalidate the result caches of all the + sessions involving this table data. + */ + printf ("\nHR: Updating the table\n\n"); + upd_table(HR); + + printf ("Employee: Execute will fetch rows from server and hence the local " + "result set \n\twill be updated\n"); + query_tab(EMPLOYEE); + printf ("HR: Execute will fetch rows from updated local cache\n"); + query_tab(HR); + printf ("Employee: Execute will fetch rows from local cache\n"); + query_tab(EMPLOYEE); + + /* + Stats table will get updated only once in few seconds. So data should be + fetched from the stats table after sleeping for few seconds. + */ + +/* Below lines should be uncommented if you want to see the cache usage stats */ + /* + printf ("\nSleeping for few seconds to let the stat table to get " + "updated\n\n"); + + sleep (60); + print_stats(); + */ + + dbLogoff (); + return 0; +} + +/* - Logon to the DB in two sessions ----------------------------------------*/ +static void dbLogon () +{ + int idx; + ub4 cachesize=10; + OraText *connStr = (text *)""; + OraText *username = (text *)"ocitest"; + OraText *password = (text *)"ocitest"; + + OCIEnvCreate ((OCIEnv **)&envhp, (ub4)OCI_DEFAULT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t))0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *))0, (size_t)0, (dvoid **)0); + + OCIHandleAlloc ((dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + + OCIHandleAlloc ((dvoid *)envhp, (dvoid **)&authhp, + (ub4)OCI_HTYPE_AUTHINFO, (size_t)0, (dvoid **)0); + + /* Connecting to session 1 */ + idx=0; + + OCIAttrSet ((dvoid *)authhp, (ub4)OCI_HTYPE_AUTHINFO, (dvoid *)username, + (ub4)strlen((char *)username), (ub4)OCI_ATTR_USERNAME, + (OCIError *)errhp); + + OCIAttrSet ((dvoid *)authhp, (ub4)OCI_HTYPE_AUTHINFO, (dvoid *)password, + (ub4)strlen((char *)password), (ub4)OCI_ATTR_PASSWORD, + (OCIError *)errhp); + + Checkerr (errhp, + OCISessionGet ((OCIEnv *)envhp, (OCIError *)errhp, + (OCISvcCtx **)&svchp[idx], (OCIAuthInfo *)authhp, (OraText *)connStr, + (ub4)strlen((char *)connStr), (OraText *)NULL, (ub4)0, (OraText **)0, + (ub4 *)0, (boolean *)0,(ub4)OCI_DEFAULT), + (oratext *)"OCISessionGet"); + + printf ("Connected to Employee Session\n"); + + OCIAttrSet((dvoid *)svchp[idx], OCI_HTYPE_SVCCTX, (dvoid *)&cachesize, + (ub4)0,OCI_ATTR_STMTCACHESIZE,errhp); + + /* Connecting to session 2 */ + idx=1; + + OCIAttrSet ((dvoid *)authhp, (ub4)OCI_HTYPE_AUTHINFO, (dvoid *)username, + (ub4)strlen((char *)username), (ub4)OCI_ATTR_USERNAME, + (OCIError *)errhp); + + OCIAttrSet ((dvoid *)authhp, (ub4)OCI_HTYPE_AUTHINFO, (dvoid *)password, + (ub4)strlen((char *)password), (ub4)OCI_ATTR_PASSWORD, + (OCIError *)errhp); + + Checkerr (errhp, + OCISessionGet ((OCIEnv *)envhp, (OCIError *)errhp, + (OCISvcCtx **)&svchp[idx], (OCIAuthInfo *)authhp, (OraText *)connStr, + (ub4)strlen((char *)connStr), (OraText *)NULL, (ub4)0, (OraText **)0, + (ub4 *)0, (boolean *)0,(ub4)OCI_DEFAULT), + (oratext *)"OCISessionGet"); + + printf ("Connected to HR Session\n\n"); + + OCIAttrSet((dvoid *)svchp[idx], OCI_HTYPE_SVCCTX, (dvoid *)&cachesize, + (ub4)0,OCI_ATTR_STMTCACHESIZE,errhp); +} + +/* - Execute SQL query and prints the data ----------------------------------*/ +static void query_tab (ub4 idx) +{ + OCIStmt *stmthp = (OCIStmt *)0; + OCIDefine *def1hp = (OCIDefine *)0; + OCIDefine *def2hp = (OCIDefine *)0; + OCIDefine *def3hp = (OCIDefine *)0; + ub4 empno; + text ename[100]; + ub4 sal; + sb4 empnoSz = sizeof (empno); + sb4 enameSz = sizeof (ename); + sb4 salSz = sizeof (sal); + ub2 datelen=0; + ub4 prefetch = 0; + + Checkerr (errhp, + OCIStmtPrepare2 ((OCISvcCtx *)svchp[idx],(OCIStmt **)&stmthp, + (OCIError *)errhp, (text *)cache_query, (ub4)strlen((char *)cache_query), + (oratext *)NULL, (ub4) 0, (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT), + (oratext *)"OCIStmtPrepare"); + + /* Setting the prefetch count = 0 */ + Checkerr(errhp, + OCIAttrSet((OCIStmt *) stmthp, OCI_HTYPE_STMT, (dvoid *)&prefetch, + sizeof(prefetch), OCI_ATTR_PREFETCH_ROWS, (OCIError *)errhp), + (oratext *) "OCIAttrSet-prefetch"); + + Checkerr (errhp, + OCIDefineByPos ((OCIStmt *)stmthp, (OCIDefine **)&def1hp, + (OCIError *)errhp, (ub4)1, (dvoid *)&(empno), (sb4)empnoSz, (ub2)SQLT_INT, + (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT), + (oratext *)"OCIDefByPos"); + + Checkerr (errhp, + OCIDefineByPos ((OCIStmt *)stmthp, (OCIDefine **)&def2hp, + (OCIError *)errhp, (ub4)2, (dvoid *)&(ename), (sb4)enameSz, (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT), + (oratext *)"OCIDefByPos2"); + + Checkerr (errhp, + OCIDefineByPos ((OCIStmt *)stmthp, (OCIDefine **)&def3hp, + (OCIError *)errhp, (ub4)3, (dvoid *)&(sal), (sb4)salSz, (ub2)SQLT_INT, + (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT), + (oratext *)"OCIDefByPos3"); + + if ((status = OCIStmtExecute ((OCISvcCtx *)svchp[idx], (OCIStmt *)stmthp, + (OCIError *)errhp, (ub4)0, (ub4)0, (OCISnapshot *)0, + (OCISnapshot *)0, (ub4)OCI_DEFAULT)) != OCI_SUCCESS ) + { + printf ("OCIStmtExecute for SELECT - Fail\n" ); + Checkerr (errhp, status,(oratext *)"Stmt Execute"); + } + else + { + do + { + status = OCIStmtFetch2((OCIStmt *)stmthp, (OCIError *)errhp, (ub4)1, + (ub2)OCI_FETCH_NEXT, (sb4)0, (ub4)OCI_DEFAULT); + + if (status == OCI_ERROR || status == OCI_INVALID_HANDLE) + { + Checkerr(errhp, status, (oratext *)"OCIStmtFetch2"); + break; + } + else if (status != OCI_NO_DATA) + { + /* + printf("EMPNO is %d, ENAME is %s, SAL is %d\n", empno, ename, sal); + */ + } + }while(status != OCI_NO_DATA); + } + + Checkerr (errhp, + OCIStmtRelease ((OCIStmt *)stmthp, (OCIError *)errhp,(dvoid *)NULL, 0, + OCI_DEFAULT), (oratext *)"StmtRelease"); +} + +/* - Execute DML statement --------------------------------------------------*/ +void upd_table(ub4 idx) +{ + OCIStmt *stmthp = (OCIStmt *)0; + + Checkerr (errhp, + OCIHandleAlloc ((dvoid *)envhp, (dvoid **)&stmthp, (ub4)OCI_HTYPE_STMT, + (size_t)0, (dvoid **)0), (oratext *)"OCIHandleAlloc"); + + Checkerr (errhp, + OCIStmtPrepare ((OCIStmt *)stmthp, (OCIError *)errhp, (text *)upd_stmt, + (ub4)strlen((char *)upd_stmt), (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT), + (oratext *)"OCIStmtPrepare"); + + if (status = OCIStmtExecute ((OCISvcCtx *)svchp[idx], (OCIStmt *)stmthp, + (OCIError *)errhp, (ub4)1, (ub4)0, (OCISnapshot *)0, + (OCISnapshot *)0, (ub4)OCI_COMMIT_ON_SUCCESS)) + { + printf ("OCIStmtExecute update - Fail\n"); + Checkerr (errhp, status,(oratext *)"Stmt Execute Update"); + } + + Checkerr (errhp, + OCIHandleFree ((dvoid *)stmthp, (ub4)OCI_HTYPE_STMT), + (oratext *)"OCIHandleFree"); +} + +/* - Fetches and prints result cache statistics information -----------------*/ +void print_stats() +{ + OCISvcCtx *syssvchp = NULL; + OCIServer *srvhp = NULL; + OCIStmt *stmthp = (OCIStmt *)0; + OCISession *sysauthhp = (OCISession *)0; + OCIDefine *def1hp = (OCIDefine *)0; + OCIDefine *def2hp = (OCIDefine *)0; + OCIDefine *def3hp = (OCIDefine *)0; + OCIDefine *def4hp = (OCIDefine *)0; + ub4 statid; + text name[128]; + ub4 value; + ub4 cacheid; + sb4 statidSz = sizeof(statid); + sb4 nameSz = sizeof (name); + sb4 valueSz= sizeof(value); + sb4 cacheidSz = sizeof(cacheid); + ub4 prefetch = 0; + OraText *connStr = (text *)""; + OraText *sysuser = (text *)"sys"; + OraText syspass[128]; + text *StatQuery= + (text *)"SELECT c1.stat_id, c1.name, c1.value, c1.cache_id \ + FROM client_result_cache_stats$ c1 \ + order by c1.cache_id, c1.stat_id"; + + printf ("Please enter password for sys user to continue:\n"); + scanf ("%s", (char *)syspass); + + OCIHandleAlloc ((dvoid *)envhp, (dvoid **)&srvhp, (ub4)OCI_HTYPE_SERVER, + (size_t)0, (dvoid **)0); + + OCIHandleAlloc ((dvoid *)envhp, (dvoid **)&syssvchp, (ub4)OCI_HTYPE_SVCCTX, + (size_t)0, (dvoid **)0); + + Checkerr (errhp, + OCIServerAttach (srvhp, errhp, (text *)connStr, + (sb4)strlen((char *)connStr), 0), (oratext *)"OCIServerAttach"); + + OCIAttrSet ((dvoid *) syssvchp, OCI_HTYPE_SVCCTX, (dvoid *)srvhp, (ub4) 0, + OCI_ATTR_SERVER, (OCIError *) errhp); + + OCIHandleAlloc ((dvoid *)envhp, (dvoid **)&sysauthhp, + (ub4)OCI_HTYPE_SESSION, (size_t)0, (dvoid **)0); + + OCIAttrSet ((dvoid *)sysauthhp, (ub4)OCI_HTYPE_SESSION, (dvoid *)sysuser, + (ub4)strlen((char *)sysuser), (ub4)OCI_ATTR_USERNAME, + (OCIError *)errhp); + + OCIAttrSet ((dvoid *)sysauthhp, (ub4)OCI_HTYPE_SESSION, (dvoid *)syspass, + (ub4)strlen((char *)syspass), (ub4)OCI_ATTR_PASSWORD, + (OCIError *)errhp); + + /* Connecting to Database as sysdba */ + Checkerr (errhp, + OCISessionBegin (syssvchp, errhp, sysauthhp, OCI_CRED_RDBMS, + (ub4)OCI_SYSDBA), (oratext *)"OCISessionBegin"); + + OCIAttrSet ((dvoid *)syssvchp, OCI_HTYPE_SVCCTX, (dvoid *)sysauthhp, (ub4)0, + OCI_ATTR_SESSION, errhp); + + Checkerr (errhp, + OCIStmtPrepare2 ((OCISvcCtx *)syssvchp,(OCIStmt **)&stmthp, + (OCIError *)errhp, (text *)StatQuery, (ub4)strlen((char *)StatQuery), + (oratext *)NULL, (ub4) 0, (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT), + (oratext *)"OCIStmtPrepare"); + + Checkerr(errhp, + OCIAttrSet((OCIStmt *) stmthp, OCI_HTYPE_STMT, (dvoid *)&prefetch, + sizeof(prefetch), OCI_ATTR_PREFETCH_ROWS, (OCIError *)errhp), + (oratext *) "OCIAttrSet-prefetch"); + + Checkerr (errhp, + OCIDefineByPos ((OCIStmt *)stmthp, (OCIDefine **)&def2hp, + (OCIError *)errhp, (ub4)1, (dvoid *)&(statid), (sb4)statidSz, + (ub2)SQLT_INT, (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT), + (oratext *)"OCIDefByPos"); + + Checkerr (errhp, + OCIDefineByPos ((OCIStmt *)stmthp, (OCIDefine **)&def3hp, + (OCIError *)errhp, (ub4)2, (dvoid *)&(name), (sb4)nameSz, (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT), + (oratext *)"OCIDefByPos"); + + Checkerr (errhp, + OCIDefineByPos ((OCIStmt *)stmthp, (OCIDefine **)&def4hp, + (OCIError *)errhp, (ub4)3, (dvoid *)&(value), (sb4)valueSz, (ub2)SQLT_INT, + (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT), + (oratext *)"OCIDefByPos"); + + Checkerr (errhp, + OCIDefineByPos ((OCIStmt *)stmthp, (OCIDefine **)&def1hp, + (OCIError *)errhp, (ub4)4, (dvoid *)&(cacheid), (sb4)cacheidSz, + (ub2)SQLT_INT, (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT), + (oratext *)"OCIDefByPos"); + + /* Fetching the data from the stats table */ + if ((status = OCIStmtExecute ((OCISvcCtx *)syssvchp, (OCIStmt *)stmthp, + (OCIError *)errhp, (ub4)0, (ub4)0, + (OCISnapshot *)0, (OCISnapshot *)0, + (ub4)OCI_DEFAULT)) != OCI_SUCCESS ) + { + printf ("OCIStmtExecute for SELECT - Fail\n" ); + Checkerr (errhp, status,(oratext *)"Stmt Execute"); + } + else + { + printf("Contents of CLIENT_RESULT_CACHE_STATS$\n"); + printf("STAT_ID NAME OF STATISTICS VALUE CACHE_ID\n"); + printf("======= ================== ===== ========\n"); + do + { + status = OCIStmtFetch2((OCIStmt *)stmthp, (OCIError *)errhp, (ub4)1, + (ub2)OCI_FETCH_NEXT, (sb4)0, (ub4)OCI_DEFAULT); + + if (status == OCI_ERROR || status == OCI_INVALID_HANDLE) + { + Checkerr(errhp, status, (oratext *)"OCIStmtFetch2"); + break; + } + else if (status != OCI_NO_DATA) + { + printf("%5d %-20s %8d %6d\n", statid, name, value, cacheid); + } + }while(status != OCI_NO_DATA); + + } + + Checkerr (errhp, + OCIStmtRelease ((OCIStmt *)stmthp, (OCIError *)errhp,(dvoid *)NULL, 0, + OCI_DEFAULT), (oratext *)"StmtRelease"); + + Checkerr (errhp, + OCISessionEnd (syssvchp, errhp, sysauthhp, OCI_DEFAULT), + (oratext *) "Session-End"); + + Checkerr (errhp, + OCIServerDetach (srvhp, errhp, OCI_DEFAULT), + (oratext *) "Server-detach"); + + OCIHandleFree((dvoid *)sysauthhp, OCI_HTYPE_SESSION); + OCIHandleFree((dvoid *)syssvchp, OCI_HTYPE_SVCCTX); + OCIHandleFree((dvoid *)srvhp, OCI_HTYPE_SERVER); +} + +/* - Session Logoff --------------------------------------------------------*/ +static void dbLogoff () +{ + int idx; + + printf ("\nLogging off all the connected sessions.\n"); + + for (idx=0; idx<2; idx++) + Checkerr (errhp, + OCISessionRelease(svchp[idx], errhp, 0,0, OCI_DEFAULT), + (oratext *) "Session-Release"); + + OCIHandleFree((dvoid *)authhp, OCI_HTYPE_AUTHINFO); + OCIHandleFree((dvoid *)errhp, OCI_HTYPE_ERROR); +} + +/* - Error checking routing -------------------------------------------------*/ +void Checkerr(OCIError *errhp, sword status, text *msg) +{ + text msgbuf[512]; + sb4 errcode = 0; + + memset((void *) msgbuf, (int)'\0', (size_t)512); + if(status!=OCI_SUCCESS) + { + printf("error msg: %s\n",msg); + } + + switch (status) + { + case OCI_SUCCESS: break; + case OCI_SUCCESS_WITH_INFO: + printf("status = OCI_SUCCESS_WITH_INFO\n"); + OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + printf("ERROR CODE = %d\n", errcode); + printf("%.*s\n", 512, msgbuf); + if (errcode == 436 || errcode == 437 || errcode == 438 || errcode == 439) + exit(1); + break; + case OCI_NEED_DATA: + printf("status = OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + printf("status = OCI_NO_DATA\n"); + break; + case OCI_ERROR: + printf("status = OCI_ERROR\n"); + OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + printf("ERROR CODE = %d\n", errcode); + printf("%.*s\n", 512, msgbuf); + if (errcode == 436 || errcode == 437 || errcode == 438 || errcode == 439) + exit(1); + break; + case OCI_INVALID_HANDLE: + OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + printf("ERROR CODE = %d\n", errcode); + printf("%.*s\n", 512, msgbuf); + printf("status = OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + printf("status = OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + printf("status = OCI_CONTINUE\n"); + break; + default: + break; + } + return; +} diff --git a/cdemoqc.sql b/cdemoqc.sql new file mode 100644 index 0000000..015c4f5 --- /dev/null +++ b/cdemoqc.sql @@ -0,0 +1,53 @@ +Rem +Rem $Header: rdbms/demo/cdemoqc.sql /main/3 2008/10/23 23:36:35 dgopal Exp $ +Rem +Rem cdemoqc.sql +Rem +Rem Copyright (c) 2007, 2008, Oracle and/or its affiliates. +Rem All rights reserved. +Rem +Rem NAME +Rem cdemoqc.sql +Rem +Rem DESCRIPTION +Rem Creates schema for query cache OCI demo cdemoqc.c +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem dgopal 10/10/08 - Added a new table from cdemoqc2.c +Rem dgopal 12/19/07 - Modified schema +Rem dgopal 05/10/07 - Created +Rem + +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 + +CONNECT system/manager +GRANT CONNECT, RESOURCE TO ocitest IDENTIFIED BY ocitest; + +CONNECT ocitest/ocitest + +DROP TABLE qctable; +DROP TABLE ssntable; + +CREATE TABLE qctable (empno NUMBER, ename VARCHAR2(20), sal NUMBER); +CREATE TABLE ssntable (ssn NUMBER, empno NUMBER); + +CREATE OR REPLACE PROCEDURE insert_val +AS BEGIN +for i in 1..1000 loop + INSERT INTO qctable VALUES (i, 'EMP_'||i, i*100); + INSERT INTO ssntable VALUES (56345000+i, i); +end loop; +end; +/ +EXECUTE insert_val; + +COMMIT; diff --git a/cdemoqc2.c b/cdemoqc2.c new file mode 100644 index 0000000..495926e --- /dev/null +++ b/cdemoqc2.c @@ -0,0 +1,619 @@ +/* Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. */ + +/* + NAME + cdemoqc2 - OCI Query Cache(result cache) table annotation functionality + + DESCRIPTION + For using client result cache, result_cache hint not necessarily needs to + be used in query. If the table is created/altered with result_cache mode + FORCE, cache will be enabled by default and it will be used even if + result_cache hint is not used in the query. If result_cache mode is not + mentioned while creating table, the default mode is DEFAULT. In this case, + cache will be used only when result_cache hint is used in the query. + + Note that even when the result_cache mode is specified as FORCE, caching + will be enabled only for those queries which are cache worthy. + + In the below table, + rows -> represent the result_cache hint usage in the query + columns -> represent, the mode with which table was created + YES -> represents result cache will be used + NO -> represents result cache will not be used + + ----------------------------------------------- + | | DEFAULT MODE | FORCE MODE | + ----------------------------------------------- + | No Hint used | NO | YES | + | result_cache | YES | YES | + | no_result_cache | NO | NO | + ----------------------------------------------- + + NOTE: + To use the query cache feature (and hence this program), database should + have been brought up with client side result cache enabled. To bring the + database with result cache enabled, add the following lines in + initialization parameter file, + client_result_cache_size= + client_result_cache_lag= + compatible=11.0.0.0.0 + and bring up the database. + + MODIFIED (MM/DD/YY) + dgopal 10/10/08 - Created + +*/ + +#include + +#include +#include +#include + +#define NO_HINT 0 +#define CACHE_HINT 1 +#define NO_CACHE_HINT 2 + +#define FORCE_MODE 0 +#define DEFAULT_MODE 1 + +#define USER_TABLES 0 +#define ALL_TABLES 1 +#define DBA_TABLES 2 + +/* Function prototypes */ +static void query_emp(int idx); +static void query_ssn(int idx); +static void alt_table(int idx); +static void print_stats(int idx); +static void dbLogon(); +static void dbLogoff(); +static void Checkerr(OCIError *errhp, sword status, text *msg); + +int main(); + +static sword status = 0; +static OCISvcCtx *svchp; +static OCIError *errhp; +static OCIEnv *envhp; +static OCIAuthInfo *authhp; + +/* Queries from qctable */ +static text *query_emp_stmt[]={ +(text *)"SELECT empno, ename, sal FROM qctable", +(text *)"SELECT /*+ result_cache */ empno, ename, sal FROM qctable", +(text *)"SELECT /*+ no_result_cache */ empno, ename, sal FROM qctable" +}; + +/* Queries from ssntable */ +static text *query_ssn_stmt[]={ +(text *)"SELECT ssn, empno FROM ssntable", +(text *)"SELECT /*+ result_cache */ ssn, empno FROM ssntable", +(text *)"SELECT /*+ no_result_cache */ ssn, empno FROM ssntable" +}; + +/* Alter table statements with result_cache annotations */ +static text *alt_stmt[]={ +(text *)"ALTER TABLE ssntable RESULT_CACHE (MODE FORCE)", +(text *)"ALTER TABLE qctable RESULT_CACHE (MODE DEFAULT)" +}; + +/* Table can also be created with result_cache annotations. +(e.g.) +1. CREATE TABLE ssntable(ssn NUMBER, empno NUMBER) RESULT_CACHE (MODE FORCE) +2. CREATE TABLE qctable(empno NUMBER, ename VARCHAR2(20), sal NUMBER) RESULT_CACHE (MODE DEFAULT) +*/ + +/* - main -------------------------------------------------------------------*/ +int main () +{ + printf ("Executing table annotation demo - cdemoqc2\n\n"); + + /* Logging on to the database */ + dbLogon (); + + /* + Table was created by the cdemoqc.sql script without any result_cache mode + parameter. In this case caching will happen only when RESULT_CACHE sql + hint is used in the query. + */ + printf ("\nQuerying qctable which was created without specifying any " + "result_cache mode\n"); + printf ("Execute query with result_cache hint in query\n"); + query_emp(CACHE_HINT); + printf ("Re-execute would fetch from local cache\n"); + query_emp(CACHE_HINT); + + /* + If table RESULT_CACHE (MODE FORCE) is specified in CREATE or ALTER TABLE + statement caching will be used even if RESULT_CACHE sql hint is not + specified in query. However NO_RESULT_CACHE sql hint can be used to + explicitily disable caching. + + This FORCE MODE can be specified for the table which hardly gets updated. + */ + printf ("\nAltering ssntable with RESULT_CACHE (MODE FORCE)\n"); + alt_table(FORCE_MODE); + printf ("Execute would create local client cache even if no hint is " + "specified in query\n"); + query_ssn(NO_HINT); + printf ("Re-execute would fetch from local cache\n"); + query_ssn(NO_HINT); + + printf ("Even if the table is created with RESULT_CACHE MODE FORCE, execute " + "will not \n cache the results if NO_RESULT_CACHE is specified in " + "query\n"); + query_ssn(NO_CACHE_HINT); + printf ("Re-execute would fetch from the server\n"); + query_ssn(NO_CACHE_HINT); + + /* + Creating or altering table with RESULT_CACHE (MODE DEFAULT) is as good as + having table without any RESULT_CACHE hint. In this case caching will be + done only when RESULT_CACHE sql hint is used in the query. + */ + printf ("\nAltering qctable with RESULT_CACHE (MODE DEFAULT)\n"); + alt_table(DEFAULT_MODE); + printf ("Execute query without any result_cache hint in query\n"); + query_emp(NO_HINT); + printf ("Re-execute would fetch from the server\n"); + query_emp(NO_HINT); + + printf ("Execute query with sql result_cache hint\n"); + query_emp(CACHE_HINT); + printf ("Re-execute would fetch from local cache\n"); + query_emp(CACHE_HINT); + + printf("\nRESULT_CACHE parameter from USER_TABLES,\n"); + print_stats(USER_TABLES); + printf("\nRESULT_CACHE parameter from ALL_TABLES,\n"); + print_stats(ALL_TABLES); + /* + For quering DBA_TABLES, user needs to login as SYSDBA. Hence if you + uncomment this call, the program will prompt for sys user password. scanf() + has been used for fetching the password from user and you may want to + replace it with your platform specific function to hide the echoing of + password. + */ + /* + printf("\nRESULT_CACHE parameter from ALL_TABLES,\n"); + print_stats(DBA_TABLES); + */ + + dbLogoff (); + return 0; +} + +/* - Logon to the DB --------------------------------------------------------*/ +static void dbLogon () +{ + ub4 cachesize=10; + OraText *connStr = (text *)""; + OraText *username = (text *)"ocitest"; + OraText *password = (text *)"ocitest"; + + OCIEnvCreate ((OCIEnv **)&envhp, (ub4)OCI_DEFAULT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t))0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *))0, (size_t)0, (dvoid **)0); + + OCIHandleAlloc ((dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + + OCIHandleAlloc ((dvoid *)envhp, (dvoid **)&authhp, + (ub4)OCI_HTYPE_AUTHINFO, (size_t)0, (dvoid **)0); + + /* Connecting to database */ + + OCIAttrSet ((dvoid *)authhp, (ub4)OCI_HTYPE_AUTHINFO, (dvoid *)username, + (ub4)strlen((char *)username), (ub4)OCI_ATTR_USERNAME, + (OCIError *)errhp); + + OCIAttrSet ((dvoid *)authhp, (ub4)OCI_HTYPE_AUTHINFO, (dvoid *)password, + (ub4)strlen((char *)password), (ub4)OCI_ATTR_PASSWORD, + (OCIError *)errhp); + + Checkerr (errhp, + OCISessionGet ((OCIEnv *)envhp, (OCIError *)errhp, + (OCISvcCtx **)&svchp, (OCIAuthInfo *)authhp, (OraText *)connStr, + (ub4)strlen((char *)connStr), (OraText *)NULL, (ub4)0, (OraText **)0, + (ub4 *)0, (boolean *)0,(ub4)OCI_DEFAULT), + (oratext *)"OCISessionGet"); + + printf ("Connected to Database Session\n"); + + OCIAttrSet((dvoid *)svchp, OCI_HTYPE_SVCCTX, (dvoid *)&cachesize, + (ub4)0,OCI_ATTR_STMTCACHESIZE,errhp); +} + +/* - Execute SQL query (from qctable) ---------------------------------------*/ +static void query_emp (int idx) +{ + OCIStmt *stmthp = (OCIStmt *)0; + OCIDefine *def1hp = (OCIDefine *)0; + OCIDefine *def2hp = (OCIDefine *)0; + OCIDefine *def3hp = (OCIDefine *)0; + ub4 empno; + text ename[100]; + ub4 sal; + sb4 empnoSz = sizeof (empno); + sb4 enameSz = sizeof (ename); + sb4 salSz = sizeof (sal); + ub4 prefetch = 0; + + Checkerr (errhp, + OCIStmtPrepare2 ((OCISvcCtx *)svchp,(OCIStmt **)&stmthp, (OCIError *)errhp, + (text *)query_emp_stmt[idx], (ub4)strlen((char *)query_emp_stmt[idx]), + (oratext *)NULL, (ub4) 0, (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT), + (oratext *)"OCIStmtPrepare-emp"); + + /* Setting the prefetch count = 0 */ + Checkerr(errhp, + OCIAttrSet((OCIStmt *) stmthp, OCI_HTYPE_STMT, (dvoid *)&prefetch, + sizeof(prefetch), OCI_ATTR_PREFETCH_ROWS, (OCIError *)errhp), + (oratext *) "OCIAttrSet-prefetch-emp"); + + Checkerr (errhp, + OCIDefineByPos ((OCIStmt *)stmthp, (OCIDefine **)&def1hp, + (OCIError *)errhp, (ub4)1, (dvoid *)&(empno), (sb4)empnoSz, (ub2)SQLT_INT, + (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT), + (oratext *)"OCIDefByPos-emp"); + + Checkerr (errhp, + OCIDefineByPos ((OCIStmt *)stmthp, (OCIDefine **)&def2hp, + (OCIError *)errhp, (ub4)2, (dvoid *)&(ename), (sb4)enameSz, (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT), + (oratext *)"OCIDefByPos2-emp"); + + Checkerr (errhp, + OCIDefineByPos ((OCIStmt *)stmthp, (OCIDefine **)&def3hp, + (OCIError *)errhp, (ub4)3, (dvoid *)&(sal), (sb4)salSz, (ub2)SQLT_INT, + (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT), + (oratext *)"OCIDefByPos3-emp"); + + if ((status = OCIStmtExecute ((OCISvcCtx *)svchp, (OCIStmt *)stmthp, + (OCIError *)errhp, (ub4)0, (ub4)0, (OCISnapshot *)0, + (OCISnapshot *)0, (ub4)OCI_DEFAULT)) != OCI_SUCCESS ) + { + printf ("OCIStmtExecute for SELECT - Fail\n" ); + Checkerr (errhp, status,(oratext *)"Stmt Execute-emp"); + } + else + { + do + { + status = OCIStmtFetch2((OCIStmt *)stmthp, (OCIError *)errhp, (ub4)1, + (ub2)OCI_FETCH_NEXT, (sb4)0, (ub4)OCI_DEFAULT); + + if (status == OCI_ERROR || status == OCI_INVALID_HANDLE) + { + Checkerr(errhp, status, (oratext *)"OCIStmtFetch2-emp"); + break; + } + else if (status != OCI_NO_DATA) + { + /* + printf("EMPNO is %d, ENAME is %s, SAL is %d\n", empno, ename, sal); + */ + } + }while(status != OCI_NO_DATA); + } + + Checkerr (errhp, + OCIStmtRelease ((OCIStmt *)stmthp, (OCIError *)errhp,(dvoid *)NULL, 0, + OCI_DEFAULT), (oratext *)"StmtRelease-emp"); +} + +/* - Execute SQL query (from ssntable) --------------------------------------*/ +static void query_ssn (int idx) +{ + OCIStmt *stmthp = (OCIStmt *)0; + OCIDefine *def1hp = (OCIDefine *)0; + OCIDefine *def2hp = (OCIDefine *)0; + ub4 ssn; + ub4 empno; + sb4 ssnSz = sizeof (ssn); + sb4 empnoSz = sizeof (empno); + ub4 prefetch = 0; + + Checkerr (errhp, + OCIStmtPrepare2 ((OCISvcCtx *)svchp,(OCIStmt **)&stmthp, (OCIError *)errhp, + (text *)query_ssn_stmt[idx], (ub4)strlen((char *)query_ssn_stmt[idx]), + (oratext *)NULL, (ub4) 0, (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT), + (oratext *)"OCIStmtPrepare-ssn"); + + /* Setting the prefetch count = 0 */ + Checkerr(errhp, + OCIAttrSet((OCIStmt *) stmthp, OCI_HTYPE_STMT, (dvoid *)&prefetch, + sizeof(prefetch), OCI_ATTR_PREFETCH_ROWS, (OCIError *)errhp), + (oratext *) "OCIAttrSet-prefetch-ssn"); + + Checkerr (errhp, + OCIDefineByPos ((OCIStmt *)stmthp, (OCIDefine **)&def1hp, + (OCIError *)errhp, (ub4)1, (dvoid *)&(ssn), (sb4)ssnSz, (ub2)SQLT_INT, + (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT), + (oratext *)"OCIDefByPos1-ssn"); + + Checkerr (errhp, + OCIDefineByPos ((OCIStmt *)stmthp, (OCIDefine **)&def2hp, + (OCIError *)errhp, (ub4)2, (dvoid *)&(empno), (sb4)empnoSz, (ub2)SQLT_INT, + (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT), + (oratext *)"OCIDefByPos2-ssn"); + + if ((status = OCIStmtExecute ((OCISvcCtx *)svchp, (OCIStmt *)stmthp, + (OCIError *)errhp, (ub4)0, (ub4)0, (OCISnapshot *)0, + (OCISnapshot *)0, (ub4)OCI_DEFAULT)) != OCI_SUCCESS ) + { + printf ("OCIStmtExecute for SELECT - Fail\n" ); + Checkerr (errhp, status,(oratext *)"Stmt Execute-ssn"); + } + else + { + do + { + status = OCIStmtFetch2((OCIStmt *)stmthp, (OCIError *)errhp, (ub4)1, + (ub2)OCI_FETCH_NEXT, (sb4)0, (ub4)OCI_DEFAULT); + + if (status == OCI_ERROR || status == OCI_INVALID_HANDLE) + { + Checkerr(errhp, status, (oratext *)"OCIStmtFetch2-ssn"); + break; + } + else if (status != OCI_NO_DATA) + { + /* + printf("SSN is %d, EMPNO is %d\n", ssn, empno); + */ + } + }while(status != OCI_NO_DATA); + } + + Checkerr (errhp, + OCIStmtRelease ((OCIStmt *)stmthp, (OCIError *)errhp,(dvoid *)NULL, 0, + OCI_DEFAULT), (oratext *)"StmtRelease-ssn"); +} + +/* - Execute alter result_cache mode statement ------------------------------*/ +void alt_table(int idx) +{ + OCIStmt *stmthp = (OCIStmt *)0; + + Checkerr (errhp, + OCIHandleAlloc ((dvoid *)envhp, (dvoid **)&stmthp, (ub4)OCI_HTYPE_STMT, + (size_t)0, (dvoid **)0), (oratext *)"OCIHandleAlloc-ddl"); + + Checkerr (errhp, + OCIStmtPrepare ((OCIStmt *)stmthp, (OCIError *)errhp, (text *)alt_stmt[idx], + (ub4)strlen((char *)alt_stmt[idx]), (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT), + (oratext *)"OCIStmtPrepare-ddl"); + + if (status = OCIStmtExecute ((OCISvcCtx *)svchp, (OCIStmt *)stmthp, + (OCIError *)errhp, (ub4)1, (ub4)0, (OCISnapshot *)0, + (OCISnapshot *)0, (ub4)OCI_COMMIT_ON_SUCCESS)) + { + printf ("OCIStmtExecute update - Fail\n"); + Checkerr (errhp, status,(oratext *)"Stmt Execute Update-ddl"); + } + + Checkerr (errhp, + OCIHandleFree ((dvoid *)stmthp, (ub4)OCI_HTYPE_STMT), + (oratext *)"OCIHandleFree-ddl"); +} + +/* - Fetches and prints result cache statistics information -----------------*/ +void print_stats(int idx) +{ + OCISvcCtx *statsvchp = NULL; + OCIServer *srvhp = NULL; + OCIStmt *stmthp = (OCIStmt *)0; + OCISession *sysauthhp = (OCISession *)0; + OCIDefine *def1hp = (OCIDefine *)0; + OCIDefine *def2hp = (OCIDefine *)0; + text tablename[128]; + text cacheusage[128]; + sb4 tablenameSz = sizeof (tablename); + sb4 cacheusageSz = sizeof (cacheusage); + ub4 prefetch = 0; + OraText *connStr = (text *)""; + OraText *sysuser = (text *)"sys"; + OraText syspass[128]; + text StatQuery[128]; + + /* For querying from USER_TABLES */ + if (idx==USER_TABLES) + { + strcpy ((char *)StatQuery, "SELECT table_name, result_cache FROM user_tables WHERE table_name='QCTABLE' OR table_name='SSNTABLE' ORDER BY table_name"); + statsvchp=svchp; + } + /* For querying from ALL_TABLES */ + else if (idx=ALL_TABLES) + { + strcpy ((char *)StatQuery, "SELECT table_name, result_cache FROM all_tables WHERE table_name='QCTABLE' OR table_name='SSNTABLE' ORDER BY table_name"); + statsvchp=svchp; + } + /* For querying from DBA_TABLES */ + else if (idx==DBA_TABLES) + { + strcpy ((char *)StatQuery, "SELECT table_name, result_cache FROM dba_tables WHERE table_name='QCTABLE' OR table_name='SSNTABLE' ORDER BY table_name"); + + /* To access DBA_TABLES sysdba perviledge is required */ + printf ("\nPlease enter password for sys user to continue:\n"); + scanf ("%s", (char *)syspass); + + OCIHandleAlloc ((dvoid *)envhp, (dvoid **)&srvhp, (ub4)OCI_HTYPE_SERVER, + (size_t)0, (dvoid **)0); + + OCIHandleAlloc ((dvoid *)envhp, (dvoid **)&statsvchp, (ub4)OCI_HTYPE_SVCCTX, + (size_t)0, (dvoid **)0); + + Checkerr (errhp, + OCIServerAttach (srvhp, errhp, (text *)connStr, + (sb4)strlen((char *)connStr), 0), (oratext *)"OCIServerAttach-stat"); + + OCIAttrSet ((dvoid *) statsvchp, OCI_HTYPE_SVCCTX, (dvoid *)srvhp, (ub4) 0, + OCI_ATTR_SERVER, (OCIError *) errhp); + + OCIHandleAlloc ((dvoid *)envhp, (dvoid **)&sysauthhp, + (ub4)OCI_HTYPE_SESSION, (size_t)0, (dvoid **)0); + + OCIAttrSet ((dvoid *)sysauthhp, (ub4)OCI_HTYPE_SESSION, (dvoid *)sysuser, + (ub4)strlen((char *)sysuser), (ub4)OCI_ATTR_USERNAME, + (OCIError *)errhp); + + OCIAttrSet ((dvoid *)sysauthhp, (ub4)OCI_HTYPE_SESSION, (dvoid *)syspass, + (ub4)strlen((char *)syspass), (ub4)OCI_ATTR_PASSWORD, + (OCIError *)errhp); + + /* Connecting to Database as sysdba */ + Checkerr (errhp, + OCISessionBegin (statsvchp, errhp, sysauthhp, OCI_CRED_RDBMS, + (ub4)OCI_SYSDBA), (oratext *)"OCISessionBegin-stat"); + + OCIAttrSet ((dvoid *)statsvchp, OCI_HTYPE_SVCCTX, (dvoid *)sysauthhp, (ub4)0, + OCI_ATTR_SESSION, errhp); + } + + Checkerr (errhp, + OCIStmtPrepare2 ((OCISvcCtx *)statsvchp,(OCIStmt **)&stmthp, + (OCIError *)errhp, (text *)StatQuery, (ub4)strlen((char *)StatQuery), + (oratext *)NULL, (ub4) 0, (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT), + (oratext *)"OCIStmtPrepare-stat"); + + Checkerr(errhp, + OCIAttrSet((OCIStmt *) stmthp, OCI_HTYPE_STMT, (dvoid *)&prefetch, + sizeof(prefetch), OCI_ATTR_PREFETCH_ROWS, (OCIError *)errhp), + (oratext *) "OCIAttrSet-prefetch-stat"); + + Checkerr (errhp, + OCIDefineByPos ((OCIStmt *)stmthp, (OCIDefine **)&def1hp, + (OCIError *)errhp, (ub4)1, (dvoid *)&(tablename), (sb4)tablenameSz, + (ub2)SQLT_STR, (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT), + (oratext *)"OCIDefByPos-stat"); + + Checkerr (errhp, + OCIDefineByPos ((OCIStmt *)stmthp, (OCIDefine **)&def2hp, + (OCIError *)errhp, (ub4)2, (dvoid *)&(cacheusage), (sb4)cacheusageSz, + (ub2)SQLT_STR, (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT), + (oratext *)"OCIDefByPos2-stat"); + + /* Fetching the data from the stats table */ + if ((status = OCIStmtExecute ((OCISvcCtx *)statsvchp, (OCIStmt *)stmthp, + (OCIError *)errhp, (ub4)0, (ub4)0, + (OCISnapshot *)0, (OCISnapshot *)0, + (ub4)OCI_DEFAULT)) != OCI_SUCCESS ) + { + printf ("OCIStmtExecute for SELECT - Fail\n" ); + Checkerr (errhp, status,(oratext *)"Stmt Execute-stat"); + } + else + { + printf("TABLE_NAME RESULT_CACHE\n"); + printf("========== ============\n"); + do + { + status = OCIStmtFetch2((OCIStmt *)stmthp, (OCIError *)errhp, (ub4)1, + (ub2)OCI_FETCH_NEXT, (sb4)0, (ub4)OCI_DEFAULT); + + if (status == OCI_ERROR || status == OCI_INVALID_HANDLE) + { + Checkerr(errhp, status, (oratext *)"OCIStmtFetch2-stat"); + break; + } + else if (status != OCI_NO_DATA) + { + printf("%-15s %-15s\n", tablename, cacheusage); + } + }while(status != OCI_NO_DATA); + } + + Checkerr (errhp, + OCIStmtRelease ((OCIStmt *)stmthp, (OCIError *)errhp,(dvoid *)NULL, 0, + OCI_DEFAULT), (oratext *)"StmtRelease-stat"); + + /* If sysdba session is created, terminate it */ + if (idx==DBA_TABLES) + { + Checkerr (errhp, + OCISessionEnd (statsvchp, errhp, sysauthhp, OCI_DEFAULT), + (oratext *) "Session-End-stat"); + + Checkerr (errhp, + OCIServerDetach (srvhp, errhp, OCI_DEFAULT), + (oratext *) "Server-detach-stat"); + + OCIHandleFree((dvoid *)sysauthhp, OCI_HTYPE_SESSION); + OCIHandleFree((dvoid *)statsvchp, OCI_HTYPE_SVCCTX); + OCIHandleFree((dvoid *)srvhp, OCI_HTYPE_SERVER); + } +} + +/* - Session Logoff --------------------------------------------------------*/ +static void dbLogoff () +{ + printf ("\nLogging off from the connected session.\n"); + + Checkerr (errhp, + OCISessionRelease(svchp, errhp, 0,0, OCI_DEFAULT), + (oratext *) "Session-Release"); + + OCIHandleFree((dvoid *)authhp, OCI_HTYPE_AUTHINFO); + OCIHandleFree((dvoid *)errhp, OCI_HTYPE_ERROR); +} + +/* - Error checking routing -------------------------------------------------*/ +void Checkerr(OCIError *errhp, sword status, text *msg) +{ + text msgbuf[512]; + sb4 errcode = 0; + + memset((void *) msgbuf, (int)'\0', (size_t)512); + if(status!=OCI_SUCCESS) + { + printf("error msg: %s\n",msg); + } + + switch (status) + { + case OCI_SUCCESS: break; + case OCI_SUCCESS_WITH_INFO: + printf("status = OCI_SUCCESS_WITH_INFO\n"); + OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + printf("ERROR CODE = %d\n", errcode); + printf("%.*s\n", 512, msgbuf); + if (errcode == 436 || errcode == 437 || errcode == 438 || errcode == 439) + exit(1); + break; + case OCI_NEED_DATA: + printf("status = OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + printf("status = OCI_NO_DATA\n"); + break; + case OCI_ERROR: + printf("status = OCI_ERROR\n"); + OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + printf("ERROR CODE = %d\n", errcode); + printf("%.*s\n", 512, msgbuf); + if (errcode == 436 || errcode == 437 || errcode == 438 || errcode == 439) + exit(1); + break; + case OCI_INVALID_HANDLE: + OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + printf("ERROR CODE = %d\n", errcode); + printf("%.*s\n", 512, msgbuf); + printf("status = OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + printf("status = OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + printf("status = OCI_CONTINUE\n"); + break; + default: + break; + } + return; +} diff --git a/cdemorid.c b/cdemorid.c new file mode 100644 index 0000000..5bae213 --- /dev/null +++ b/cdemorid.c @@ -0,0 +1,517 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemorid.c 14-jul-99.13:15:16 mjaeger Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1997, 1999, Oracle Corporation. All rights reserved. +*/ + +/* + + NAME + cdemorid - example of array DML and fetches using prefetch + example of getting multiple rowids in one roundtrip + + + DESCRIPTION + test retrieves ROWIDs from table and use it for a subsequent + UPDATE. 2 roundtrips, one to get all the rowids, and another to update it + Does not require use of ROWID psuedo column in the text of the SQL. + Uses OCI_COMMIT_ON_SUCCESS to cut down a roundtrip to commit the update. + + NOTES + The ROWID used for INSERT, UPDATE, or DELETE must be obtained + through a SELECT ... FOR UPDATE ... statement, not through a + simple SELECT statement, using OCIGetAttr. Prefetching must be used. + Not compatible with pre 8i servers. + + Please run cdemorid.sql before this. + + MODIFIED (MM/DD/YY) + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + dchatter 10/16/98 - Creating new demo for select for update and update + using rowids in two roundtrips. + dchatter 10/16/98 - Creation + + + +*/ + +/*------------------------Inclusions-------------------------------*/ + +#ifndef CDEMORID +#include +#endif + +static boolean logged_on = FALSE; + + +static ub4 ridlen = 0; /* for the one obtained from RDD */ +static ub4 i; + +/*------------------------end of Inclusions-----------------------------*/ + +int main(argc, argv) +int argc; +char *argv[]; +{ + text *username = (text *)"CDEMORID"; + text *password = (text *)"CDEMORID"; + + OCIEnv *envhp; + OCISvcCtx *svchp; + OCIError *errhp; + OCIRowid *Rowid[MAXROWS]; + OCIStmt *select_p, *update_p; + + /* + * Initialize the handles for the program + */ + + if (init_handles(&envhp, &errhp, (ub4)OCI_DEFAULT)) + { + printf("FAILED: init_handles()\n"); + return cleanup(logged_on, envhp, svchp, errhp); + } + + /* + * Connect and create an user session + */ + + if (OCILogon(envhp, errhp, &svchp, username, strlen (username), + password, strlen (password), "", 0)) + { + printf("FAILED: log_on()\n"); + return cleanup(logged_on, envhp, svchp, errhp); + } + + logged_on = TRUE; + + /* allocate the statement handles for Select and Update */ + + if (OCIHandleAlloc((dvoid *)envhp, (dvoid **) &select_p, + (ub4)OCI_HTYPE_STMT, (CONST size_t) 0, (dvoid **) 0) + || OCIHandleAlloc((dvoid *)envhp, (dvoid **) &update_p, + (ub4)OCI_HTYPE_STMT, (CONST size_t) 0, (dvoid **) 0)) + { + printf("FAILED: alloc statement handles\n"); + return cleanup(logged_on, envhp, svchp, errhp); + } + + for (i = 0; i < MAXROWS; i++) + if (OCIDescriptorAlloc((dvoid *) envhp, (dvoid **) &(Rowid[i]), + (ub4) OCI_DTYPE_ROWID, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIDescriptorAlloc()\n"); + return cleanup(logged_on, envhp, svchp, errhp); + } + + + /* + * First we select all the rows that are to be updated. + * There are five rows that satisfy the example query and we get all the five + * rows in one roundtrip since prefetch count is 10. + */ + if (get_all_rows(svchp, errhp, select_p, Rowid)) + { + printf("Fetch of all rowids failed\n"); + return cleanup(logged_on, envhp, svchp, errhp); + } + + /* + * We update five rows in one roundtrip by binding an array of rowids fetched + * in the previous functions. + * We also commit in the same roundtrip. + * We do another roundtrip to fetch the updated rows for display although we + * could have used the returning clause to even cut that roundtrip. See + * cdemodr.c for details on how to use DML returning. + */ + + if (update_all_rows(svchp, errhp, update_p, select_p, Rowid)) + { + printf("Update of all rows failed\n"); + return cleanup(logged_on, envhp, svchp, errhp); + } + + return cleanup(logged_on, envhp, svchp, errhp); +} + + +/* ----------------------------------------------------------------- */ +/* initialize environment, allocate handles */ +/* ----------------------------------------------------------------- */ +sword init_handles(envhp, errhp, init_mode) +OCIEnv **envhp; +OCIError **errhp; +ub4 init_mode; +{ + printf("Environment setup ....\n"); + + if (OCIInitialize(init_mode, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 )) + { + printf("FAILED: OCIInitialize()\n"); + return OCI_ERROR; + } + + if (OCIEnvInit((OCIEnv **) envhp, (ub4) OCI_DEFAULT, + (size_t) 0, (dvoid **) 0 )) + { + printf("FAILED: OCIEnvInit()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) *envhp, (dvoid **) errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on errhp\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + +/*---------------------------------------------------------------------* + * cleanup() + * disconnects and cleans up the allocated memory + *---------------------------------------------------------------------*/ + +sword cleanup(loggedon, envhp, svchp, errhp) +boolean loggedon; +OCIEnv *envhp; +OCISvcCtx *svchp; +OCIError *errhp; +{ + + report_error(errhp); + + if (loggedon) + OCILogoff (svchp, errhp); + + printf("Freeing handles ...\n"); + + if (envhp) + OCIHandleFree((dvoid *) envhp, (ub4) OCI_HTYPE_ENV); + + return OCI_SUCCESS; +} + + +/* ----------------------------------------------------------------- */ +void report_error(errhp) +OCIError *errhp; +{ + text msgbuf[512]; + sb4 errcode = 0; + + memset((void *) msgbuf, (int)'\0', (size_t)512); + + OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + if (errcode) + { + printf("ERROR CODE = %d\n", errcode); + printf("%.*s\n", 512, msgbuf); + exit(1); + } + +} + +/* ----------------------------------------------------------------- */ +void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + switch (status) + { + case OCI_SUCCESS: break; + case OCI_SUCCESS_WITH_INFO: + printf("status = OCI_SUCCESS_WITH_INFO\n"); + report_error(errhp); + break; + case OCI_NEED_DATA: + printf("status = OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + printf("status = OCI_NO_DATA\n"); + break; + case OCI_ERROR: + printf("status = OCI_ERROR\n"); + report_error(errhp); + break; + case OCI_INVALID_HANDLE: + printf("status = OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + printf("status = OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + printf("status = OCI_CONTINUE\n"); + break; + default: + break; + } +} + +sword get_all_rows(svchp, errhp, select_p, Rowid) +OCISvcCtx *svchp; +OCIError *errhp; +OCIStmt *select_p; +OCIRowid **Rowid; + +{ + + + text *mySql = (text *) "SELECT C1, C2 from FOO where C1 > 15 for UPDATE"; + ub4 prefetch = 10; + sword errr; + ub4 c1; + text c2[30]; + OCIDefine *defnp1, *defnp2; + + /* prepare the select statement for fetching all rows */ + + if (OCIStmtPrepare (select_p, errhp, + mySql, strlen(mySql), OCI_NTV_SYNTAX, OCI_DEFAULT)) + { + printf ("Prepare failed \n"); + return (OCI_ERROR); + } + + /* + * since we are interested in all the rows lets set prefetch to 10 + * before execute + */ + + + if (OCIAttrSet (select_p, + OCI_HTYPE_STMT, + &prefetch, /* prefetch upto 10 rows */ + 0, + OCI_ATTR_PREFETCH_ROWS, + errhp)) + { + printf ("Setting the prefetch count failed \n"); + return (OCI_ERROR); + } + + + if (errr = OCIStmtExecute(svchp, + select_p, + errhp, + (ub4) 0, + (ub4) 0, + (OCISnapshot *) NULL, + (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)) + { + if (errr != OCI_NO_DATA) return errr; + + } + + + /* + * now fetch all the rows. + * we will just define one piece of storage each for the columns and get the + * data into it since we really do not care for the column data. + * after each fetch we will retrieve the rowid of the fetched row. + */ + + if (OCIDefineByPos ( select_p, + &defnp1, + errhp, + 1, + &c1, + sizeof (c1), + SQLT_INT, + (dvoid *) 0, + (dvoid *) 0, + (dvoid *) 0, + OCI_DEFAULT) || + OCIDefineByPos ( select_p, + &defnp2, + errhp, + 2, + &c2, + 30, + SQLT_STR, + (dvoid *) 0, + (dvoid *) 0, + (dvoid *) 0, + OCI_DEFAULT)) + { + printf ("Failed to define\n"); + return (OCI_ERROR); + } + + printf ("Column C1 Column C2\n"); + printf ("_______________________\n"); + + for (i = 0; i < MAXROWS; i++) + { + if (OCIStmtFetch (select_p, + errhp, + 1, + OCI_FETCH_NEXT, + OCI_DEFAULT)) + { + printf ("Fetch failed \n"); + return (OCI_ERROR); + } + + printf ("%d %s\n", c1, c2); + + if (OCIAttrGet (select_p, + OCI_HTYPE_STMT, + Rowid[i], /* get the current rowid */ + 0, + OCI_ATTR_ROWID, + errhp)) + { + printf ("Getting the Rowid failed \n"); + return (OCI_ERROR); + } + + } + + return OCI_SUCCESS; +} + + +sword update_all_rows(svchp, errhp, update_p, select_p, Rowid) +OCISvcCtx *svchp; +OCIError *errhp; +OCIStmt *update_p; +OCIStmt *select_p; +OCIRowid **Rowid; + +{ + + + text *mySql = (text *) "UPDATE FOO set c1 = c1 - 1 where rowid = :a"; + ub4 prefetch = 10; + sword errr; + ub4 c1; + text c2[30]; + OCIBind *bndhp; + OCIDefine *defnp1, + *defnp2; + + /* prepare the select statement for fetching all rows */ + + if (OCIStmtPrepare (update_p, errhp, + mySql, strlen(mySql), OCI_NTV_SYNTAX, OCI_DEFAULT)) + { + printf ("Prepare failed \n"); + return (OCI_ERROR); + } + + if (OCIBindByPos ( update_p, + &bndhp, + errhp, + 1, + &Rowid[0], + sizeof(OCIRowid *), + SQLT_RDD, + (ub2 *) 0, + (ub2 *) 0, + (ub4) 0, + (ub4) 0, + (ub4 *) 0, + (ub4) OCI_DEFAULT)) + { + printf ("Bind failed \n"); + return (OCI_ERROR); + } + + if (errr = OCIStmtExecute(svchp, + update_p, + errhp, + (ub4) MAXROWS, + (ub4) 0, + (OCISnapshot *) NULL, + (OCISnapshot *) NULL, + (ub4) OCI_COMMIT_ON_SUCCESS)) + { + printf ("Update failed \n"); + return (OCI_ERROR); + } + + + /* + * now fetch all the rows for display. + * we will just define one piece of storage each for the columns and get the + * data into it since we really do not care for the column data. + */ + + if (errr = OCIStmtExecute(svchp, + select_p, + errhp, + (ub4) 0, + (ub4) 0, + (OCISnapshot *) NULL, + (OCISnapshot *) NULL, + (ub4) OCI_DEFAULT)) + { + if (errr != OCI_NO_DATA) return errr; + + } + + if (OCIDefineByPos ( select_p, + &defnp1, + errhp, + 1, + &c1, + sizeof (c1), + SQLT_INT, + (dvoid *) 0, + (dvoid *) 0, + (dvoid *) 0, + OCI_DEFAULT) || + OCIDefineByPos ( select_p, + &defnp2, + errhp, + 2, + &c2, + 30, + SQLT_STR, + (dvoid *) 0, + (dvoid *) 0, + (dvoid *) 0, + OCI_DEFAULT)) + { + printf ("Failed to define\n"); + return (OCI_ERROR); + } + + + printf ("after UPDATE\n"); + printf ("Column C1 Column C2\n"); + printf ("_______________________\n"); + + + for (i = 0; i < MAXROWS; i++) + { + if (OCIStmtFetch (select_p, + errhp, + 1, + OCI_FETCH_NEXT, + OCI_DEFAULT)) + { + printf ("Fetch failed \n"); + return (OCI_ERROR); + } + + printf ("%d %s\n", c1, c2); + + } + + return OCI_SUCCESS; +} + + +/* end of file cdemorid.c */ + + diff --git a/cdemorid.h b/cdemorid.h new file mode 100644 index 0000000..70472cd --- /dev/null +++ b/cdemorid.h @@ -0,0 +1,105 @@ +/* + * $Header: cdemorid.h 13-sep-2000.22:27:29 emendez Exp $ + */ + +/* Copyright (c) 1997, 2000 Oracle Corporation. All rights reserved. +*/ + +/* NOTE: See 'header_template.doc' in the 'doc' dve under the 'forms' + directory for the header file template that includes instructions. +*/ + +/* + NAME + cdemorid.h - + + DESCRIPTION + test using ROWID with INSERT, UPDATE, DELETE. + + RELATED DOCUMENTS + + INSPECTION STATUS + Inspection date: + Inspection status: + Estimated increasing cost defects per page: + Rule sets: + + ACCEPTANCE REVIEW STATUS + Review date: + Review status: + Reviewers: + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + EXAMPLES + + NOTES + + + MODIFIED (MM/DD/YY) + emendez 09/13/00 - fix top 5 olint errors + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + dchatter 10/16/98 - Creating new demo cdemorid + dchatter 10/16/98 - Creation + + +*/ + +#ifndef CDEMORID +#define CDEMORID + +/*------------------------------------------------------------------------ + * Include Files + */ + +#include +#include +#include +#include + +#define MAXBINDS 2 +#define MAXROWS 5 +/*-------------------------------------------------------------------------- + * Static Function Declarations + */ + +sword init_handles(/*_ OCIEnv **envhp, + OCIError **errhp, + ub4 init_mode _*/); + +sword cleanup(/*_ boolean loggedon, + OCIEnv *envhp, + OCISvcCtx *svchp, + OCIError *errhp _*/); + +void report_error(/*_ OCIError *errhp _*/); + +void checkerr(/*_ OCIError *errhp, + sword status _*/); + +sword get_all_rows(/*_ OCISvcCtx *svchp, + OCIError *errhp, + OCIStmt *select_p, + OCIRowid **Rowid _*/); + +sword update_all_rows(/*_ OCISvcCtx *svchp, + OCIError *errhp, + OCIStmt *update_p, + OCIStmt *select_p, + OCIRowid **Rowid _*/); + +int main(/*_ int argc, char *argv[] _*/); + + +#endif /* CDEMORID */ + + + + + + + diff --git a/cdemorid.sql b/cdemorid.sql new file mode 100644 index 0000000..550e56f --- /dev/null +++ b/cdemorid.sql @@ -0,0 +1,57 @@ +rem +rem $Header: cdemorid.sql 14-jul-99.13:52:59 mjaeger Exp $ +rem +rem cdemorid.sql +rem +rem Copyright (c) 1998, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem cdemorid.sql - SQL to set up cdemorid demo +rem +rem DESCRIPTION +rem set up for testing ROWID with UPDATE +rem +rem NOTES +rem +rem +rem MODIFIED (MM/DD/YY) +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem dchatter 10/16/98 - SQL for cdemorid +rem dchatter 10/16/98 - Created +rem + +connect system/manager +drop user cdemorid cascade; +grant connect, resource to cdemorid identified by cdemorid; + + +CONNECT cdemorid/cdemorid + +CREATE TABLE FOO (C1 INTEGER, C2 VARCHAR2(20)); + +INSERT INTO FOO VALUES (1, 'Row 1'); +INSERT INTO FOO VALUES (2, 'Row 2'); +INSERT INTO FOO VALUES (3, 'Row 3'); +INSERT INTO FOO VALUES (4, 'Row 4'); +INSERT INTO FOO VALUES (5, 'Row 5'); +INSERT INTO FOO VALUES (6, 'Row 6'); +INSERT INTO FOO VALUES (7, 'Row 7'); +INSERT INTO FOO VALUES (8, 'Row 8'); +INSERT INTO FOO VALUES (9, 'Row 9'); +INSERT INTO FOO VALUES (10, 'Row 10'); +INSERT INTO FOO VALUES (11, 'Row 11'); +INSERT INTO FOO VALUES (12, 'Row 12'); +INSERT INTO FOO VALUES (13, 'Row 13'); +INSERT INTO FOO VALUES (14, 'Row 14'); +INSERT INTO FOO VALUES (15, 'Row 15'); +INSERT INTO FOO VALUES (17, 'Row 16'); +INSERT INTO FOO VALUES (18, 'Row 17'); +INSERT INTO FOO VALUES (19, 'Row 18'); +INSERT INTO FOO VALUES (20, 'Row 19'); +INSERT INTO FOO VALUES (21, 'Row 20'); + +COMMIT + + +EXIT + diff --git a/cdemort.c b/cdemort.c new file mode 100644 index 0000000..52d1a73 --- /dev/null +++ b/cdemort.c @@ -0,0 +1,621 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemort.c 14-jul-99.13:21:07 mjaeger Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1995, 1999,, 2000 Oracle Corporation. All rights reserved. +*/ + +/* + NAME + cdemort.c + DESCRIPTION + Tests ORT user interface type access. + + cdemo_ort takes the username, password and a type name + (created in the database) as a command line argument and + dumps all the information about the type -- its attribute + types, methods, method parameters, etc. + + NOTES + See routines. + + MODIFIED (MM/DD/YY) + svedala 01/24/00 - 4th argument to OCITypeMethodOverload should be + "CONST text *" - bug 1078623 + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + svedala 09/09/98 - lines longer than 79 chars reformatted - bug 722491 + cchau 05/19/97 - change OCITypeByName to OCIDescribeAny + echen 03/05/97 - remove unnecessary code + cxcheng 02/20/97 - fix oro names + cxcheng 02/10/97 - remove short ORO names + cxcheng 01/15/97 - change prototype of OCITypeElemParameterizedType() + echen 01/03/97 - modify the test + echen 11/15/96 - oci beautification + echen 07/25/96 - enhance the demo + dchatter 07/18/96 - remove Oracle specific code + echen 07/16/96 - Creation +*/ + +#ifndef CDEMO_ORT_ORACLE +#include "cdemort.h" +#endif + +/*****************************************************************************/ +static void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + break; + case OCI_NEED_DATA: + break; + case OCI_NO_DATA: + break; + case OCI_ERROR: + (void) OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); + (void) printf("Error - %s\n", errbuf); + break; + case OCI_INVALID_HANDLE: + break; + case OCI_STILL_EXECUTING: + break; + case OCI_CONTINUE: + break; + default: + break; + } +} + +/*****************************************************************************/ +static void print_method_positions(meth_name, methpos, om_count) +text *meth_name; +ub4 methpos[10]; +ub4 om_count; +{ + ub4 i; + + (void) printf("The position(s) for method %s -- %d", + meth_name, methpos[0]); + for (i = 1; i < om_count; i++) + (void) printf(", %d", methpos[i]); + + (void) printf(".\n"); +} + + +/*****************************************************************************/ +static void unit_test_type_access(envhp, errhp, svchp, type_name) +OCIEnv *envhp; +OCIError *errhp; +OCISvcCtx *svchp; +char *type_name; +{ + ub1 meth_flags; + ub4 i, j, k; + text *text_value, *ret_param; + ub4 text_len, len; + ub4 count, pcount, pos, methpos[10], om_count; + OCITypeCode typecode; + OCIType *at_tdo = (OCIType *) 0, + *tdo_stored, *param_tdo, *attr_tdo, *non_collection, + *return_tdo; + OCITypeElem *rdo, *pdo; + OCITypeIter *iterator; + OCITypeMethod *mdoPtr_array = (OCITypeMethod *) 0; + OCITypeElem *ado = (OCITypeElem *) 0, **bad_ado = (OCITypeElem **) 0, + *ado1 = (OCITypeElem *) 0; + OCITypeMethod *mdo, **bad_mdo = (OCITypeMethod **) 0; + OCITypeElem *ms_ado; + ub2 sqtcode, sqttype; + ub4 num_elems; + OCITypeElem *element; + OCIType *element_type; + OCIType *table_type; + text *method, *pname, *meth_name; + ub4 mname_len; + OCIRef *type_ref = (OCIRef *) 0; + OCIDescribe *dschp = (OCIDescribe *) 0; + OCIParam *parmp; + + + + /* ----------------- GET INFORMATION ABOUT A TYPE ----------------- */ + + /* allocate describe handle for OCIDescribeAny */ + checkerr(errhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **) &dschp, + (ub4) OCI_HTYPE_DESCRIBE, + (size_t) 0, (dvoid **) 0)); + + /* if (OCITypeByName(envhp, errhp, svchp, (const text *)"", + (ub4) strlen(""), (const text *) type_name, + (ub4) strlen(type_name), + (CONST text *) 0, (ub4) 0, + OCI_DURATION_SESSION, OCI_TYPEGET_HEADER, + &at_tdo) != OCI_SUCCESS || !at_tdo) + { + (void) printf("Can not get type descriptor.\n"); + return; + } */ + + checkerr(errhp, OCIDescribeAny(svchp, errhp, (text *)type_name, + (ub4) strlen(type_name), OCI_OTYPE_NAME, (ub1)1, + (ub1) OCI_PTYPE_TYPE, dschp)); + + checkerr(errhp, OCIAttrGet((dvoid *) dschp, (ub4) OCI_HTYPE_DESCRIBE, + (dvoid *)&parmp, (ub4 *)0, (ub4)OCI_ATTR_PARAM, errhp)); + + checkerr(errhp, OCIAttrGet((dvoid*) parmp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &type_ref, (ub4 *) 0, + (ub4) OCI_ATTR_REF_TDO, (OCIError *) errhp)); + + checkerr(errhp, OCIObjectPin(envhp, errhp, type_ref, (OCIComplexObject *) 0, + OCI_PIN_ANY, OCI_DURATION_SESSION, OCI_LOCK_NONE, + (dvoid **)&at_tdo)); + + if (!at_tdo) + { + (void) printf("Can not get type descriptor.\n"); + return; + } + + if (OCITypeTypeCode(envhp, errhp, at_tdo) != OCI_TYPECODE_OBJECT) + (void) printf("The type is not name type.\n"); + + /* version name will be "$8.0" for future label */ + if (memcmp((const void *) OCITypeVersion(envhp, errhp, at_tdo, &text_len), + (const void *) "$8.0", text_len)) + (void) printf("return version is wrong.\n"); + + /* ---------- GET IMMEDIATE ATTRIBUTES IN A TYPE ---------- */ + + /* loop through all attributes in the type */ + count = OCITypeAttrs(envhp, errhp, at_tdo); + + if (OCITypeIterNew(envhp, errhp, at_tdo, &iterator) != OCI_SUCCESS) + (void) printf("BUG -- OCITypeIterNew, test return code OCI_SUCCESS.\n"); + + for (i = 0; OCITypeAttrNext(envhp, errhp, + iterator, &ado) != OCI_NO_DATA; i++) + { + /* get the attribute's name */ + (void) printf("Attribute # %d -- %s\n", i + 1, + OCITypeElemName(envhp, errhp, ado, &text_len)); + + /* get information about the attribute by name */ + if (OCITypeAttrByName(envhp, errhp, at_tdo, + OCITypeElemName(envhp, errhp, ado, &text_len), + text_len, &ado1) != OCI_SUCCESS) + (void) printf("Can not get attribute by name.\n"); + + /* get the attribute's type code */ + sqtcode = OCITypeElemExtTypeCode(envhp, errhp, ado); + (void) printf("The SQT code is %d.\n", sqtcode); + + /* get the attribute's type code */ + typecode = OCITypeElemTypeCode(envhp, errhp, ado); + + switch (typecode) + { + /* scalar types */ + case OCI_TYPECODE_DATE: /* date */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_DATE.\n"); + break; + case OCI_TYPECODE_SIGNED8: /* byte */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_SIGNED8.\n"); + break; + case OCI_TYPECODE_SIGNED16: /* short */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_SIGNED16.\n"); + break; + case OCI_TYPECODE_UNSIGNED8: /* unsigned byte */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_UNSIGNED8.\n"); + break; + case OCI_TYPECODE_UNSIGNED16: /* unsigned short */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_UNSIGNED16.\n"); + break; + case OCI_TYPECODE_OCTET: /* octet */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_OCTET.\n"); + break; + case OCI_TYPECODE_MLSLABEL: /* oracle mlslabel */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_MLSLABEL.\n"); + break; + case OCI_TYPECODE_CLOB: /* clob */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_CLOB.\n"); + break; + case OCI_TYPECODE_BLOB: /* blob */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_BLOB.\n"); + break; + case OCI_TYPECODE_CFILE: /* cfile */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_CFILE.\n"); + break; + case OCI_TYPECODE_BFILE: /* bfile */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_BFILE.\n"); + break; + /* number types */ + case OCI_TYPECODE_INTEGER: + (void) printf(" TYPE CODE -- OCI_TYPECODE_INTEGER.\n"); + break; + case OCI_TYPECODE_NUMBER: /* oracle number */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_NUMBER.\n"); + (void) printf(" Scale -- %d\n", + OCITypeElemNumScale(envhp, errhp, ado)); + break; + case OCI_TYPECODE_DECIMAL: /* decimal */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_DECIMAL.\n"); + (void) printf(" Scale -- %d\n", + OCITypeElemNumScale(envhp, errhp, ado)); + break; + + /* fall through to get the precision */ + case OCI_TYPECODE_FLOAT: /* float */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_FLOAT.\n"); + (void) printf(" Scale -- %d, Precision %d\n", + OCITypeElemNumScale(envhp, errhp, ado), + OCITypeElemNumPrec(envhp, errhp, ado) ); + break; + case OCI_TYPECODE_SIGNED32: /* long */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_SIGNED32.\n"); + (void) printf(" Scale -- %d, Precision %d\n", + OCITypeElemNumScale(envhp, errhp, ado), + OCITypeElemNumPrec(envhp, errhp, ado) ); + break; + case OCI_TYPECODE_UNSIGNED32: /* unsigned long */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_UNSIGNED32.\n"); + (void) printf(" Scale -- %d, Precision %d\n", + OCITypeElemNumScale(envhp, errhp, ado), + OCITypeElemNumPrec(envhp, errhp, ado) ); + break; + case OCI_TYPECODE_REAL: /* real */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_REAL.\n"); + (void) printf(" Scale -- %d, Precision %d\n", + OCITypeElemNumScale(envhp, errhp, ado), + OCITypeElemNumPrec(envhp, errhp, ado) ); + break; + case OCI_TYPECODE_DOUBLE: /* double */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_DOUBLE.\n"); + (void) printf(" Scale -- %d, Precision %d\n", + OCITypeElemNumScale(envhp, errhp, ado), + OCITypeElemNumPrec(envhp, errhp, ado) ); + break; + + /* string types */ + case OCI_TYPECODE_CHAR: /* fixed length string */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_CHAR.\n"); + (void) printf(" Character set id -- %d\n", + OCITypeElemCharSetID(envhp, errhp, ado)); + (void) printf(" String length -- %d\n", + OCITypeElemLength(envhp, errhp, ado)); + break; + case OCI_TYPECODE_VARCHAR2: /* variable length string */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_VARCHAR2.\n"); + (void) printf(" Character set id -- %d\n", + OCITypeElemCharSetID(envhp, errhp, ado)); + (void) printf(" String length -- %d\n", + OCITypeElemLength(envhp, errhp, ado)); + break; + case OCI_TYPECODE_VARCHAR: /* variable length string old */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_VARCHAR.\n"); + (void) printf(" Character set id -- %d\n", + OCITypeElemCharSetID(envhp, errhp, ado)); + (void) printf(" String length -- %d\n", + OCITypeElemLength(envhp, errhp, ado)); + break; + case OCI_TYPECODE_RAW: /* raw */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_RAW.\n"); + (void) printf(" String length -- %d\n", + OCITypeElemLength(envhp, errhp, ado)); + break; + + /* parameterized types */ + case OCI_TYPECODE_VARRAY: /* variable array */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_VARRAY.\n"); + if ( OCITypeElemParameterizedType(envhp, errhp, + ado, &tdo_stored) != OCI_SUCCESS ) + (void) printf( + "Error -- can not get parameterized types's descriptor.\n"); + (void) printf(" Array elements type code -- %d\n", + OCITypeTypeCode(envhp, errhp, tdo_stored)); + break; + + case OCI_TYPECODE_REF: /* reference */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_REF.\n"); + if ( OCITypeElemParameterizedType(envhp, errhp, + ado, &tdo_stored) != OCI_SUCCESS ) + (void) printf( + "Error -- can not get parameterized types's descriptor.\n"); + (void) printf(" Array elements type code -- %d\n", + OCITypeTypeCode(envhp, errhp, tdo_stored)); + break; + case OCI_TYPECODE_PTR: /* pointer */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_PTR.\n"); + if ( OCITypeElemParameterizedType(envhp, errhp, + ado, &tdo_stored) != OCI_SUCCESS ) + (void) printf( + "Error -- can not get parameterized types's descriptor.\n"); + (void) printf(" Array elements type code -- %d\n", + OCITypeTypeCode(envhp, errhp, tdo_stored)); + break; + + case OCI_TYPECODE_NAMEDCOLLECTION: /* domain type */ + (void) printf(" TYPE CODE -- OCI_TYPECODE_NAMEDCOLLECTION.\n"); + if ( OCITypeElemType( envhp, errhp, ado, &attr_tdo) == OCI_SUCCESS ) + { + switch (OCITypeCollTypeCode(envhp, errhp, attr_tdo)) + { + case OCI_TYPECODE_VARRAY: /* variable array */ + + (void) printf(" SUBTYPE CODE -- OCI_TYPECODE_VARRAY.\n"); + + if (OCITypeCollSize(envhp, errhp, + attr_tdo, &num_elems) != OCI_SUCCESS) + (void) printf( + "Error -- can not get collectio type element count.\n"); + (void) printf("The number of elements are %d.\n", num_elems); + + /* test error code for OCITypeCollElem */ + /* get the ado of the array */ + element = (OCITypeElem *)0; + if (OCITypeCollElem(envhp, errhp, + attr_tdo, &element) != OCI_SUCCESS) + (void) printf( + "Error -- can not get descriptor to an element's descriptor.\n"); + + /* get the type of the array */ + if (ortgcty(envhp, errhp, attr_tdo, &element_type) != OCI_SUCCESS) + (void) printf( + "Error -- can not get element's type descriptor.\n"); + (void) printf(" The type code for array is %d.\n", + OCITypeTypeCode(envhp, errhp, element_type) ); + + if (OCITypeCollExtTypeCode(envhp, errhp, + attr_tdo, &sqtcode) != OCI_SUCCESS) + (void) printf("Error -- can not get element's sql code.\n"); + (void) printf(" The SQT code for array is %d.\n", sqtcode ); + break; + + case OCI_TYPECODE_TABLE: /* multiset */ + + (void) printf(" SUBTYPE CODE -- OCI_TYPECODE_TABLE.\n"); + /* get the type of the multiset */ + if (ortgcty(envhp, errhp, attr_tdo, &table_type) != OCI_SUCCESS) + (void) printf("Error -- can not get the type of a multiset.\n"); + (void) printf(" The type code for the multiset is %d.\n", + OCITypeTypeCode(envhp, errhp, table_type) ); + + break; + } + } + else + (void) printf( + " Error -- OCITypeElemType, test return code OCI_SUCCESS.\n"); + break; + + /* abstract type */ + case OCI_TYPECODE_OBJECT: /* abstract data type */ + if ( OCITypeElemType( envhp, errhp, ado, &attr_tdo) == OCI_SUCCESS ) + { + if ( OCITypeTypeCode(envhp, errhp, attr_tdo)!=OCI_TYPECODE_OBJECT ) + (void) printf(" Error -- expect type code OCI_TYPECODE_OBJECT.\n"); + } + else + (void) printf(" Error -- can not get attribute tdo.\n"); + (void) printf(" TYPE CODE -- OCI_TYPECODE_OBJECT.\n"); + break; + + default: + (void) printf("Error: invalid type code\n"); + break; + } /* end of typecode switch */ + + } + + + /* ------------ GET THE IMMEDIATE METHODS OF A TYPE ------------ */ + + count = OCITypeMethods(envhp, errhp, at_tdo); + + /* ----------------- GET THE MAP FUNCTION ----------------- */ + /* MAP method cannot be created yet */ + if ( OCITypeMethodMap(envhp, errhp, at_tdo, &mdo) == OCI_SUCCESS ) + (void) printf("Error -- can not get the map function.\n"); + if (mdo != (OCITypeMethod *)0) + (void) printf("Map method name -- %s.\n", + OCITypeMethodName(envhp, errhp, mdo, &text_len)); + + /* ----------------- GET THE ORDER FUNCTION ----------------- */ + /* MAP method cannot be created yet */ + if ( OCITypeMethodOrder(envhp, errhp, at_tdo, &mdo) == OCI_SUCCESS ) + (void) printf("Error -- can not get map method's mdo.\n"); + if (mdo != (OCITypeMethod *)0) + (void) printf("Order method name -- %s.\n", + OCITypeMethodName(envhp, errhp, mdo, &text_len)); + + + /* ----------- LOOP THROUGH ALL METHODS IN A TYPE ----------- */ + + (void) printf("Number of methods -- %d\n", count); + for (i = 0; OCITypeMethodNext(envhp, errhp, + iterator, &mdo) != OCI_NO_DATA; i++) + { + if (OCITypeResult(envhp, errhp, mdo, &rdo) != OCI_SUCCESS) + (void) printf("BUG -- OCITypeResult, test return code OCI_SUCCESS.\n"); + + + /* get the typecode of the method's result */ + typecode = OCITypeElemTypeCode(envhp, errhp, rdo); + + meth_name = OCITypeMethodName(envhp, errhp, mdo, &text_len); + (void) printf("\nMethod name -- %s, Type code: %d, Position: %d.\n", + meth_name, typecode, i); + + if (OCITypeMethodByName(envhp, errhp, at_tdo, (CONST text *) meth_name, + (ub4) strlen((const char *) meth_name), + &mdoPtr_array) != OCI_SUCCESS) + (void) printf( + "Error -- OCITypeMethodByName, test return code OCI_SUCCESS.\n"); + + /* Get method's return parameter */ + if (OCITypeResult(envhp, errhp, mdo, &rdo) != OCI_SUCCESS) + (void) printf("Error -- ortgrbp, test return code OCI_SUCCESS.\n"); + + /* find out how many methods exist with this name */ + om_count = OCITypeMethodOverload(envhp, errhp, at_tdo, + (CONST text *) meth_name, + (ub4) strlen((const char *) meth_name)); + (void) printf("Number of overloaded methods for %s -- %d\n", + meth_name, om_count); + + print_method_positions(meth_name, methpos, om_count); + + /* get the method's encapsulation */ + if (OCITypeMethodEncap(envhp, errhp, mdo) != OCI_TYPEENCAP_PUBLIC) + (void) printf("Error -- wrong method's encapsulation.\n"); + + /* ------------ GET THE PARAMETERS IN A METHOD ------------ */ + + /* loop through all parameters in the method */ + pcount = OCITypeMethodParams(envhp, errhp, mdo); + (void) printf("Number of parameter's in method -- %d\n", pcount); + + for (j = 1; j <= pcount; j++) + { + /* get the parameter information by position */ + if (OCITypeParamByPos(envhp, errhp, mdo, j, &pdo) != OCI_SUCCESS) + (void) printf( + "Error -- OCITypeParamByPos, test return code OCI_SUCCESS.\n"); + + /* put the parameter's number */ + (void) printf("Parameter's number -- %d\n.", j); + + /* get the parameter's name */ + pname = OCITypeElemName(envhp, errhp, pdo, &text_len); + (void) printf("Parameter's name -- %s\n.", pname); + + /* get a parameter in a method by name */ + if (OCITypeParamByName(envhp, errhp, mdo, (CONST text *) pname, (ub4) + strlen((const char *) pname), &pdo) != OCI_SUCCESS) + (void) printf( + "Error -- OCITypeParamByName, test return code OCI_SUCCESS.\n"); + + if (OCITypeParamPos(envhp, errhp, mdo, (CONST text *) pname, + (ub4) strlen((const char *)pname), + &pos, &pdo) != OCI_SUCCESS) + (void) printf( + "Error -- OCITypeParamPos, test return code OCI_SUCCESS.\n"); + /* check the position */ + if (pos != j) + (void) printf("Error -- wrong attribute position.\n"); + + /* get the parameter's mode */ + (void) printf( + "Parameter's mode -- %d\n.", OCITypeElemParamMode(envhp, errhp, pdo)); + + /* get the parameter's required flag */ + OCI_TYPEPARAM_IS_REQUIRED(OCITypeElemFlags(envhp, errhp, pdo)) ? + (void) printf("parameter's required flag is TRUE -- %d\n.", + OCITypeElemParamMode(envhp, errhp, pdo)): + (void) printf("parameter's required flag is FALSE -- %d\n.", + OCITypeElemParamMode(envhp, errhp, pdo)); + if ( OCITypeElemType(envhp, errhp, pdo, ¶m_tdo) == OCI_SUCCESS ) + (void) printf(" Parameter type code -- %d\n", + OCITypeTypeCode(envhp, errhp, param_tdo)); + + /* got to verify with Zona if default value is working */ + text_value = OCITypeElemDefaultValue( envhp, errhp, pdo, &text_len); + if (text_len) + (void) printf(" Parameter default value -- %s\n", text_value); + } + + } /* end methods for loop */ + + +} + +/*****************************************************************************/ +int main(int argc, char *argv[]) +{ + OCIEnv *envhp; + OCIServer *srvhp; + OCIError *errhp; + OCISvcCtx *svchp; + OCISession *usrhp; + dvoid *tmp; + int i; + + + if (argc < 4) + { + (void) printf( + "Usage -- cdemort \n"); + return (0); + } + /* initialize the process */ + OCIInitialize((ub4) OCI_THREADED | OCI_OBJECT, + (dvoid *)0, (dvoid * (*)()) 0, + (dvoid * (*)()) 0, (void (*)()) 0 ); + /* initialize the environment handle */ + (void) OCIEnvInit( &envhp, (ub4) OCI_DEFAULT, 21, (dvoid **) &tmp ); + /* get the error handle */ + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, + 52, (dvoid **) &tmp); + /* two server contexts */ + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, + 52, (dvoid **) &tmp); + /* attach to the server */ + (void) OCIServerAttach( srvhp, errhp, (text *) "", + (sb4) 0, (ub4) OCI_DEFAULT); + /* get the service handle */ + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, + 52, (dvoid **) &tmp); + + /* set attribute server context in the service context */ + (void) OCIAttrSet( (dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, + (ub4) OCI_ATTR_SERVER, (OCIError *) errhp); + /* get the user handle */ + (void) OCIHandleAlloc((dvoid *)envhp, (dvoid **)&usrhp, + (ub4)OCI_HTYPE_SESSION, 0, (dvoid **)0); + /* set the user name attribute */ + (void) OCIAttrSet((dvoid *) usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)argv[1], (ub4)strlen(argv[1]), + (ub4)OCI_ATTR_USERNAME, errhp); + /* set the password attribute */ + (void) OCIAttrSet((dvoid *) usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)argv[2], (ub4)strlen(argv[2]), + (ub4)OCI_ATTR_PASSWORD, errhp); + /* Authenticate */ + checkerr(errhp, OCISessionBegin (svchp, errhp, usrhp, + OCI_CRED_RDBMS, OCI_DEFAULT)); + /* set the user context attribute */ + (void) OCIAttrSet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)usrhp, (ub4)0, + (ub4)OCI_ATTR_SESSION, errhp); + /* loop through all the types */ + for (i = 3; i < argc; i++) { + /* dump an adt with all the types */ + (void) printf(" %s\n", argv[i]); + unit_test_type_access(envhp, errhp, svchp, argv[i]); + } + + checkerr(errhp, OCISessionEnd (svchp, errhp, usrhp, OCI_DEFAULT)); + /* dettach the server */ + (void) OCIServerDetach( srvhp, errhp, (ub4) OCI_DEFAULT ); + checkerr(errhp, OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX)); + checkerr(errhp, OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR)); + checkerr(errhp, OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER)); + + return (0); +} + + diff --git a/cdemort.h b/cdemort.h new file mode 100644 index 0000000..00a9e1b --- /dev/null +++ b/cdemort.h @@ -0,0 +1,75 @@ +/* + * $Header: cdemort.h 14-jul-99.12:52:18 mjaeger Exp $ + */ + +/* Copyright (c) 1995, 1999, Oracle Corporation. All rights reserved. +*/ + +/* + NAME + cdemort.h + + DESCRIPTION + This file contains the header information for the cdemort.c + + RELATED DOCUMENTS + None. + + INSPECTION STATUS + Inspection date: + Inspection status: + Estimated increasing cost defects per page: + Rule sets: + + ACCEPTANCE REVIEW STATUS + Review date: + Review status: + Reviewers: + + PUBLIC FUNCTION(S) + None. + + PRIVATE FUNCTION(S) + As defined below. + + EXAMPLES + + NOTES + + MODIFIED (MM/DD/YY) + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + echen 11/15/96 - oci beautification + dchatter 07/18/96 - delete spurious .h files + echen 08/07/95 - Creation +*/ + +#ifndef CDEMO_OBJ_ORACLE +#define CDEMO_OBJ_ORACLE + +#ifndef OCI_ORACLE +#include +#endif + + +/*--------------------------------------------------------------------------- + PUBLIC TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ +#define RUNTEST TRUE +#define USERNAME "internal" +#define SERVER "ORACLE" +#define SCHEMA "SYS" +#define ADDRESS_TYPE_NAME "ADDRESS_OBJECT" +#define RETURN_ON_ERROR(error) if (error) return (error) + +static void unit_test_type_access(/*_ OCIEnv *envhp, OCIError *errhp, + OCISvcCtx *svchp, char *type_name _*/); + +int main(/*_ int argc, char *argv[] _*/); + +#endif /* CDEMO_OBJ_ORACLE */ + diff --git a/cdemosc.c b/cdemosc.c new file mode 100644 index 0000000..e8895ca --- /dev/null +++ b/cdemosc.c @@ -0,0 +1,390 @@ +/* Copyright (c) 2001, Oracle Corporation. All rights reserved. */ + +/* + + NAME + cdemosc.c - OCI demo program for scrollable cursor. + + DESCRIPTION + An example program which reads employee records from table empo. + SQL> describe empo; + Name Null? Type + ------------------------- -------- --------------- + EMPNO NUMBER + ENAME CHAR(5) + ADDR EMPADDR + ECOLL EVARRAY + SQL> describe empaddr; + Name Null? Type + ------------------------- -------- --------------- + STATE CHAR(2) + ZIP NUMBER + + EXPORT FUNCTION(S) + + + INTERNAL FUNCTION(S) + + + STATIC FUNCTION(S) + + + NOTES + Dependent Files: + cdemosc.sql - SQL script to be run before execution. + + MODIFIED (MM/DD/YY) + ani 04/30/01 - Merged ani_ocidemo + ani 04/24/01 - Creation + +*/ + +#include +#include +#include + +#ifndef OCI_ORACLE +#include +#endif + +typedef struct address +{ + OCIString * state ; + OCINumber zip; +} address ; + +typedef struct null_address +{ + sb2 null_state ; + sb2 null_zip; +} null_address ; + + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + +#define MAXROWS 3 +#define MAX_ENAMELEN 20 + +static text *username = (text *) "scott"; +static text *password = (text *) "tiger"; + +/* Define SQL statements to be used in program. */ +static text *selemp = (text *)"SELECT empno, ename, addr, ecoll FROM empo"; + +static sword empno[MAXROWS] ; +static text empname[MAXROWS][MAX_ENAMELEN]; +static address * empaddr [MAXROWS] ; +static null_address * indaddr [MAXROWS] ; +static ub4 rc[MAXROWS] ; +static OCIColl * evarray[MAXROWS] ; +static OCIEnv *envhp; +static OCIError *errhp; +static OCISvcCtx *svchp; +static sword status; +static OCIStmt *stmthp; +static sword status; + +/*--------------------------------------------------------------------------- + STATIC FUNCTION DECLARATIONS + ---------------------------------------------------------------------------*/ + +static void checkerr(/*_ OCIError *errhp, sword status _*/); +static void checkprint(/*_ OCIError *errhp, sword status, ub4 nrows _*/); +static void cleanup(/*_ void _*/); +static void myprint (/*_ ub4 _*/); +int main(/*_ int argc, char *argv[] _*/); + + +int main(argc, argv) +int argc; +char *argv[]; +{ + + OCISession *authp = (OCISession *) 0; + OCIServer *srvhp; + OCISvcCtx *svchp; + OCIType * addr_tdo ; + OCIType * addr_tdo2 ; + ub4 empaddrsz ; + OCIDefine *defn1p = (OCIDefine *) 0; + OCIDefine *defn2p = (OCIDefine *) 0; + OCIDefine *defn3p = (OCIDefine *) 0; + OCIDefine *defn4p = (OCIDefine *) 0; + OCIDefine *defn5p = (OCIDefine *) 0; + int num ; + + ub4 prefetch = 5 ; + + (void) OCIInitialize((ub4) OCI_DEFAULT | OCI_OBJECT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 ); + + (void) OCIEnvInit( (OCIEnv **) &envhp, OCI_DEFAULT, (size_t) 0, + (dvoid **) 0 ); + + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + + /* server contexts */ + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, OCI_HTYPE_SERVER, + (size_t) 0, (dvoid **) 0); + + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, OCI_HTYPE_SVCCTX, + (size_t) 0, (dvoid **) 0); + + (void) OCIServerAttach( srvhp, errhp, (text *)"", (sb4) strlen(""), 0); + + /* set attribute server context in the service context */ + (void) OCIAttrSet( (dvoid *) svchp, OCI_HTYPE_SVCCTX, (dvoid *)srvhp, + (ub4) 0, OCI_ATTR_SERVER, (OCIError *) errhp); + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **)&authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0); + + (void) OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) username, (ub4) strlen((char *)username), + (ub4) OCI_ATTR_USERNAME, errhp); + + (void) OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) password, (ub4) strlen((char *)password), + (ub4) OCI_ATTR_PASSWORD, errhp); + + checkerr(errhp, OCISessionBegin ( svchp, errhp, authp, OCI_CRED_RDBMS, + (ub4) OCI_DEFAULT)); + + (void) OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) authp, (ub4) 0, + (ub4) OCI_ATTR_SESSION, errhp); + + checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp, + OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0)); + + + /**** SCROLLABLE RESULT SET *****/ + + /* Retrieve the employee records */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, selemp, + (ub4) strlen((char *) selemp), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); + (void) OCIAttrSet((dvoid *) stmthp, (ub4) OCI_HTYPE_STMT, + (dvoid *) & prefetch, 0, + (ub4) OCI_ATTR_PREFETCH_ROWS, errhp); + + /* bind the input variable */ + checkerr(errhp, OCIDefineByPos(stmthp, &defn1p, errhp, 1, (dvoid *) empno, + (sword) sizeof(sword), SQLT_INT, (dvoid *) 0, (ub2 *)0, + (ub2 *)0, OCI_DEFAULT)); + checkerr(errhp, OCIDefineByPos(stmthp, &defn2p, errhp, 2, (dvoid **) empname, + (sword) MAX_ENAMELEN, SQLT_STR, (dvoid *) 0, (ub2 *)0, + (ub2 *)0, OCI_DEFAULT)); + + checkerr(errhp, OCITypeByName(envhp, errhp, svchp, (const text *) 0, + (ub4) 0, (const text *) "EMPADDR", + (ub4) strlen((const char *) "EMPADDR"), + (CONST text *) 0, (ub4) 0, + OCI_DURATION_SESSION, OCI_TYPEGET_ALL, + &addr_tdo)); + + checkerr(errhp, OCIDefineByPos(stmthp, &defn3p, errhp, 3, (dvoid *) 0, + (sword) 0, SQLT_NTY, (dvoid *) 0, (ub2 *)0, + (ub2 *)0, OCI_DEFAULT)); + checkerr(errhp, OCIDefineObject(defn3p, errhp, addr_tdo, (dvoid **) empaddr, + (ub4 *) & empaddrsz, (dvoid **) indaddr, (ub4 *) rc)); + + checkerr(errhp, OCITypeByName(envhp, errhp, svchp, (const text *) 0, + (ub4) 0, (const text *) "EVARRAY", + (ub4) strlen((const char *) "EVARRAY"), + (CONST text *) 0, (ub4) 0, + OCI_DURATION_SESSION, OCI_TYPEGET_ALL, + &addr_tdo2)); + checkerr(errhp, OCIDefineByPos(stmthp, &defn4p, errhp, 4, (dvoid *) 0, + (sword) 0, SQLT_NTY, (dvoid *) 0, (ub2 *)0, + (ub2 *)0, OCI_DEFAULT)); + checkerr(errhp, OCIDefineObject(defn4p, errhp, addr_tdo2, (dvoid **) evarray, + (ub4 *) 0, (dvoid **) 0, (ub4 *) 0)); + + checkprint(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 0, (ub4) + 0, (CONST OCISnapshot *) + NULL, (OCISnapshot *) NULL, + OCI_STMT_SCROLLABLE_READONLY ),0); + + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 3, + OCI_FETCH_ABSOLUTE, (sb4) 6, OCI_DEFAULT),3); + + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 3, + OCI_FETCH_RELATIVE, (sb4) -2, OCI_DEFAULT),3); + + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 2, + OCI_FETCH_ABSOLUTE, (sb4) 9, OCI_DEFAULT),2); + + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 1, + OCI_FETCH_LAST, (sb4) 0, OCI_DEFAULT),1); + + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 1, + OCI_FETCH_FIRST, (sb4) 0, OCI_DEFAULT),1); + + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 1, + OCI_FETCH_LAST, (sb4) 0, OCI_DEFAULT),1); + + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 1, + OCI_FETCH_FIRST, (sb4) 0, OCI_DEFAULT),1); + + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 1, + OCI_FETCH_ABSOLUTE, (sb4) 15, OCI_DEFAULT),1); + + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 2, + OCI_FETCH_NEXT, (sb4) 0, OCI_DEFAULT),2); + + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 1, + OCI_FETCH_PRIOR, (sb4) 0, OCI_DEFAULT),1); + + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 3, + OCI_FETCH_RELATIVE, (sb4) -8, OCI_DEFAULT),3); + + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 2, + OCI_FETCH_NEXT, (sb4) 0, OCI_DEFAULT),2); + + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 1, + OCI_FETCH_FIRST, (sb4) 0, OCI_DEFAULT),1); + + /* cancel the statement handle - and free resources on client and server */ + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 0, + OCI_FETCH_NEXT, (sb4) 0, OCI_DEFAULT),0); + + /* this should result in some error */ + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 1, + OCI_FETCH_NEXT, (sb4) 0, OCI_DEFAULT),1); + + /* re-execute in the non-scrollable mode */ + checkprint(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 3, (ub4) + 0, (CONST OCISnapshot *) + NULL, (OCISnapshot *) NULL, + 0),3); + + /* this should result in error */ + checkprint(errhp, OCIStmtFetch2(stmthp, errhp, (ub4) 1, + OCI_FETCH_ABSOLUTE, (sb4) 4, OCI_DEFAULT),1); + cleanup() ; + + return 1; +} + + +/*check fetch status and print rows upon success*/ +void checkprint(errhp, status,nrows) +OCIError *errhp; +sword status; +ub4 nrows; +{ + checkerr(errhp,status); + if (status != OCI_ERROR && status != OCI_NO_DATA) + myprint(nrows); +} + + +/*check status and print error information */ +void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", 512, errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} + + +/* + * Exit program with an exit code. + */ +void cleanup() +{ + if (envhp) + (void) OCIHandleFree((dvoid *) envhp, OCI_HTYPE_ENV); + return; +} + + +/*void myfflush() +{ + eb1 buf[50]; + + fgets((char *) buf, 50, stdin); +}*/ + + +/*print rows*/ +void myprint (ub4 nrows) +{ + int i, j, num, cp, rc, amount ; + sb4 colsz; + void * elem ; + ub4 sz = sizeof(cp) ; + boolean exist = FALSE; + + checkerr(errhp, OCIAttrGet((CONST void *) stmthp, OCI_HTYPE_STMT, + (void *) & cp, (ub4 *) & sz, + OCI_ATTR_CURRENT_POSITION, errhp)); + checkerr(errhp, OCIAttrGet((CONST void *) stmthp, OCI_HTYPE_STMT, + (void *) & rc, (ub4 *) & sz, + OCI_ATTR_ROW_COUNT, errhp)); + printf("******** Current position, Row Count = %d, %d ******** \n", cp, rc); + + for (i =0 ; i < nrows ; i++ ) + { + OCINumberToInt(errhp, & empaddr[i]->zip, sizeof(num), + OCI_NUMBER_SIGNED, (void *) & num); + printf("\n %d %s %s %d ", empno[i], empname[i], + OCIStringPtr(envhp, empaddr[i]->state), num); + + colsz = OCICollMax (envhp, (OCIColl *) evarray[i]) ; + for (j = 0; j < colsz ; j++) + { + OCICollGetElem (envhp, errhp, (OCIColl *) evarray[i], j, & exist, + (void **) & elem, (void **) 0); + if (!exist) + printf(" *** error - coll, row %d col-elem %d ", i, j); + else { + checkerr(errhp, OCINumberToInt(errhp, (OCINumber *) elem, + sizeof(int), OCI_NUMBER_SIGNED, & num)); + printf("%d ", num); + } + } + printf ("\n"); + } +} + +/* end of file cdemosc.c */ + diff --git a/cdemosc.sql b/cdemosc.sql new file mode 100644 index 0000000..4dc2793 --- /dev/null +++ b/cdemosc.sql @@ -0,0 +1,80 @@ +Rem +Rem $Header: cdemosc.sql 03-may-2001.17:06:41 jchai Exp $ +Rem +Rem cdemosc.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem cdemosc.sql - Demo program for scrollable cursor. +Rem +Rem DESCRIPTION +Rem SQL script to prepare table empo and data in the table. +Rem +Rem NOTES +Rem Neet to run before cdemosc. +Rem +Rem MODIFIED (MM/DD/YY) +Rem jchai 05/03/01 - connect as scott/tiger +Rem ani 04/30/01 - Merged ani_ocidemo +Rem ani 04/24/01 - Created +Rem + +connect scott/tiger; +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +drop table empo +/ +drop type evarray +/ +drop type empaddr +/ + +create or replace type empaddr as object ( + state char(2) , + zip number ) +/ + +create or replace type evarray is VARRAY(2) of number +/ + +create table empo (empno number, + ename char(5), + addr empaddr, + ecoll evarray) +/ + +insert into empo values (1, 'abc1', empaddr('ca', 94061), evarray(13,145)) +/ +insert into empo values (2, 'abc2', empaddr('ca', 94062), evarray(23,245)) +/ +insert into empo values (3, 'abc3', empaddr('ca', 94063), evarray(33,345)) +/ +insert into empo values (4, 'abc4', empaddr('ca', 94064), evarray(43,445)) +/ +insert into empo values (5, 'abc5', empaddr('ca', 94065), evarray(53,545)) +/ +insert into empo values (6, 'abc6', empaddr('ca', 94066), evarray(63,645)) +/ +insert into empo values (7, 'abc7', empaddr('ca', 94067), evarray(73,745)) +/ +insert into empo values (8, 'abc8', empaddr('ca', 94068), evarray(83,85)) +/ +insert into empo values (9, 'abc9', empaddr('ca', 94069), evarray(93,95)) +/ +insert into empo values (10, 'abc10', empaddr('ca', 94060), evarray(103,1045)) +/ +insert into empo values (11, 'abc11', empaddr('ca', 94070), evarray(113,1045)) +/ +insert into empo values (12, 'abc12', empaddr('ca', 94071), evarray(123,1045)) +/ +insert into empo values (13, 'abc13', empaddr('ca', 94072), evarray(133,1045)) +/ +insert into empo values (14, 'abc14', empaddr('ca', 94073), evarray(143,1045)) +/ diff --git a/cdemoses.c b/cdemoses.c new file mode 100644 index 0000000..59f6da6 --- /dev/null +++ b/cdemoses.c @@ -0,0 +1,553 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemoses.c 08-dec-2000.12:35:31 lchidamb Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1998, 1999, Oracle Corporation. All rights reserved. +*/ + +/* + + NAME + cdemoses.c - C Demo program to illustrate Session Management + + DESCRIPTION + This program Illustrates the following functionality: + (1) Session Switching + Session Switching allows applications to multiplex several users + over the same connection. This allows apps to multiplex several + sessions over one connection without losing the database privilege + and security features. + + a) Create One Connection + b) Create 10 sessions + c) Switch one session after another followed by SELECT USER FROM DUAL + + (2) Session Migration + Session Migration lets applications move sessions across connections. + With this feature, the application can move sessions around + dynamically based on system load and the application could implement + its own application level user priority scheme. + + a) Create Two Connections + b) Create 10 migratable sessions on first connection + c) Switch one session after another followed by SELECT USER FROM DUAL + On first connection. + b) Migrate sessions to second connection and SEKECT USER FROM DUAL + + NOTES + + IMPORTANT!!!! + TO RUN THIS DEMOS, YOU NEED TO RUN cdemoses.sql + IMPORTANT!!!! + + + MODIFIED (MM/DD/YY) + lchidamb 12/08/00 - lint + lchidamb 12/05/00 - remove DISCARD + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + lchidamb 10/14/98 - Add Migration Demo + lchidamb 10/13/98 - Session Management Demo + lchidamb 10/13/98 - Creation + +*/ + +/*---------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include + +#define EX_FAILURE -1 +#define NUM_USERS 10 +char *user[NUM_USERS] = +{ "user0", + "user1", + "user2", + "user3", + "user4", + "user5", + "user6", + "user7", + "user8", + "user9"}; + +/* this statement is executed by all sessions */ +char stmt[] = "SELECT USER FROM DUAL"; + +/* global username array: keeps track of current user session */ +char username[100]; + +/* length of username */ +ub2 userlen; + +/* indicator for username */ +sb2 userind; + +int main () +{ + sword retval = 0; + ub2 i; + OCIEnv *envhp; + OCIError *errhp; + OCIServer *srvhp; + OCIServer *srvhp1; + OCISession *userhp[10]; + OCISession *primary, *primary1; + OCIStmt *stmhp; + + /* Initialize OCI Process and Initialize Environment and Error handles */ + initialize_main(&envhp, &errhp); + + /* Initialize Server handle */ + initialize_server(envhp, errhp, &srvhp); + + + /************************* SESSION SWITCHING DEMO **************************/ + fprintf(stdout, "----------SESSION SWITCHING DEMO-----------------------\n"); + /* Initialize Users */ + for(i = 0; i < NUM_USERS; i++) + initialize_user(envhp, errhp, srvhp, &userhp[i], user[i]); + + /* Initialize Statement */ + initialize_statement(envhp, errhp, &stmhp); + + /* Switch Sessions and Execute Statements */ + for(i = 0; i < NUM_USERS; i++) + { + fprintf(stdout, "SWITCHING SESSION to %s\n", user[i]); + execute_statement(envhp, errhp, userhp[i], srvhp, stmhp); + } + + /* Switch Sessions and Terminate Users */ + for(i = 0; i < NUM_USERS; i++) + { + fprintf(stdout, "SWITCHING SESSION to %s\n", user[i]); + terminate_user(envhp, errhp, srvhp, userhp[i]); + } + + fprintf(stdout, "\n\n\n"); + /************************* SESSION MIGRATION DEMO **************************/ + fprintf(stdout, "----------SESSION MIGRATION DEMO-----------------------\n"); + /* Initialize Another Server handle */ + initialize_server(envhp, errhp, &srvhp1); + + /* Initialize non-migratable primary session on both servers */ + initialize_user(envhp, errhp, srvhp, &primary, "primary"); + initialize_user(envhp, errhp, srvhp1,&primary1, "primary"); + + + /* Initialize Migratable Users on First Server */ + for(i = 0; i < NUM_USERS; i++) + initialize_migratable_user(envhp, errhp, srvhp, primary, + &userhp[i], user[i]); + + /* Switch Sessions and Execute Statements on First Server */ + for(i = 0; i < NUM_USERS; i++) + { + fprintf(stdout, "SWITCHING SESSION to %s\n", user[i]); + execute_statement(envhp, errhp, userhp[i], srvhp, stmhp); + } + + + /* + * Oops, Imagine first connection is too loaded, lets move all + * users to the second connection and leave the first connection + * for doing some long operation. + */ + + fprintf(stdout, "\n--------MIGRATING ALL SESSIONS to SERVER2------------\n"); + /* Switch Sessions and Execute Statements on Second Server */ + for(i = 0; i < NUM_USERS; i++) + { + fprintf(stdout, "MIGRATING SESSION %s to SERVER2\n", user[i]); + execute_statement(envhp, errhp, userhp[i], srvhp1, stmhp); + } + + /* Terminate Statement */ + terminate_statement(stmhp); + + /* Migrate Sessions Back to Server1 and Terminate Users */ + fprintf(stdout, "\n-------MIGRATING ALL SESSIONS BACK to SERVER1--------\n"); + for(i = 0; i < NUM_USERS; i++) + { + fprintf(stdout, "MIGRATING SESSION %s BACK TO SERVER1\n", user[i]); + terminate_user(envhp, errhp, srvhp, userhp[i]); + } + + fprintf(stdout, "\n------TERMINATING PRIMARY SESSIONS-------------------\n"); + terminate_user(envhp, errhp, srvhp, primary); + terminate_user(envhp, errhp, srvhp1, primary1); + + /* Terminate Servers */ + terminate_server(errhp, srvhp); + terminate_server(errhp, srvhp1); + + /* Terminate Main */ + terminate_main(envhp, errhp); + return 0; +} + + +/* initialize_user */ +void initialize_user(envhp, errhp, srvhp, userhpp, name) +OCIEnv *envhp; +OCIError *errhp; +OCIServer *srvhp; +OCISession **userhpp; +char *name; +{ + OCISvcCtx *svchp; + + fprintf (stdout, "Authentication for %s is progress...0\n", name); + + /* Temporary Service Context */ + if (OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS ) + { + fprintf(stdout, "Fail to OCIHandleAlloc for service handle..."); + terminate_main(envhp, errhp); + exit(EX_FAILURE); + } + + if (OCIHandleAlloc( (dvoid *) envhp, (dvoid **) userhpp, + (ub4) OCI_HTYPE_SESSION, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS ) + { + fprintf(stdout, "Fail to OCIHandleAlloc for user handle..."); + terminate_main(envhp, errhp); + exit(EX_FAILURE); + } + + + + /* Set the server handle in service handle */ + if (OCIAttrSet (svchp, OCI_HTYPE_SVCCTX, srvhp, 0, + OCI_ATTR_SERVER, errhp) != OCI_SUCCESS) + error_report(errhp, "initialize_user - OCIAttrSet"); + + /* set the username/password in user handle */ + if (OCIAttrSet(*userhpp, OCI_HTYPE_SESSION, name, strlen(name), + OCI_ATTR_USERNAME, errhp) != OCI_SUCCESS) + error_report(errhp, "initialize_user - OCIAttrSet"); + + if (OCIAttrSet(*userhpp, OCI_HTYPE_SESSION, name, strlen(name), + OCI_ATTR_PASSWORD, errhp) != OCI_SUCCESS) + error_report(errhp, "initialize_user - OCIAttrSet"); + + /* Authenticate */ + if (OCISessionBegin (svchp, errhp, *userhpp, + OCI_CRED_RDBMS, OCI_DEFAULT) != OCI_SUCCESS) + error_report(errhp, "initialize_user - ocisauth"); + + /* Free Temporary Service Context */ + (void) OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX); + + fprintf (stdout, "Authentication for %s successful.\n", name); +} + + +/* initialize_migratable_user */ +void initialize_migratable_user(envhp, errhp, srvhp, primary, userhpp, name) +OCIEnv *envhp; +OCIError *errhp; +OCIServer *srvhp; +OCISession *primary; +OCISession **userhpp; +char *name; +{ + OCISvcCtx *svchp; + + fprintf (stdout, "Authentication for %s is progress...0\n", name); + + /* Temporary Service Context */ + if (OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS ) + { + fprintf(stdout, "Fail to OCIHandleAlloc for service handle..."); + terminate_main(envhp, errhp); + exit(EX_FAILURE); + } + + /* Set the Primary Session handle in the service handle */ + if (OCIAttrSet(svchp, OCI_HTYPE_SVCCTX, primary, 0, + OCI_ATTR_SESSION, errhp) != OCI_SUCCESS) + error_report(errhp, "conn2serv - OCIAttrSet"); + + /* Set the server handle in service handle */ + if (OCIAttrSet (svchp, OCI_HTYPE_SVCCTX, srvhp, 0, + OCI_ATTR_SERVER, errhp) != OCI_SUCCESS) + error_report(errhp, "conn2serv - OCIAttrSet"); + + if (OCIHandleAlloc( (dvoid *) envhp, (dvoid **) userhpp, + (ub4) OCI_HTYPE_SESSION, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS ) + { + fprintf(stdout, "Fail to OCIHandleAlloc for user handle..."); + terminate_main(envhp, errhp); + exit(EX_FAILURE); + } + + /* set the username/password in user handle */ + if (OCIAttrSet(*userhpp, OCI_HTYPE_SESSION, name, strlen(name), + OCI_ATTR_USERNAME, errhp) != OCI_SUCCESS) + error_report(errhp, "conn2serv - OCIAttrSet"); + + if (OCIAttrSet(*userhpp, OCI_HTYPE_SESSION, name, strlen(name), + OCI_ATTR_PASSWORD, errhp) != OCI_SUCCESS) + error_report(errhp, "conn2serv - OCIAttrSet"); + + /* Authenticate */ + if (OCISessionBegin (svchp, errhp, *userhpp, + OCI_CRED_RDBMS, OCI_MIGRATE) != OCI_SUCCESS) + error_report(errhp, "conn2serv - ocisauth"); + + /* Free Temporary Service Context */ + (void) OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX); + + fprintf (stdout, "Authentication for %s successful.\n", name); +} + +/* terminate_user */ +void terminate_user(envhp, errhp, srvhp, userhp) +OCIEnv *envhp; +OCIError *errhp; +OCIServer *srvhp; +OCISession *userhp; +{ + OCISvcCtx *svchp; + /* Temporary Service Context */ + if (OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS ) + { + fprintf(stdout, "Fail to OCIHandleAlloc for service handle..."); + terminate_main(envhp, errhp); + exit(EX_FAILURE); + } + + fprintf(stdout, "Logging off...\n"); + + /*****************************************************************/ + /**************** SWITCH SESSIONS BEGIN **************************/ + /* Set the server handle in service handle */ + if (OCIAttrSet (svchp, OCI_HTYPE_SVCCTX, srvhp, 0, + OCI_ATTR_SERVER, errhp) != OCI_SUCCESS) + error_report(errhp, "conn2serv - OCIAttrSet"); + + /* Set the Authentication handle in the service handle */ + if (OCIAttrSet(svchp, OCI_HTYPE_SVCCTX, userhp, 0, + OCI_ATTR_SESSION, errhp) != OCI_SUCCESS) + error_report(errhp, "conn2serv - OCIAttrSet"); + /**************** SWITCH SESSIONS END ****************************/ + /*****************************************************************/ + if (OCISessionEnd(svchp, errhp, userhp, (ub4) 0)) + { + error_report(errhp, (CONST text *)"logout: ologof"); + } + + /* Free Temporary Service Context */ + (void) OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX); + fprintf(stdout, "Logged off.\n"); +} + +/* initialize_main */ +void initialize_main(envhpp, errhpp) +OCIEnv **envhpp; +OCIError **errhpp; +{ + int i; + + if (OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0, (dvoid * (*)()) 0, + (dvoid * (*)())0, (void (*)()) 0 ) != OCI_SUCCESS) + { + fprintf(stdout, "Fail to OCIInitialize..."); + exit(EX_FAILURE); + } + + if (OCIEnvInit( (OCIEnv **) envhpp, (ub4) OCI_DEFAULT, + (size_t) 0, (dvoid **) 0 ) != OCI_SUCCESS) + { + fprintf(stdout, "Fail to OCIEnvInit for service handle..."); + exit(EX_FAILURE); + } + + /* Get Error Handle */ + if (OCIHandleAlloc( (dvoid *) *envhpp, (dvoid **) errhpp, + (ub4) OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS) + { + fprintf(stdout, "Fail to OCIHandleAlloc for error handle..."); + exit(EX_FAILURE); + } + return; +} + +/* terminate_main*/ +void terminate_main(envhp, errhp) +OCIEnv *envhp; +OCIError *errhp; +{ + (void) OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR); + (void) OCIHandleFree((dvoid *) envhp, (ub4) OCI_HTYPE_ENV); +} + + +/* initialize_server */ +void initialize_server(envhp, errhp, srvhpp) +OCIEnv *envhp; +OCIError *errhp; +OCIServer **srvhpp; +{ + if (OCIHandleAlloc( (dvoid *) envhp, (dvoid **) srvhpp, + (ub4) OCI_HTYPE_SERVER, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS ) + { + fprintf(stdout, "Fail to OCIHandleAlloc for server handle..."); + exit(EX_FAILURE); + } + + /* Initialize Server Handle */ + if (OCIServerAttach(*srvhpp, errhp, (text *)"", 0, 0) != OCI_SUCCESS ) + error_report(errhp, "conn2serv - OCIServerAttach"); +} + +/* terminate_server */ +void terminate_server(errhp, srvhp) +OCIError *errhp; +OCIServer *srvhp; +{ + (void) OCIServerDetach(srvhp, errhp, OCI_DEFAULT ); + (void) OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER); +} + + +/* initialize_statement */ +void initialize_statement(envhp, errhp, stmhpp) +OCIEnv *envhp; +OCIError *errhp; +OCIStmt **stmhpp; +{ + OCIDefine *dfnhp = (OCIDefine *)NULL; + + /* Get statement handles */ + if (OCIHandleAlloc( (dvoid *)envhp, (dvoid **) stmhpp, + (ub4) OCI_HTYPE_STMT, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS ) + { + fprintf(stdout, "Fail to OCIHandleAlloc for statement handle"); + terminate_main(envhp, errhp); + exit(EX_FAILURE); + } + + if (OCIStmtPrepare(*stmhpp, errhp, (text *)stmt, + (ub4)strlen(stmt), + (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT)) + { + fprintf(stdout, "Fail to OCIHandleAlloc for statement handle"); + terminate_main(envhp, errhp); + exit(EX_FAILURE); + } + + /* OCIDefineByPos */ + if (OCIDefineByPos(*stmhpp, &dfnhp, errhp, (ub4)1, + (dvoid *)username, (sb4)sizeof(username), SQLT_CHR, + ( dvoid *)&userind, &userlen, (ub2 *)NULL, + (ub4)OCI_DEFAULT)) + { + fprintf(stdout, "Fail to OCIHandleAlloc for statement handle"); + terminate_main(envhp, errhp); + exit(EX_FAILURE); + } + + fprintf(stdout, ""); +} + +/* terminate_statement */ +void terminate_statement(stmhp) +OCIStmt *stmhp; +{ + (void) OCIHandleFree((dvoid *) stmhp, (ub4) OCI_HTYPE_STMT); +} + +/* error_report */ +void error_report(errhp, op) +OCIError *errhp; +CONST text *op; +{ + text msgbuf[2000]; + sb4 errcode = 0; + + fprintf(stdout,"ORACLE error during %s\n", op); + OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + fprintf(stdout,"ERROR CODE = %d\n", errcode); + fprintf(stdout,"%s\n", msgbuf); + exit(EX_FAILURE); +} + + +void execute_statement(envhp, errhp, userhp, srvhp, stmhp) +OCIEnv *envhp; +OCIError *errhp; +OCISession *userhp; +OCIServer *srvhp; +OCIStmt *stmhp; +{ + OCISvcCtx *svchp; + sword retval; + + /* Temporary Service Context */ + if (OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, + (size_t) 0, (dvoid **) 0) != OCI_SUCCESS ) + { + fprintf(stdout, "Fail to OCIHandleAlloc for service handle..."); + terminate_main(envhp, errhp); + exit(EX_FAILURE); + } + + /*****************************************************************/ + /**************** SWITCH SESSIONS BEGIN **************************/ + /* Set the server handle in service handle */ + if (OCIAttrSet (svchp, OCI_HTYPE_SVCCTX, srvhp, 0, + OCI_ATTR_SERVER, errhp) != OCI_SUCCESS) + error_report(errhp, "conn2serv - OCIAttrSet"); + + /* Set the Authentication handle in the service handle */ + if (OCIAttrSet(svchp, OCI_HTYPE_SVCCTX, userhp, 0, + OCI_ATTR_SESSION, errhp) != OCI_SUCCESS) + error_report(errhp, "conn2serv - OCIAttrSet"); + /**************** SWITCH SESSIONS END ****************************/ + /*****************************************************************/ + + + /* Now attempt to select user from dual!!!!! */ + fprintf(stdout, "SELECT USER FROM DUAL\n"); + + retval = OCIStmtExecute(svchp, stmhp, errhp, (ub4)1, (ub4)0, + (OCISnapshot*)0, (OCISnapshot*)0, + (ub4)OCI_DEFAULT); + + if (retval == OCI_SUCCESS) + { + fprintf(stdout, "User name of current session: %.*s\n", + userlen, username); + memset((void *)username, 0, sizeof(username)); + } + else + { + error_report(errhp, (text *)"OCIStmtExecute"); + return; + } + + /* Free Temporary Service Context */ + (void) OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX); +} + +/* end of file cdemoses.c */ + diff --git a/cdemoses.h b/cdemoses.h new file mode 100644 index 0000000..b0f3834 --- /dev/null +++ b/cdemoses.h @@ -0,0 +1,100 @@ +/* + * $Header: cdemoses.h 05-dec-2000.11:47:17 lchidamb Exp $ + */ + +/* Copyright (c) 1998, 2000 Oracle Corporation. All rights reserved. +*/ + +/* NOTE: See 'header_template.doc' in the 'doc' dve under the 'forms' + directory for the header file template that includes instructions. +*/ + +/* + NAME + cdemoses.h - C Demo for Session Management + + DESCRIPTION + This program Illustrates the following functionality: + (1) Session Switching + Session Switching allows applications to multiplex several users + over the same connection. This allows apps to multiplex several + sessions over one connection without losing the database privilege + and security features. + + (2) Session Migration + Session Migration lets applications move sessions across connections. + With this feature, the application can move sessions around + dynamically based on system load and the application could implement + its own application level user priority scheme. + + NOTES + + MODIFIED (MM/DD/YY) + lchidamb 12/05/00 - remove s.h include + emendez 09/13/00 - fix top 5 olint errors + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + lchidamb 10/14/98 - prototype changes + lchidamb 10/13/98 - session management demo header + lchidamb 10/13/98 - Creation + +*/ + + +#ifndef cdemoses_ORACLE +# define cdemoses_ORACLE + + + +/*--------------------------------------------------------------------------- + PUBLIC TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + + +/*--------------------------------------------------------------------------- + PUBLIC FUNCTIONS + ---------------------------------------------------------------------------*/ + +void initialize_main(/*_ OCIEnv **envhpp, OCIError **errhpp _*/); + +void terminate_main(/*_ OCIEnv *envhp, OCIError *errhp _*/); + +void initialize_server(/*_ OCIEnv *envhp, OCIError *errhp, + OCIServer **srvhpp _*/); + +void terminate_server(/*_ OCIError *errhp, OCIServer *srvhp _*/); + +void initialize_user(/*_ OCIEnv *envhp, OCIError *errhp, + OCIServer *srvhp, OCISession **userhpp, + char *name _*/); + +void initialize_migratable_user(/*_ OCIEnv *envhp, OCIError *errhp, + OCIServer *srvhp, OCISession *primary, + OCISession **userhpp, + char *name _*/); + +void terminate_user(/*_ OCIEnv *envhp, OCIError *errhp, + OCIServer *srvhp, OCISession *userhp _*/); + +void initialize_statement(/*_ OCIEnv *envhp, OCIError *errhp, + OCIStmt **stmhpp _*/); + +void terminate_statement(/*_ OCIStmt *stmhp _*/); + +void error_report(/*_ OCIError *errhp, CONST text *op _*/); + +void execute_statement(/*_ OCIEnv *envhp, OCIError *errhp, + OCISession *userhp, OCIServer *srvhp, + OCIStmt *stmhp _*/); + + +/*--------------------------------------------------------------------------- + PRIVATE FUNCTIONS + ---------------------------------------------------------------------------*/ + + +#endif /* cdemoses_ORACLE */ diff --git a/cdemoses.sql b/cdemoses.sql new file mode 100644 index 0000000..624c118 --- /dev/null +++ b/cdemoses.sql @@ -0,0 +1,51 @@ +rem +rem $Header: cdemoses.sql 14-nov-00.18:39:03 hdnguyen Exp $ +rem +rem cdemoses.sql +rem +rem Copyright (c) 1998, 1999,, 2000 Oracle Corporation. All rights reserved. +rem +rem NAME +rem cdemoses.sql - +rem +rem DESCRIPTION +rem +rem +rem NOTES +rem +rem +rem MODIFIED (MM/DD/YY) +rem hdnguyen 11/14/00 - fixed connect internal +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem lchidamb 10/14/98 - Add Primary User +rem lchidamb 10/13/98 - SQL script for Session management demo +rem lchidamb 10/13/98 - Created +rem +connect / as sysdba; +drop user user0 cascade; +drop user user1 cascade; +drop user user2 cascade; +drop user user3 cascade; +drop user user4 cascade; +drop user user5 cascade; +drop user user6 cascade; +drop user user7 cascade; +drop user user8 cascade; +drop user user9 cascade; + +drop user primary cascade; + +grant connect, resource to user0 identified by user0; +grant connect, resource to user1 identified by user1; +grant connect, resource to user2 identified by user2; +grant connect, resource to user3 identified by user3; +grant connect, resource to user4 identified by user4; +grant connect, resource to user5 identified by user5; +grant connect, resource to user6 identified by user6; +grant connect, resource to user7 identified by user7; +grant connect, resource to user8 identified by user8; +grant connect, resource to user9 identified by user9; + + +grant connect, resource to primary identified by primary; + diff --git a/cdemosp.c b/cdemosp.c new file mode 100644 index 0000000..efce90a --- /dev/null +++ b/cdemosp.c @@ -0,0 +1,255 @@ +/* Copyright (c) 2001, 2002, Oracle Corporation. All rights reserved. */ +/* + + NAME + cdemosp.c - Basic OCI Session Pooling functionality + + DESCRIPTION + + + This program invokes multiple threads to insert MAXTHREAD records + into EMPLOYEES table. + This program assumes that sample HR schema is setup. + + MODIFIED (MM/DD/YY) + msowdaga 04/30/08 - Fix bug 6236196, multiple threads should not share + single error handle + sudsrini 12/26/02 - Use different empnos to insert, than 1-10 + jchai 01/28/02 - Merged jchai_change_oci_sp_sc_cp_names + sudsrini 01/08/02 - Merged sudsrini_enable_sp_sc_suite + sudsrini 12/30/01 - Lint Fix + abande 12/07/01 - Creation + +*/ + +#ifndef OCISP_ORACLE +# include +#endif + +/* Maximum Number of threads */ +#define MAXTHREAD 10 +static ub4 sessMin = 3; +static ub4 sessMax = 8; +static ub4 sessIncr = 5; + +static OCIError *errhp; +static OCIEnv *envhp; +static OCISPool *poolhp=(OCISPool *) 0; +static int employeeNum[MAXTHREAD]; + +static OraText *poolName; +static ub4 poolNameLen; +static CONST OraText *database = (text *)""; +static CONST OraText *appusername =(text *)"hr"; +static CONST OraText *apppassword =(text *)"hr"; + +/* Values to be inserted into EMP table */ +static char firstname[10][10]={"A","B","C","D","E","F","G","H","I","J"}; +static char lastname[10][10]={"A","B","C","D","E","F","G","H","I","J"}; +static char email[10][20]={"A@oracle.com","B@oracle.com","C@oracle.com", + "D@oracle.com","E@oracle.com","F@oracle.com", + "G@oracle.com","H@oracle.com","I@oracle.com", + "J@oracle.com"}; + +static char ejob[10][11]={"FI_ACCOUNT","AC_ACCOUNT","SA_MAN","PU_MAN", + "PU_CLERK","IT_PROG","MK_REP","AD_VP","AC_MGR", + "HR_REP"}; +static float esal[10]={10000.00, + 5000.00, + 8000.00, + 6000.00, + 10000.00, + 8000.00, + 6000.00, + 6000.00, + 5000.00, + 5000.00}; + +static char hiredate[10][10]={"07-JUN-94","08-JAN-94","18-JUL-97", + "21-FEB-96","02-JUL-96","13-AUG-99", + "28-DEC-98","27-SEP-96","01-JUL-99", "01-AUG-97"}; + +static unsigned int edept[10] = {10,20,10,20,30,10,30,20,10,20}; + +static void checkerr (OCIError *errhp, sword status); +static void threadFunction (dvoid *arg); + +int main(void) +{ + int i = 0; + sword lstat; + int timeout =1; + OCIEnvCreate (&envhp, OCI_THREADED, (dvoid *)0, NULL, + NULL, NULL, 0, (dvoid *)0); + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **) &poolhp, OCI_HTYPE_SPOOL, + (size_t) 0, (dvoid **) 0); + + /* Create the session pool */ + checkerr(errhp, OCIAttrSet((dvoid *) poolhp, + (ub4) OCI_HTYPE_SPOOL, (dvoid *) &timeout, (ub4)0, + OCI_ATTR_SPOOL_TIMEOUT, errhp)); + + if (lstat = OCISessionPoolCreate(envhp, errhp,poolhp, (OraText **)&poolName, + (ub4 *)&poolNameLen, database, + (ub4)strlen((const signed char *)database), + sessMin, sessMax, sessIncr, + (OraText *)appusername, + (ub4)strlen((const signed char *)appusername), + (OraText *)apppassword, + (ub4)strlen((const signed char *)apppassword), + OCI_DEFAULT)) + { + checkerr(errhp,lstat); + } + + printf("Session Pool Created \n"); + + /* Multiple threads using the session pool */ + { + OCIThreadId *thrid[MAXTHREAD]; + OCIThreadHandle *thrhp[MAXTHREAD]; + + OCIThreadProcessInit (); + checkerr (errhp, OCIThreadInit (envhp, errhp)); + for (i = 0; i < MAXTHREAD; ++i) + { + checkerr (errhp, OCIThreadIdInit (envhp, errhp, &thrid[i])); + checkerr (errhp, OCIThreadHndInit (envhp, errhp, &thrhp[i])); + } + for (i = 0; i < MAXTHREAD; ++i) + { + employeeNum[i]=i; + /* Inserting into EMP table */ + checkerr (errhp, OCIThreadCreate (envhp, errhp, threadFunction, + (dvoid *) &employeeNum[i], thrid[i], thrhp[i])); + } + for (i = 0; i < MAXTHREAD; ++i) + { + checkerr (errhp, OCIThreadJoin (envhp, errhp, thrhp[i])); + checkerr (errhp, OCIThreadClose (envhp, errhp, thrhp[i])); + checkerr (errhp, OCIThreadIdDestroy (envhp, errhp, &(thrid[i]))); + checkerr (errhp, OCIThreadHndDestroy (envhp, errhp, &(thrhp[i]))); + } + checkerr (errhp, OCIThreadTerm (envhp, errhp)); + } /* ALL THE THREADS ARE COMPLETE */ + lstat = OCISessionPoolDestroy(poolhp, errhp, OCI_DEFAULT); + + printf("Session Pool Destroyed \n"); + + if (lstat != OCI_SUCCESS) + checkerr(errhp, lstat); + + checkerr(errhp, OCIHandleFree((dvoid *)poolhp, OCI_HTYPE_SPOOL)); + + checkerr(errhp, OCIHandleFree((dvoid *)errhp, OCI_HTYPE_ERROR)); + return 0; + +} /* end of main () */ + +/* Inserts records into EMP table */ +static void threadFunction (dvoid *arg) +{ + int empno = *(int *)arg; + OCISvcCtx *svchp = (OCISvcCtx *) 0; + text insertst1[256]; + OCIStmt *stmthp = (OCIStmt *)0; + OCIError *errhp2 = (OCIError *) 0; + OCIAuthInfo *authp = (OCIAuthInfo *)0; + sword lstat; + text name[10]; + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp2, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + + lstat = OCIHandleAlloc((dvoid *) envhp, + (dvoid **)&authp, (ub4) OCI_HTYPE_AUTHINFO, + (size_t) 0, (dvoid **) 0); + if (lstat) + checkerr(errhp2, lstat); + + checkerr(errhp2, OCIAttrSet((dvoid *) authp,(ub4) OCI_HTYPE_AUTHINFO, + (dvoid *) appusername, (ub4) strlen((char *)appusername), + (ub4) OCI_ATTR_USERNAME, errhp2)); + + checkerr(errhp2,OCIAttrSet((dvoid *) authp,(ub4) OCI_HTYPE_AUTHINFO, + (dvoid *) apppassword, (ub4) strlen((char *)apppassword), + (ub4) OCI_ATTR_PASSWORD, errhp2)); + + if (lstat = OCISessionGet(envhp, errhp2, &svchp, authp, + (OraText *)poolName, (ub4)strlen((char *)poolName), NULL, + 0, NULL, NULL, NULL, OCI_SESSGET_SPOOL)) + { + checkerr(errhp2,lstat); + } + + (void) sprintf(insertst1,"INSERT INTO EMPLOYEES (employee_id, first_name,\ + last_name, email, hire_date, job_id, salary, department_id)\ + values (%d, '%s', '%s', '%s', '%s', '%s',%7.2f, %d )", + empno+2345,firstname[empno],lastname[empno], email[empno], + hiredate[empno], ejob[empno], esal[empno], edept[empno]); + + OCIHandleAlloc(envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0); + + checkerr(errhp2, OCIStmtPrepare (stmthp, errhp2, (CONST OraText *)insertst1, + (ub4)strlen((const signed char *)insertst1), + OCI_NTV_SYNTAX, OCI_DEFAULT)); + + checkerr(errhp2, OCIStmtExecute (svchp, stmthp, errhp2, (ub4)1, (ub4)0, + (OCISnapshot *)0, (OCISnapshot *)0, + OCI_DEFAULT )); + + checkerr(errhp2, OCITransCommit(svchp,errhp2,(ub4)0)); + + printf("Insert complete \n"); + + checkerr(errhp2, OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT)); + checkerr(errhp2, OCISessionRelease(svchp, errhp2, NULL, 0, OCI_DEFAULT)); + OCIHandleFree((dvoid *)authp, OCI_HTYPE_AUTHINFO); + OCIHandleFree((dvoid *)errhp2, OCI_HTYPE_ERROR); + +} /* end of threadFunction (dvoid *) */ + +/* This function prints the error */ +void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", 512, errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} diff --git a/cdemosp.h b/cdemosp.h new file mode 100644 index 0000000..4216252 --- /dev/null +++ b/cdemosp.h @@ -0,0 +1,51 @@ +/* Copyright (c) 2002, Oracle Corporation. All rights reserved. */ + +/* + NAME + cdemosp.h - OCI Session Pool demo program header + + + MODIFIED (MM/DD/YY) + jchai 01/28/02 - Merged jchai_change_oci_sp_sc_cp_names + sudsrini 01/08/02 - Merged sudsrini_enable_sp_sc_suite + sudsrini 01/03/02 - Creation + +*/ + +#ifndef ORATYPES +# include +#endif + +#ifndef OCI_ORACLE +# include +#endif + +#include +#include +#include + +#ifndef OCISP_ORACLE +# define OCISP_ORACLE + +/*--------------------------------------------------------------------------- + PUBLIC TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + + +/*--------------------------------------------------------------------------- + EXPORT FUNCTIONS + ---------------------------------------------------------------------------*/ + +int main (void); + +/*--------------------------------------------------------------------------- + INTERNAL FUNCTIONS + ---------------------------------------------------------------------------*/ + + +#endif /* OCISP_ORACLE */ diff --git a/cdemostc.c b/cdemostc.c new file mode 100644 index 0000000..9834456 --- /dev/null +++ b/cdemostc.c @@ -0,0 +1,206 @@ +/* Copyright (c) 2001, 2002, Oracle Corporation. All rights reserved. */ +/* + NAME + cdemostc.c- OCI Statement caching functionality - basic demo + + DESCRIPTION + This program assumes that sample HR schema is setup. + Does the following steps: + o prepare a statement + o tag it + o retag the same statement and + o retreive the statement from the cache. + + MODIFIED (MM/DD/YY) + sprabhak 12/10/02 - Changed the mode to statement cache + sudsrini 01/30/02 - Rename ocisc -> cdemostc + gkirsur 01/25/02 - Merged gkirsur_stcache_tests + sudsrini 01/24/02 - Removed argc and argv as its not being used + sprabhak 01/22/02 -Incorporated review comments + sprabhak 12/15/01 - Modified + schandir 12/06/01 - Creation + +*/ +#ifndef OCISC_ORACLE +# include +#endif + +static OCIError *errhp; +static OCIEnv *envhp; +static OCIServer *svrhp = (OCIServer *)0; +static OCISession *sesnhp = (OCISession *)0; +static OCISvcCtx *svchp = (OCISvcCtx *)0; +static OCIStmt *stmthp = (OCIStmt *)0; + +static CONST OraText *database = (OraText *)""; +static CONST OraText *username = (OraText *)"hr"; +static CONST OraText *password = (OraText *)"hr"; + + +int main(void) +{ + int i = 0; + sword lstat; + + OCIEnvCreate ((OCIEnv **)&envhp, (ub4)OCI_THREADED, (dvoid *)0, + (dvoid * (*) (dvoid *, size_t))0, (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *))0, (size_t)0, (dvoid **)0); + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + lstat = OCILogon2(envhp, errhp, &svchp, username + , (ub4)strlen ((char *)username),password + , (ub4)strlen ((char *)password), database + , (ub4)strlen((char *)database),OCI_LOGON2_STMTCACHE); + + if (lstat) + checkerr(errhp, lstat); + + queryRows(svchp); + + /* close connection */ + lstat = OCILogoff(svchp, errhp); + if (lstat) + checkerr(errhp, lstat); + + checkerr(errhp, OCIHandleFree((dvoid *)errhp, OCI_HTYPE_ERROR)); + + return 0; +} /* end of main () */ + + +/* Displays the contents of EMP table */ +static void queryRows(OCISvcCtx *svchp) +{ + sword status = 0; + static text *upd=(text *) + "update employees set salary = 20000 WHERE employee_id = 10"; + int i; + static CONST text *tag = (text *)"tagA"; + static CONST text *tag1 =(text *)"tagB"; + + /* Calling OCIStmtPrepare2 with a SQLtext specified */ + + status= OCIStmtPrepare2 ((OCISvcCtx *)svchp,(OCIStmt **)&stmthp, + (OCIError *)errhp, (text *)upd, (ub4)strlen((char *)upd), + NULL,0,OCI_NTV_SYNTAX,OCI_DEFAULT); + + if (status != OCI_SUCCESS ) + { + printf("OCIStmtPrepare2 Failure...\n"); + checkerr(errhp, status); + } + else + { + printf("OCIStmtPrepare2 Success...\n"); + } + + /*Tag the statement prepared*/ + status=OCIStmtRelease ((OCIStmt *)stmthp, (OCIError *)errhp,tag , + (ub4)strlen((char *)tag),OCI_DEFAULT); + + if ( status != OCI_SUCCESS ) + { + printf("OCIStmtRelease Failure...\n"); + checkerr(errhp, status); + } + else + { + printf("OCIStmtRelease Success...\n"); + } + status= OCIStmtPrepare2 ((OCISvcCtx *)svchp,(OCIStmt **)&stmthp, + (OCIError *)errhp, (text *)upd, (ub4)strlen((char *)upd), tag, + (ub4)strlen((char *)tag), OCI_NTV_SYNTAX, OCI_DEFAULT); + + if ( status != OCI_SUCCESS ) + { + printf("OCIStmtPrepare2 Failure...\n"); + checkerr(errhp, status); + } + else + { + printf("OCIStmtPrepare2 Success...\n"); + } + + /*Retag the statement with a different tag*/ + status=OCIStmtRelease ((OCIStmt *)stmthp, (OCIError *)errhp,tag1, + (ub4)strlen((char *)tag1), OCI_DEFAULT); + if ( status != OCI_SUCCESS ) + { + printf("OCIStmtRelease Failure...\n"); + checkerr(errhp, status); + } + else + { + printf("OCIStmtRelease Success...\n"); + } + /*Trying to get the statement with the tag */ + status= OCIStmtPrepare2 ((OCISvcCtx *)svchp,(OCIStmt **)&stmthp, + (OCIError *)errhp, (text *)upd, (ub4)strlen((char *)upd), tag1, + (ub4)strlen((char *)tag1), OCI_NTV_SYNTAX, OCI_DEFAULT); + + if ( status != OCI_SUCCESS ) + { + printf("OCIStmtPrepare2 Failure...\n"); + checkerr(errhp, status); + } + else + { + printf("OCIStmtPrepare2 Success...\n"); + } + /*Now releasing the stmt back to the cache*/ + status=OCIStmtRelease ((OCIStmt *)stmthp, (OCIError *)errhp,tag1, + (ub4)strlen((char *)tag1), OCI_DEFAULT); + if ( status != OCI_SUCCESS ) + { + printf("OCIStmtRelease Failure...\n"); + checkerr(errhp, status); + } + else + { + printf("OCIStmtRelease Success...\n"); + } + + +} /* end of queryRows() */ + + +/* This function prints the error */ +void checkerr(OCIError *errhp,sword status) +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", 512, errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + + default: + break; + } +} + diff --git a/cdemostc.h b/cdemostc.h new file mode 100644 index 0000000..bc010ee --- /dev/null +++ b/cdemostc.h @@ -0,0 +1,55 @@ +/* Copyright (c) 2002, Oracle Corporation. All rights reserved. */ + +/* + NAME + cdemostc.h - OCI Statement caching + + + MODIFIED (MM/DD/YY) + sudsrini 01/30/02 - Rename ocisc -> cdemostc + gkirsur 01/25/02 - Merged gkirsur_stcache_tests + sudsrini 01/24/02 - Removed argc and argv from main definition + sprabhak 01/22/02 - Incorporated Review comments + sprabhak 01/10/02 - Creation + +*/ + +#ifndef ORATYPES +# include +#endif + +#ifndef OCI_ORACLE +# include +#endif + +#include +#include +#include + +#ifndef OCISC_ORACLE +# define OCISC_ORACLE + +/*--------------------------------------------------------------------------- + PUBLIC TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + + +/*--------------------------------------------------------------------------- + EXPORT FUNCTIONS + ---------------------------------------------------------------------------*/ + + +/*--------------------------------------------------------------------------- + INTERNAL FUNCTIONS + ---------------------------------------------------------------------------*/ + +int main(void); +static void checkerr (OCIError *errhp, sword status); +static void queryRows(OCISvcCtx *svchp); + +#endif /* OCISC_ORACLE */ diff --git a/cdemosyev.c b/cdemosyev.c new file mode 100644 index 0000000..e09d235 --- /dev/null +++ b/cdemosyev.c @@ -0,0 +1,402 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemosyev.c 26-jan-00.08:39:37 mrhodes Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) Oracle Corporation 1998, 1999, 2000. All Rights Reserved. */ + +/* + + NAME + cdemosyev.c - C DEMO for registration for SYstem EVents + + DESCRIPTION + This program demonstrates registration for predefined subscriptions. + At time of registration a callback function is specified which is + invoked when the client needs to be notified. + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + + + NOTES + should run cdemosyev.sql before running this program + + MODIFIED (MM/DD/YY) + mrhodes 01/26/00 - adjust ifdef + mpjoshi 07/30/99 - resolve merge conflict + mpjoshi 07/28/99 - make 'sleep' call nt compatible + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + sasuri 11/23/98 - add shutdown notification + sasuri 06/16/98 - system event demo files + sasuri 06/16/98 - Creation + +*/ + +/* for WINDOWS compatibility of 'sleep' call */ +#if defined(WIN32COMMON) || defined(WIN32) || defined(_WIN32) +#include +#define sleep(x) Sleep(1000*(x)) +#endif + +#include +#include +#include +#include +#include + +static text *username = (text *) "PUBSUB"; +static text *password = (text *) "PUBSUB"; +static int count = 0; +ub4 namespace = OCI_SUBSCR_NAMESPACE_AQ; + +static OCIEnv *envhp; +static OCIServer *srvhp; +static OCIError *errhp; +static OCISvcCtx *svchp; + +static void checkerr(/*_ OCIError *errhp, sword status _*/); +static void cleanup(/*_ void _*/); +static void myfflush(/*_ void _*/); +void initSubscriptionHn (); +int main(); + +static sword status; + +/* define all callback functions */ + +/* callback function for notification of server error events */ + +ub4 notifyDropSch(ctx, subscrhp, pay, payl, desc, mode) +dvoid *ctx; +OCISubscription *subscrhp; +dvoid *pay; +ub4 payl; +dvoid *desc; +ub4 mode; +{ + printf("Notification : Drop on Schema\n"); + return (0); +} + +ub4 notifyError(ctx, subscrhp, pay, payl, desc, mode) +dvoid *ctx; +OCISubscription *subscrhp; +dvoid *pay; +ub4 payl; +dvoid *desc; +ub4 mode; +{ + printf("Notification : Error Event\n"); + return (0); +} + +/* for startup */ + +ub4 notifyStartup(ctx, subscrhp, pay, payl, desc, mode) +dvoid *ctx; +OCISubscription *subscrhp; +dvoid *pay; +ub4 payl; +dvoid *desc; +ub4 mode; +{ + printf("Notification : Startup of Database\n"); + return (0); +} + + +/* for shutdown */ + +ub4 notifyShutdown(ctx, subscrhp, pay, payl, desc, mode) +dvoid *ctx; +OCISubscription *subscrhp; +dvoid *pay; +ub4 payl; +dvoid *desc; +ub4 mode; +{ + count++; + printf("Notification : Shutdown of Database\n"); + return (0); +} + + +ub4 notifyLogon(ctx, subscrhp, pay, payl, desc, mode) +dvoid *ctx; +OCISubscription *subscrhp; +dvoid *pay; +ub4 payl; +dvoid *desc; +ub4 mode; +{ + printf("Notification : Logon on Database\n"); + return (0); +} + +ub4 notifySnoop(ctx, subscrhp, pay, payl, desc, mode) +dvoid *ctx; +OCISubscription *subscrhp; +dvoid *pay; +ub4 payl; +dvoid *desc; +ub4 mode; +{ + printf("Notification : User EVENT Logged on\n"); + return (0); +} + + +ub4 notifyLogoff(ctx, subscrhp, pay, payl, desc, mode) +dvoid *ctx; +OCISubscription *subscrhp; +dvoid *pay; +ub4 payl; +dvoid *desc; +ub4 mode; +{ + printf("Notification : Logoff on Database\n"); + return (0); +} + + +ub4 notifyCreateSch(ctx, subscrhp, pay, payl, desc, mode) +dvoid *ctx; +OCISubscription *subscrhp; +dvoid *pay; +ub4 payl; +dvoid *desc; +ub4 mode; +{ + printf("Notification : Create on Schema\n"); + return (0); +} + +int main() +{ + OCISession *authp = (OCISession *) 0; + OCISubscription *subscrhpErr = (OCISubscription *)0; + OCISubscription *subscrhpStartup = (OCISubscription *)0; + OCISubscription *subscrhpShutdown = (OCISubscription *)0; + OCISubscription *subscrhpLogon = (OCISubscription *)0; + OCISubscription *subscrhpLogoff = (OCISubscription *)0; + OCISubscription *subscrhpCreate = (OCISubscription *)0; + OCISubscription *subscrhpDrop = (OCISubscription *)0; + OCISubscription *subscrhpSnoop = (OCISubscription *)0; + + printf("Initializing OCI Process\n"); + + (void) OCIInitialize((ub4) OCI_EVENTS|OCI_OBJECT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 ); + + printf("Initialization successful\n"); + + printf("Initializing OCI Env\n"); + (void) OCIEnvInit( (OCIEnv **) &envhp, OCI_DEFAULT, (size_t) 0, + (dvoid **) 0 ); + printf("Initialization successful\n"); + + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR, + + (size_t) 0, (dvoid **) 0); + + /* Set server contexts */ + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, + OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0); + + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, + OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0); + + printf("connecting to server\n"); + (void) OCIServerAttach( srvhp, errhp, (text *)"", strlen(""), 0); + printf("connect successful\n"); + + /* set attribute server context in the service context */ + (void) OCIAttrSet( (dvoid *) svchp, OCI_HTYPE_SVCCTX, (dvoid *)srvhp, + (ub4) 0, OCI_ATTR_SERVER, (OCIError *) errhp); + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **)&authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0); + + (void) OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) username, (ub4) strlen((char *)username), + (ub4) OCI_ATTR_USERNAME, errhp); + + (void) OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) password, (ub4) strlen((char *)password), + (ub4) OCI_ATTR_PASSWORD, errhp); + + checkerr(errhp, OCISessionBegin ( svchp, errhp, authp, OCI_CRED_RDBMS, + (ub4) OCI_DEFAULT)); + + (void) OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) authp, (ub4) 0, + (ub4) OCI_ATTR_SESSION, errhp); + + + /* Registration Code */ + + /* each call to initSubscriptionHn allocates + and initialises a registration handle */ + + initSubscriptionHn( &subscrhpErr, + "PUBSUB.ERROR:ADMIN", + (dvoid*)notifyError); + + initSubscriptionHn( &subscrhpStartup, + "PUBSUB.STARTUP:ADMIN", + (dvoid*)notifyStartup); + + initSubscriptionHn( &subscrhpShutdown, + "PUBSUB.SHUTDOWN:ADMIN", + (dvoid*)notifyShutdown); + + initSubscriptionHn( &subscrhpLogon, + "PUBSUB.LOGON:ADMIN", + (dvoid*)notifyLogon); + + initSubscriptionHn( &subscrhpLogoff, + "PUBSUB.LOGOFF:ADMIN", + (dvoid*)notifyLogoff); + + initSubscriptionHn( &subscrhpCreate, + "PUBSUB.CREATE_SCH:ADMIN", + (dvoid*)notifyCreateSch); + + initSubscriptionHn( &subscrhpDrop, + "PUBSUB.DROP_SCH:ADMIN", + (dvoid*)notifyDropSch); + + initSubscriptionHn( &subscrhpSnoop, + "PUBSUB.LOGON:SNOOP", + (dvoid*)notifySnoop); + + /* end session */ + checkerr(errhp, OCISessionEnd ( svchp, errhp, authp, (ub4) OCI_DEFAULT)); + + /* detach from server */ + OCIServerDetach( srvhp, errhp, OCI_DEFAULT); + + while (count != 2) + sleep(1); +} + + +void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, + &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", 512, errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} + + +/* + * Exit program with an exit code. + */ +void cleanup() +{ + if (errhp) + (void) OCIServerDetach( srvhp, errhp, OCI_DEFAULT ); + if (srvhp) + checkerr(errhp, OCIHandleFree((dvoid *) srvhp, OCI_HTYPE_SERVER)); + if (svchp) + (void) OCIHandleFree((dvoid *) svchp, OCI_HTYPE_SVCCTX); + if (errhp) + (void) OCIHandleFree((dvoid *) errhp, OCI_HTYPE_ERROR); + return; +} + + +void myfflush() +{ + eb1 buf[50]; + + fgets((char *) buf, 50, stdin); +} + + +void initSubscriptionHn (subscrhp, +subscriptionName, +func) + +OCISubscription **subscrhp; +char* subscriptionName; +dvoid * func; +{ + + /* allocate subscription handle */ + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **)subscrhp, + (ub4) OCI_HTYPE_SUBSCRIPTION, + (size_t) 0, (dvoid **) 0); + /* set subscription name in handle */ + + (void) OCIAttrSet((dvoid *) *subscrhp, (ub4) OCI_HTYPE_SUBSCRIPTION, + (dvoid *) subscriptionName, + (ub4) strlen((char *)subscriptionName), + (ub4) OCI_ATTR_SUBSCR_NAME, errhp); + + /* set callback function in handle */ + + (void) OCIAttrSet((dvoid *) *subscrhp, (ub4) OCI_HTYPE_SUBSCRIPTION, + (dvoid *) func, (ub4) 0, + (ub4) OCI_ATTR_SUBSCR_CALLBACK, errhp); + + (void) OCIAttrSet((dvoid *) *subscrhp, (ub4) OCI_HTYPE_SUBSCRIPTION, + (dvoid *) 0, (ub4) 0, + (ub4) OCI_ATTR_SUBSCR_CTX, errhp); + + + /* set namespace in handle */ + + (void) OCIAttrSet((dvoid *) *subscrhp, (ub4) OCI_HTYPE_SUBSCRIPTION, + (dvoid *) &namespace, (ub4) 0, + (ub4) OCI_ATTR_SUBSCR_NAMESPACE, errhp); + printf("Begining Registration for subscription %s\n", subscriptionName); + checkerr(errhp, OCISubscriptionRegister(svchp, subscrhp, 1, errhp, + + OCI_DEFAULT)); + printf("done\n"); +} + +/* end of file cdemosyev.c */ diff --git a/cdemosyev.sql b/cdemosyev.sql new file mode 100644 index 0000000..75cdc7d --- /dev/null +++ b/cdemosyev.sql @@ -0,0 +1,339 @@ +rem +rem $Header: cdemosyev.sql 14-nov-00.18:39:09 hdnguyen Exp $ +rem +rem cdemosyev.sql +rem +rem Copyright (c) 1998, 1999,, 2000 Oracle Corporation. All rights reserved. +rem +rem NAME +rem cdemosyev.sql - C DEMO for SYstem EVents +rem +rem DESCRIPTION +rem This Demo script creates users and schema objects necessary +rem for setting up system event triggers and subscriptions using +rem Advanced Queues (AQ). +rem The following are created: +rem triggers which fire on the events +rem queue table, used by persistent queues for storage +rem queues to which triggers enqueue messages +rem subscriptions to queues +rem +rem +rem NOTES +rem This file should be executed before running the OCI registration +rem Script cdemosyev.c, followed by cdemosyex.sql + +rem This script will setup the users and schema objects required for +rem creating subscriptions. After executing this file, cdemosyev.c +rem should be executed. On execution the user should see, on the +rem standard output, messages indicating successful registration for +rem various subscriptions. During the registration process the user +rem specifies a callback function which is invoked when the user needs +rem to be notified. +rem The script cdemosyex performs a set of actions for each of which the +rem corresponding callback function is invoked at the user end. + +rem MODIFIED (MM/DD/YY) +rem hdnguyen 11/14/00 - fixed connect internal +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem sasuri 11/23/98 - add shutdown notification +rem sasuri 06/16/98 - system event demo files +rem sasuri 06/16/98 - Created +rem + +connect / as sysdba; +set serveroutput on +set echo on + +rem --------------------------------------------------------------------------- +rem +rem Set up a user with appropriate privileges +rem +rem --------------------------------------------------------------------------- + +create user event identified by event; +grant dba to event; + +create user pubsub identified by pubsub; +grant connect, resource, dba to pubsub; +grant AQ_ADMINISTRATOR_ROLE, AQ_USER_ROLE to pubsub; +grant select_catalog_role to pubsub; +grant execute on dbms_aq to pubsub; +execute dbms_aqadm.grant_type_access('pubsub'); +execute dbms_aqadm.grant_system_privilege('ENQUEUE_ANY','pubsub',FALSE); +execute dbms_aqadm.grant_system_privilege('DEQUEUE_ANY','pubsub',FALSE); +connect pubsub/pubsub; + +rem --------------------------------------------------------------------------- +rem +rem create queue tables for persistent multiple consumers +rem +rem --------------------------------------------------------------------------- + +connect pubsub/pubsub; + +rem Create or replace a queue table +begin +DBMS_AQADM.CREATE_QUEUE_TABLE( + QUEUE_TABLE=>'pubsub.raw_msg_table', + MULTIPLE_CONSUMERS => TRUE, + QUEUE_PAYLOAD_TYPE =>'RAW', + COMPATIBLE => '8.1.3'); +end; +/ + +rem --------------------------------------------------------------------------- +rem +rem Create various persistent queues for publishing messages +rem +rem --------------------------------------------------------------------------- + +rem Create a queue for error events +begin +DBMS_AQADM.CREATE_QUEUE(QUEUE_NAME=>'pubsub.error', + QUEUE_TABLE=>'pubsub.raw_msg_table', + COMMENT=>'Q for error triggers'); +end; +/ + +rem Create a queue for startup +begin +DBMS_AQADM.CREATE_QUEUE(QUEUE_NAME=>'pubsub.startup', + QUEUE_TABLE=>'pubsub.raw_msg_table', + COMMENT=>'Q for startup triggers'); +end; +/ + +rem Create a queue for shutdown +begin +DBMS_AQADM.CREATE_QUEUE(QUEUE_NAME=>'pubsub.shutdown', + QUEUE_TABLE=>'pubsub.raw_msg_table', + COMMENT=>'Q for shutdown triggers'); +end; +/ + +rem Create a queue for logon events +begin +DBMS_AQADM.CREATE_QUEUE(QUEUE_NAME=>'pubsub.logon', + QUEUE_TABLE=>'pubsub.raw_msg_table', + COMMENT=>'Q for logon triggers'); +end; +/ + +rem Create a queue for logoff events +begin +DBMS_AQADM.CREATE_QUEUE(QUEUE_NAME=>'pubsub.logoff', + QUEUE_TABLE=>'pubsub.raw_msg_table', + COMMENT=>'Q for logoff triggers'); +end; +/ + +rem --------- Create non-persistent queues ----------------------- + +rem Create a queue for create on schema events +begin +DBMS_AQADM.CREATE_NP_QUEUE(QUEUE_NAME=>'pubsub.create_sch', + MULTIPLE_CONSUMERS => TRUE); +end; +/ + +begin +DBMS_AQADM.CREATE_NP_QUEUE(QUEUE_NAME=>'pubsub.drop_sch', + MULTIPLE_CONSUMERS => TRUE); +end; +/ + +rem --------------------------------------------------------------------------- +rem +rem Start all queues +rem +rem --------------------------------------------------------------------------- + + +begin +DBMS_AQADM.START_QUEUE('pubsub.error'); +DBMS_AQADM.START_QUEUE('pubsub.startup'); +DBMS_AQADM.START_QUEUE('pubsub.shutdown'); +DBMS_AQADM.START_QUEUE('pubsub.logon'); +DBMS_AQADM.START_QUEUE('pubsub.logoff'); +DBMS_AQADM.START_QUEUE('pubsub.create_sch'); +DBMS_AQADM.START_QUEUE ('pubsub.drop_sch'); + +end; +/ + +rem --------------------------------------------------------------------------- +rem +rem define new_enqueue/new_np_enqueue for convenience +rem +rem --------------------------------------------------------------------------- + + +create or replace procedure new_enqueue(queue_name in varchar2, + payload in raw , + correlation in varchar2 := NULL, + exception_queue in varchar2 := NULL) +as + +enq_ct dbms_aq.enqueue_options_t; +msg_prop dbms_aq.message_properties_t; +enq_msgid raw(16); +userdata raw(1000); + +begin + msg_prop.exception_queue := exception_queue; + msg_prop.correlation := correlation; + userdata := payload; + + DBMS_AQ.ENQUEUE(queue_name, enq_ct, msg_prop, userdata, enq_msgid); +end; +/ +grant execute on new_enqueue to public; + +create or replace procedure new_np_enqueue(queue varchar2, + id integer, + correlation varchar2) +as + +msgprop dbms_aq.message_properties_t; +enqopt dbms_aq.enqueue_options_t; +enq_msgid raw(16); +payload raw(10); + +begin + payload := hextoraw('123'); + enqopt.visibility:=dbms_aq.IMMEDIATE; + msgprop.correlation:=correlation; + DBMS_AQ.ENQUEUE( queue, enqopt, msgprop, payload, enq_msgid); +end; +/ + +grant execute on new_np_enqueue to public; + +rem --------------------------------------------------------------------------- +rem +rem create subscriptions to all event-publications for agent 'ADMIN' +rem +rem --------------------------------------------------------------------------- + + + +DECLARE + +subscriber sys.aq$_agent; + +begin + +subscriber := sys.aq$_agent('admin', null, null); + +dbms_aqadm.add_subscriber(queue_name => 'pubsub.error', + subscriber => subscriber); + +dbms_aqadm.add_subscriber(queue_name => 'pubsub.startup', + subscriber => subscriber); + +dbms_aqadm.add_subscriber(queue_name => 'pubsub.shutdown', + subscriber => subscriber); + +dbms_aqadm.add_subscriber(queue_name => 'pubsub.logoff', + subscriber => subscriber); + +dbms_aqadm.add_subscriber(queue_name => 'pubsub.logon', + subscriber => subscriber); + +dbms_aqadm.add_subscriber(queue_name => 'pubsub.create_sch', + subscriber => subscriber); + +dbms_aqadm.add_subscriber(queue_name => 'pubsub.drop_sch', + subscriber => subscriber); +end; +/ + +rem --------------------------------------------------------------------------- +rem +rem add subscriber with rule based on curent user name, using correlation_id +rem +rem --------------------------------------------------------------------------- + +declare +subscriber sys.aq$_agent; +begin +subscriber := sys.aq$_agent('SNOOP', null, null); +dbms_aqadm.add_subscriber(queue_name => 'pubsub.logon', + subscriber => subscriber, + rule => 'CORRID = ''EVENT'' '); +end; +/ + +rem --------------------------------------------------------------------------- +rem +rem now create triggers on various events +rem +rem --------------------------------------------------------------------------- + + +rem create trigger on after server errors +create or replace trigger systrig0 + AFTER SERVERERROR + ON DATABASE + begin + new_enqueue('pubsub.error', hextoraw('9999')); + end; +/ + +rem create trigger on after startup +create or replace trigger systrig1 + AFTER STARTUP + ON DATABASE + begin + new_enqueue('pubsub.startup', hextoraw('9999')); + end; +/ + +rem create trigger on after shutdown +create or replace trigger systrig2 + BEFORE SHUTDOWN + ON DATABASE + begin + new_enqueue('pubsub.shutdown', hextoraw('9999')); + end; +/ + +rem create trigger on after logon +create or replace trigger systrig3 + AFTER LOGON + ON DATABASE + begin + new_enqueue('pubsub.logon', hextoraw('9999'), dbms_standard.login_user); + end; +/ + +rem create trigger on before logoff +create or replace trigger systrig4 + BEFORE LOGOFF + ON DATABASE + begin + new_enqueue('pubsub.logoff', hextoraw('9999')); + end; +/ + +rem create trigger on after create on sch +create or replace trigger systrig5 + AFTER CREATE + ON SCHEMA + begin + new_np_enqueue('pubsub.create_sch', 1, 'non persistent'); + end; +/ + +rem create trigger on after drop on sch + +create or replace trigger systrig6 + AFTER DROP + ON SCHEMA + begin + new_np_enqueue('pubsub.drop_sch', 1, 'non persistent'); + end; +/ + +disconnect diff --git a/cdemosyex.sql b/cdemosyex.sql new file mode 100644 index 0000000..72e86c0 --- /dev/null +++ b/cdemosyex.sql @@ -0,0 +1,43 @@ +rem +rem $Header: cdemosyex.sql 14-nov-00.18:39:15 hdnguyen Exp $ +rem +rem cdemosyex.sql +rem +rem Copyright (c) 1998, 1999,, 2000 Oracle Corporation. All rights reserved. +rem +rem NAME +rem cdemosyex.sql - C DEMO for executing SYstem EVents +rem +rem DESCRIPTION +rem This SQL script causes the triggers, defined in cdemosyev.sql, +rem to fire. This results in enqueueing of message(s) into queue(s). +rem If there are subscription defined on the queue that are satisfied, +rem a list of recipients are computed. All registered recipients are +rem notified by invoking callback functions. +rem +rem NOTES +rem +rem +rem MODIFIED (MM/DD/YY) +rem hdnguyen 11/14/00 - fixed connect internal +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem sasuri 11/23/98 - add shutdown notification +rem sasuri 06/16/98 - system event demo files +rem sasuri 06/16/98 - Created +rem + +connect event/event +drop table foo; +create table foo(n number); +drop table foo; +connect foo/bar +connect pubsub/pubsub +drop table foo; +create table foo(n number); +drop table foo; +disconnect +connect / as sysdba +shutdown +connect / as sysdba +startup +shutdown diff --git a/cdemothr.c b/cdemothr.c new file mode 100644 index 0000000..016d374 --- /dev/null +++ b/cdemothr.c @@ -0,0 +1,587 @@ +/* Copyright (c) 1997, 1999, Oracle Corporation. All rights reserved. +*/ + +/* + + NAME + cdemothr.c - C Demo for ociTHRead + + DESCRIPTION + This file demonstrates an example of using the OCIThread package + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + + + NOTES + + + MODIFIED (MM/DD/YY) + msowdaga 04/30/08 - Fix bug 6236196, multiple threads should not share + single error handle + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + tsaulys 10/14/98 - minor changes + nramakri 12/17/97 - Creation + +*/ + +#include +#include +#include +#include +#include + +static OCIEnv *envhp; +static OCIError *errhp; + +static void ThrKeyDestroy(/*_ dvoid *arg _*/); +static void ThrFunc(/*_ dvoid *arg _*/); +static int ThrMain(/*_ void _*/); +static sword checkerr(/*_ OCIError *errhp, sword status _*/); +int main(/*_ int argc, char *argv[] _*/); + +int main(argc, argv) +int argc; +char *argv[]; +{ + int status = 0; + + (void) OCIInitialize((ub4) OCI_THREADED, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 ); + + (void) OCIEnvInit( (OCIEnv **) &envhp, OCI_DEFAULT, (size_t) 0, + (dvoid **) 0 ); + + (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + + status = ThrMain(); + + if (errhp) + (void) OCIHandleFree((dvoid *) errhp, OCI_HTYPE_ERROR); + + return status; +} + +sword checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", 512, errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + default: + break; + } + return status; +} + +/*--------------------------- ThrKeyDestroy() --------------------------*/ + +/* + NAME + ThrKeyDestroy - Thread Key Destructor Function + + DESCRIPTION + This is the destructor function used with the 'key_' element of the + 'CDemoThrCtx' data type. See 'thrdemo.h' for info on the + datatype. + + PARAMETERS + void ThrKeyDestroy(dvoid *arg) + + arg This will be the key's value for the thread that just + terminated. + + RETURNS + Nothing. + + NOTES + This sends a diagnostic message to 'stdout' if it is called with a NULL + arg. + + Otherwise, it sets the 'ub1' pointed to by 'arg' to FALSE. +*/ + +static void ThrKeyDestroy(arg) +dvoid *arg; +{ + ub1 *loc = (ub1 *) arg; + + if (arg == (dvoid *)NULL) + { + printf("Key destructor called with NULL argument.\n"); + } + else + *loc = FALSE; + + return; +} + +/*----------------------------- ThrFunc() ------------------------------*/ + +/* + NAME + ThrFunc - Thread Function + + DESCRIPTION + This is the function that gets spawned as a separate thread by + 'ThrMain()'. + + PARAMETERS + void ThrFunc(dvoid *arg) + + arg This should point to the 'CDemoThrCtx' being used + + RETURNS + Nothing. + + NOTES + This sends a diagnostic message to 'stdout' if something unexpected + happens. + +*/ + +static void ThrFunc(arg) +dvoid *arg; +{ + CDemoThrCtx *tdctx = (CDemoThrCtx *) arg; + OCIError *errhp2 = (OCIError *) 0; + OCIThreadId *ourID; /* This eventually gets this thread's ID. */ + sword ourTNum; /* Eventually, this gets our thread number. */ + uword i; /* Loop counter. */ + uword flag; /* Boolean flag. */ + dvoid *keyval; /* Used to retrieve values from a key. */ + boolean result1, result2; + + + (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp2, OCI_HTYPE_ERROR, + (size_t) 0, (dvoid **) 0); + + /* ***** INITIALIZATION ***** */ + + if (checkerr(errhp2, OCIThreadIdInit(envhp, errhp2, &ourID)) != OCI_SUCCESS) + goto exit0; + + /* ***** THREAD ID MANIPULATION ***** */ + + if (checkerr(errhp2, OCIThreadIdGet(envhp, errhp2, ourID)) != OCI_SUCCESS) + goto exit1; + + /* Make sure the ID we just got is not NULL, and is not the same as the */ + /* ID for the main thread. */ + + (void) checkerr(errhp2, OCIThreadIdNull(envhp, errhp2, ourID, &result1)); + (void) checkerr(errhp2, OCIThreadIdSame(envhp, errhp2, ourID, + tdctx->mainTID_CDemoThrCtx, &result2)); + if ((result1 == TRUE) || + (result2 == ((OCIThreadIsMulti() == TRUE) ? TRUE : FALSE))) + { + printf("A spawned thread's ID doesn't seem to be valid.\n"); + } + + /* ***** DETERMINE THREAD NUMBER ***** */ + + ourTNum = -1; + + /* We need to search the 'tdctx->tidAr[]' array. First, we must acquire */ + /* its mutex. */ + (void) checkerr(errhp2, OCIThreadMutexAcquire(envhp, errhp2, + tdctx->tidArMx_CDemoThrCtx)); + + /* Search 'tdctx->tidAr[]'. */ + for (i = 0; i < CDEMOTHR_NUMTHREADS; i++) + { + (void) checkerr(errhp2, OCIThreadIdSame(envhp, errhp2, ourID, + tdctx->tidAr_CDemoThrCtx[i], &result1)); + if (result1 == TRUE) + { + ourTNum = (sword) i; + break; + } + } + + /* We are done with the array. We can release its mutex. */ + (void) checkerr(errhp2, OCIThreadMutexRelease(envhp, errhp2, + tdctx->tidArMx_CDemoThrCtx)); + + if (ourTNum == -1) + { + /* We couldn't find our thread ID. */ + printf("A thread's ID was not in the ID array.\n"); + + /* There is nothing more we can do. We should just terminate. */ + goto exit1; + } + + /* ***** SAVE OUR THREAD NUMBER IN THE NUMBER ARRAY ***** */ + + /* We can indicate everything is OK by putting our thread number in the */ + /* array of thread numbers. */ + (tdctx->tnumAr_CDemoThrCtx)[ourTNum] = ourTNum; + + /* ***** USING KEYS ***** */ + + /* With 'tdctx->key_', we will check that the initial value is NULL, and */ + /* that we can set and retrieve values correctly. */ + + if (checkerr(errhp2, OCIThreadKeyGet(envhp, errhp2, tdctx->key_CDemoThrCtx, + &keyval)) != OCI_SUCCESS) + { + printf("Could not retrieve initial value from key.\n"); + } + + if (keyval != (dvoid *)NULL) + { + printf("Initial value of the key is not NULL.\n"); + } + + if (checkerr(errhp2, OCIThreadKeySet(envhp, errhp2, tdctx->key_CDemoThrCtx, + (dvoid *) &ourTNum)) + != OCI_SUCCESS) + { + printf("Could not set the value of key.\n"); + } + + if (checkerr(errhp2, OCIThreadKeyGet(envhp, errhp2, tdctx->key_CDemoThrCtx, + &keyval)) != OCI_SUCCESS) + { + printf("Could not retrieve value of key after it was set.\n"); + } + + if (keyval != (dvoid *) &ourTNum) + { + printf("Incorrect value from key after setting it.\n"); + } + + /* For 'tdctx->key_', we will now set the value in the key to point to */ + /* our element in 'tdctx->key_'. Then, some threads will reset the value */ + /* to NULL and clear the element in 'tdctx->key_' to FALSE. */ + + if (checkerr(errhp2, OCIThreadKeySet(envhp, errhp2, tdctx->key_CDemoThrCtx, + (dvoid *)&(tdctx->keyAr_CDemoThrCtx[ourTNum]))) + != OCI_SUCCESS) + { + printf("Could not set value in key.\n"); + } + + if (ourTNum < (CDEMOTHR_NUMTHREADS/2)) + { + if (checkerr(errhp2, OCIThreadKeySet(envhp, errhp2, tdctx->key_CDemoThrCtx, + (dvoid *)NULL)) != OCI_SUCCESS) + { + printf("Could not set value in key to NULL.\n"); + } + tdctx->keyAr_CDemoThrCtx[ourTNum] = FALSE; + } + + /* ***** TERMINATION ***** */ + + /* This is the exit point. This terminates the OCITHREAD context (if it */ + /* is not NULL), and returns. */ + + exit1: + (void) checkerr(errhp2, OCIThreadIdDestroy(envhp, errhp2, &ourID)); + + exit0: + OCIHandleFree((dvoid *)errhp2, OCI_HTYPE_ERROR); + return; +} + +static int ThrMain() +{ + + CDemoThrCtx tdctx; + OCIThreadId *tidArray[CDEMOTHR_NUMTHREADS]; + OCIThreadHandle *tHndArray[CDEMOTHR_NUMTHREADS]; + + uword i; /* Loop counter. */ + dvoid *keyval; /* Used to retrieve values for a key. */ + uword tJoins; /* Number of threads we join with. */ + eword demoStat; /* Set to TRUE if the test succeeded. */ + boolean result; /* For Boolean tests */ + + demoStat = TRUE; + tJoins = 0; + + /* ***** INITIALIZATION ***** */ + + /* In a multi-threaded application, 'OCIThreadProcessInit()' must be + called before anything else. In addition, the call must not be + concurrent with any other OCIThread calls. Therefore, we will make the + call here, before we spawn any threads. + */ + printf("Initializing OCIThread. \n"); + OCIThreadProcessInit(); + + if (checkerr(errhp, OCIThreadInit(envhp, errhp)) != OCI_SUCCESS) + { + demoStat = FALSE; + goto exit0; + } + + printf("Initializing the thread ID structure. \n"); + if (checkerr(errhp, OCIThreadIdInit(envhp, errhp, + &(tdctx.mainTID_CDemoThrCtx))) + != OCI_SUCCESS) + { + demoStat = FALSE; + goto exit1; + } + + /* + * Setup what we need to in 'tdctx'. + */ + + /* Put our thread ID in. */ + printf("Retrieving the current thread ID. \n"); + if (checkerr(errhp, OCIThreadIdGet(envhp, errhp, tdctx.mainTID_CDemoThrCtx)) + != OCI_SUCCESS) + { + demoStat = FALSE; + goto exit0; + } + + /* Initialize the mutex protecting the thread array. */ + printf("Intializing the mutex protecting the thread array. \n"); + if (checkerr(errhp, OCIThreadMutexInit(envhp, errhp, + &(tdctx.tidArMx_CDemoThrCtx))) + != OCI_SUCCESS) + { + demoStat = FALSE; + goto exit2; + } + + printf("Initializing all thread IDs and thread handles. \n"); + for (i = 0; i < CDEMOTHR_NUMTHREADS; i++) + { + if (checkerr(errhp, OCIThreadIdInit(envhp, errhp, &(tidArray[i]))) + != OCI_SUCCESS) + { + demoStat = FALSE; + goto exit2; + } + + if (checkerr(errhp, OCIThreadHndInit(envhp, errhp, + &(tHndArray[i]))) != OCI_SUCCESS) + { + demoStat = FALSE; + goto exit2; + } + + if (checkerr(errhp, OCIThreadIdInit(envhp, errhp, + &((tdctx.tidAr_CDemoThrCtx)[i]))) + != OCI_SUCCESS) + { + demoStat = FALSE; + goto exit2; + } + } + + /* Set the thread ID arrays (both 'tidArray' and the one in 'tdctx') to hold + only NULL thread IDs. Clear the thread number array in 'tdctx'. + */ + printf("Setting all thread IDs and thread handles to NULL. \n"); + for (i = 0; i < CDEMOTHR_NUMTHREADS; i++) + { + (void) checkerr(errhp, OCIThreadIdSetNull(envhp, errhp, tidArray[i])); + (void) checkerr(errhp, OCIThreadIdSetNull(envhp, errhp, + (tdctx.tidAr_CDemoThrCtx)[i])); + (tdctx.tnumAr_CDemoThrCtx)[i] = -1; + } + + /* Initialize 'tdctx.key_' and its array. This key will have + 'ThrKeyDestroy()' as its destructor function. + */ + printf("Initializing the thread key. \n"); + if (OCIThreadIsMulti() == TRUE) + { + (void) checkerr(errhp, OCIThreadKeyInit(envhp, errhp, + &(tdctx.key_CDemoThrCtx), + (OCIThreadKeyDestFunc)ThrKeyDestroy)); + } + else + { + (void) checkerr(errhp, OCIThreadKeyInit(envhp, errhp, + &(tdctx.key_CDemoThrCtx), NULL)); + + } + + printf("Setting the value for the thread key for each thread. \n"); + for (i = 0; i < CDEMOTHR_NUMTHREADS; i++) + { + tdctx.keyAr_CDemoThrCtx[i] = TRUE; + } + + /* ***** SPAWN OTHER THREADS ***** */ + + /* Acquire the mutex protecting the thread ID array in 'tdctx'. We will */ + /* release it once the array has been filled. */ + (void) checkerr(errhp, OCIThreadMutexAcquire(envhp, errhp, + tdctx.tidArMx_CDemoThrCtx)); + + /* Spawn all the threads. */ + printf("Spawning all threads. \n"); + for (i = 0; i < CDEMOTHR_NUMTHREADS; i++) + { + if (OCIThreadIsMulti() == TRUE) /* Multi-threaded environment */ + { + if (checkerr(errhp, OCIThreadCreate(envhp, errhp, ThrFunc, + (dvoid *) &tdctx, + tidArray[i], tHndArray[i])) + != OCI_SUCCESS) + { + demoStat = FALSE; + } + } + else + { + ThrFunc((dvoid *)&tdctx); + } + + /* Put the thread ID for the new thread in the array in 'tdctx'. */ + (void) checkerr(errhp, OCIThreadIdSet(envhp, errhp, + (tdctx.tidAr_CDemoThrCtx)[i], + tidArray[i])); + } + + /* All the threads are spawned; so 'tdctx.tidAr_CDemoThrCtx[]' is full. + We can release the mutex protecting it. + */ + (void) checkerr(errhp, OCIThreadMutexRelease(envhp, errhp, + tdctx.tidArMx_CDemoThrCtx)); + + printf("Waiting for all threads to finish. \n"); + if (OCIThreadIsMulti() == TRUE) + { + /* ***** WAIT FOR OTHER THREADS TO FINISH ***** */ + /* Wait for each thread in turn, and make sure that it put its number */ + /* in the thread number array. */ + + for (i=0; i + + PRIVATE FUNCTION(S) + + + EXAMPLES + + NOTES + + + MODIFIED (MM/DD/YY) + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + nramakri 12/17/97 - Creation + +*/ + +#ifndef CDEMOTHR_ORACLE +#define CDEMOTHR_ORACLE + +#include + +/*--------------------------------------------------------------------------- + PUBLIC TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + +/*--------------------------- CDEMOTHR_NUMTHREADS ---------------------------*/ +/*** + Constant for the number of threads that will be spawned in demo in + a multi-threaded environment +***/ +#define CDEMOTHR_NUMTHREADS 32 + +/*-------------------------------- CDemoThrCtx---------------------------*/ +/* + CDemoThrCtx - C Demo Thread Context + + One instance of this structure is created and shared among all the threads + that are created in the demo ('CDemoThr()'). +*/ + +struct CDemoThrCtx +{ + OCIThreadId *mainTID_CDemoThrCtx; /* ID for the main thread */ + /* All of the spawned threads do a check to make sure that their thread */ + /* ID is different from that of the main thread. */ + + OCIThreadMutex *tidArMx_CDemoThrCtx; /* Mutex for 'tidAr_' */ + + /* Array of thread IDs */ + OCIThreadId *tidAr_CDemoThrCtx[CDEMOTHR_NUMTHREADS]; + /* As threads are spawned, the array is filled up with their IDs. The */ + /* mutex must be held in order for it be safe to access the array. */ + + sword tnumAr_CDemoThrCtx[CDEMOTHR_NUMTHREADS]; /* Array of thread #'s */ + /* A thread whose ID is in position 'i' in 'tidAr_' will put 'i' in */ + /* position 'i' of this array. The main thread checks this to ensure */ + /* that everything went OK. */ + + OCIThreadKey *key_CDemoThrCtx; /* Thread key */ + ub1 keyAr_CDemoThrCtx[CDEMOTHR_NUMTHREADS]; /* Values for thread key */ +}; +typedef struct CDemoThrCtx CDemoThrCtx; + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + + +/*--------------------------------------------------------------------------- + PUBLIC FUNCTIONS + ---------------------------------------------------------------------------*/ + + +/*--------------------------------------------------------------------------- + PRIVATE FUNCTIONS + ---------------------------------------------------------------------------*/ + +#endif /* CDEMOTHR_ORACLE */ diff --git a/cdemoucb.c b/cdemoucb.c new file mode 100644 index 0000000..a6ef649 --- /dev/null +++ b/cdemoucb.c @@ -0,0 +1,621 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemoucb.c 14-jul-99.13:18:11 mjaeger Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1998, 1999, Oracle Corporation. All rights reserved. +*/ + +/* + + NAME + cdemoucb.c - User callback demo program + + DESCRIPTION + This program demonstrates using user callbacks. Both static + and dynamic callbacks are demonstrated. Passing of + arguments to callback routine is also demostrated. + + The program executes a create table command. Callback + routine is registered for OCIStmtPrepare(), in the comments + below OCIStmtPrepare() is mentioned but same applies to all + calls for which callbacks can be registered. + + To use dynamic callback file cdemoucbl.c needs to be linked + into a shared library using the make file provided, see + comments in cdemoucbl.c for more details. + + If environment variable ORA_OCI_UCBPKG is set then routine + OCIEnvCallback in cdemoucbl.c is called, which registers + the callback function for OCIStmtPrepare(). + + All arguments of routine OCIStmtPrepare are also passed to + callback routines, this is verified by doing a va_start + and then acquiring and printing sqlstmt passed to + OCIStmtPrepare(). + + Callback "chaining" is demonstrated as follows: If + ORA_OCI_UCBPKG is set then the dynamic callbacks are + registered first for OCIStmtPrepare. Calling the function + OCIUserCallbackGet returns pointers to the registered + callbacks. These pointers are saved and then static callback + functions are registered for OCIStmtPrepare. Since + registering another entry and exit callback functions for + OCIStmtPrepare will overwrite the previously registered + dynamic callback functions, so the saved pointers are used to + make calls to the dynamic functions. + + Note that the last argument to user callbacks is an arglist. + Therefore, for callback chaining, a wrapper function is needed + to simulate a function with variable number of parameters. + The wrapper function takes all the parameters that have been + passed to the static callback. Since, it is a function with + variable number of parametes, it can create the arglist that is + to be passed to the dynamic callback. This is demonstrated + in the entry callback function. + + In the special case where the static callback does not need the + parameters passed to it, the static callback can simply + pass the arglist directly to the dynamic callback. This is + demonstrated in the exit callback function. + + This program will also work in "static-only" mode. In this + case dynamic callback function will not get registered and + this program will know that after call to + OCIUserCallbackGet and will not attempt to call the + dynamic callback function. + + PUBLIC FUNCTION(S) + + PRIVATE FUNCTION(S) + + RETURNS + + NOTES + + MODIFIED (MM/DD/YY) + slari 08/30/99 - add OCIUcb * + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + slari 11/22/98 - add wrapper for chained callback + slari 11/21/98 - conform to new OCIUserCallback with arglist + svedala 10/13/98 - Creation + +*/ + +#include +#include +#include +#include +#include + +static text *username = (text *) "CDEMOUCB"; +static text *password = (text *) "CDEMOUCB"; + +static text *crstmt = (text *) "CREATE TABLE TAB1 (COL1 VARCHAR2(40))"; + +static OCIEnv *envhp; +static OCIServer *srvhp; +static OCIError *errhp; +static OCISvcCtx *svchp; +static OCIStmt *stmthp; +static OCISession *authp = (OCISession *) 0; + +struct stat_ctx_struct +{ + OCIUserCallback *entry_funcptr; + dvoid *entry_ctxptr; + OCIUserCallback *exit_funcptr; + dvoid *exit_ctxptr; +}; + +typedef struct stat_ctx_struct stat_ctx_struct; + +static void checkerr(/*_ OCIError *errhp, sword status _*/); +static void cleanup(/*_ void _*/); + +sword stmtprep_entry_statcbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist); + +sword stmtprep_exit_statcbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist); + +sword stmtprep_wrapper_cbk_fn (OCIUserCallback *funcptr, dvoid *ctxp, dvoid + *hndlp, ub4 type, ub4 fcode, ub4 when, + sword returnCode, sb4 *errnop, ...); + + +int main(/*_ int argc, char *argv[] _*/); + +static sword status; + +int main(argc, argv) +int argc; +char *argv[]; +{ + + static ub4 pos; + ub4 attrval; + ub4 attrsiz; + text errbuf[512]; + sb4 errcode = 0; + text sversion[512]; + + stat_ctx_struct *static_context; + + OCIUserCallback dyn_entry_funcptr; + dvoid *dyn_entry_ctxptr; + + OCIUserCallback dyn_exit_funcptr; + dvoid *dyn_exit_ctxptr; + + (void) printf("Initializing and Connecting\n\n"); + + if (init_handles()) + { + (void) printf("FAILED: init_handles()\n"); + return OCI_ERROR; + } + + if (log_on()) + { + (void) printf("FAILED: log_on()\n"); + return OCI_ERROR; + } + + if (status = OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp, + OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + + /* Call OCIUserCallbackGet() to check if an entry callback */ + /* is registered for OCIStmtPrepare. If a callback was */ + /* registered dynamically its pointer will be returned. */ + + if (status = OCIUserCallbackGet(envhp, OCI_HTYPE_ENV, errhp, + OCI_FNCODE_STMTPREPARE, OCI_UCBTYPE_ENTRY, + &dyn_entry_funcptr, &dyn_entry_ctxptr, + (OCIUcb *)0)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + + /* Call OCIUserCallbackGet() to check if an exit callback */ + /* is registered for OCIStmtPrepare. If a callback was */ + /* registered dynamically its pointer will be returned. */ + + if (status = OCIUserCallbackGet(envhp, OCI_HTYPE_ENV, errhp, + OCI_FNCODE_STMTPREPARE, OCI_UCBTYPE_EXIT, + &dyn_exit_funcptr, &dyn_exit_ctxptr, + (OCIUcb *)0)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + /* Allocate a structure for context to be passed */ + /* to static callback function. */ + + static_context = (stat_ctx_struct *) malloc(sizeof(stat_ctx_struct)); + + + /* Save the pointer to dynamic callback routine and the */ + /* context associated with dynamic callback function */ + + if ((OCIUserCallback) *dyn_entry_funcptr) + { + static_context->entry_funcptr = &dyn_entry_funcptr; + static_context->entry_ctxptr = dyn_entry_ctxptr; + } + else + { + static_context->entry_funcptr = 0; + static_context->entry_ctxptr = 0; + } + + + if ((OCIUserCallback) *dyn_exit_funcptr) + { + static_context->exit_funcptr = &dyn_exit_funcptr; + static_context->exit_ctxptr = dyn_exit_ctxptr; + } + else + { + static_context->exit_funcptr = 0; + static_context->exit_ctxptr = 0; + } + + /* Register the static callback routine "stmtprep_entry_statcbk_fn" */ + /* for OCIStmtPrepare, entry-time. This will overwrite the */ + /* of entry dynamic callback if one was registered */ + + if (OCIUserCallbackRegister(envhp, OCI_HTYPE_ENV, errhp, + stmtprep_entry_statcbk_fn, static_context, + OCI_FNCODE_STMTPREPARE, OCI_UCBTYPE_ENTRY, + (OCIUcb *)0)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + + /* Register the exit static callback function for OCIStmtPrepare */ + + if (OCIUserCallbackRegister(envhp, OCI_HTYPE_ENV, errhp, + stmtprep_exit_statcbk_fn, static_context, + OCI_FNCODE_STMTPREPARE, OCI_UCBTYPE_EXIT, + (OCIUcb *)0)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + if (status = OCIStmtPrepare(stmthp, errhp, crstmt, + (ub4) strlen((char *) crstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + if ((status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL, OCI_DEFAULT)) + && (status != OCI_NO_DATA)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + if (status = OCITransCommit(svchp, errhp, 0)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + + if (status = OCISessionEnd(svchp, errhp, authp, (ub4) 0)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + (void) printf("\nDetach and deallocate handles\n"); + + if (status = OCIServerDetach( srvhp, errhp, OCI_DEFAULT)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + cleanup(); +} + + +void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", 512, errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} + + +/* ----------------------------------------------------------------- */ +/* initialize environment, allocate handles, etc. */ +/* ----------------------------------------------------------------- */ + +sb4 init_handles() +{ + if (OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 )) + { + (void) printf("FAILED: OCIInitialize()\n"); + return OCI_ERROR; + } + + /* initialize environment handle */ + if (OCIEnvInit((OCIEnv **) &envhp, (ub4) OCI_DEFAULT, + (size_t) 0, (dvoid **) 0 )) + { + (void) printf("FAILED: OCIEnvInit()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &stmthp, + (ub4) OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + + +/* ----------------------------------------------------------------- */ +/* attach to the server and log on */ +/* ----------------------------------------------------------------- */ + +sb4 log_on() +{ + text *uid = (text *)"CDEMOUCB"; + text *pwd = (text *)"CDEMOUCB"; + text *cstring = (text *) ""; + + /* attach to the server */ + if (OCIServerAttach(srvhp, errhp, (text *) cstring, + (sb4) strlen((char *)cstring), (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIServerAttach()\n"); + return OCI_ERROR; + } + + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) uid, (ub4) strlen((char *)uid), + (ub4) OCI_ATTR_USERNAME, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) pwd, (ub4) strlen((char *)pwd), + (ub4) OCI_ATTR_PASSWORD, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + /* set the server attribute in the service context */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, (ub4) OCI_ATTR_SERVER, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + /* log on */ + if (OCISessionBegin(svchp, errhp, authp, (ub4) OCI_CRED_RDBMS, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCISessionBegin()\n"); + return OCI_ERROR; + } + + /* set the session attribute in the service context */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, (dvoid *) authp, + (ub4) 0, (ub4) OCI_ATTR_SESSION, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; + +} + + +/* ----------------------------------------------------------------- */ +/* Exit program with an exit code. */ +/* ----------------------------------------------------------------- */ +void cleanup() +{ + sword status; + + if (stmthp) + { + if (status = OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT)) + { + (void) printf("Status = %d\n", status); + checkerr(errhp, status); + } + } + + if (srvhp) + { + if (status = OCIHandleFree((dvoid *) srvhp, OCI_HTYPE_SERVER)) + { + (void) printf("Status = %d\n", status); + checkerr(errhp, status); + } + } + + if (errhp) + { + (void) OCIHandleFree((dvoid *) errhp, OCI_HTYPE_ERROR); + } + return; +} + + + +/* ----------------------------------------------------------------- */ +/* Entry callback function for OCIStmtPrepare. This function is */ +/* statically registered (i.e. from within this file). Since, it */ +/* uses (via va_arg) the parametes passed to it, it calls a wrapper */ +/* function that recreates the arglist to be passed to the dynamic */ +/* callback. */ +/* ----------------------------------------------------------------- */ +sword stmtprep_entry_statcbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist) +{ + stat_ctx_struct *loc_ctx; + OCIStmt *stmthp; + OCIError *errhp; + text *sqlstmt; + ub4 stmtlen; + ub4 language; + ub4 mode; + sword retCode = OCI_CONTINUE; + + + /* Retrieve all arguments of OCIStmtPrepare and save */ + /* them so they can be passed on to dynamic-registered */ + /* callback if one was registered */ + + stmthp = va_arg(arglist, OCIStmt *); + errhp = va_arg(arglist, OCIError *); + sqlstmt = va_arg(arglist, text *); + stmtlen = va_arg(arglist, ub4); + language = va_arg(arglist, ub4); + mode = va_arg(arglist, ub4); + + printf("In static entry callback routine for OCIStmtPrepare:\n"); + printf("sql_stmt = [%s]\n\n", sqlstmt); + + + /* If dynamic callback was registered, then make a */ + /* call to the dynamic routine. */ + + loc_ctx = ctxp; + + if (loc_ctx->entry_funcptr) + { + + retCode = stmtprep_wrapper_cbk_fn(loc_ctx->entry_funcptr, + loc_ctx->entry_ctxptr, hndlp, type, fcode, + when, returnCode, errnop, stmthp, errhp, + sqlstmt, stmtlen, language, mode); + } + + return retCode; +} + + +/* ----------------------------------------------------------------- */ +/* Entry wrapper callback function for OCIStmtPrepare. This */ +/* function "recreates the arglist that is expected by the dynamic */ +/* callback. */ +/* ----------------------------------------------------------------- */ +sword stmtprep_wrapper_cbk_fn (OCIUserCallback *funcptr, dvoid *ctxp, dvoid + *hndlp, ub4 type, ub4 fcode, ub4 when, + sword returnCode, sb4 *errnop, ...) +{ + va_list arglist; + sword retCode; + + va_start(arglist, errnop); + + printf("In wrapper callback routine for OCIStmtPrepare:\n"); + + retCode = (*funcptr)(ctxp, hndlp, type, fcode, when, returnCode, errnop, + arglist); + va_end(arglist); + + return retCode; +} + + +/* ----------------------------------------------------------------- */ +/* Exit callback function (static) for OCIStmtPrepare. Since it */ +/* does not utilize any parameters in the arglist, it can pass */ +/* the arglist directly to the dynamic callback. */ +/* ----------------------------------------------------------------- */ +sword stmtprep_exit_statcbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist) +{ + stat_ctx_struct *loc_ctx; + sword retCode = OCI_CONTINUE; + + + printf("\nIn static exit callback routine for OCIStmtPrepare\n"); + + /* If dynamic callback was registered, then make a */ + /* call to the dynamic routine. */ + + loc_ctx = ctxp; + + if (loc_ctx->exit_funcptr) + { + + retCode = (*loc_ctx->exit_funcptr)(loc_ctx->exit_ctxptr, hndlp, type, + fcode, when, returnCode, errnop, arglist); + } + + return retCode; +} + + + +/* end of file cdemoucb.c */ + diff --git a/cdemoucb.sql b/cdemoucb.sql new file mode 100644 index 0000000..2dcf645 --- /dev/null +++ b/cdemoucb.sql @@ -0,0 +1,27 @@ +rem +rem $Header: cdemoucb.sql 10-apr-2007.18:07:12 azhao Exp $ +rem +rem cdemoucb.sql +rem +rem Copyright (c) 1998, 2007, Oracle. All rights reserved. +rem +rem NAME +rem cdemoucb.sql - +rem +rem DESCRIPTION +rem +rem +rem NOTES +rem +rem +rem MODIFIED (MM/DD/YY) +rem azhao 04/10/07 - case sensitive password +rem hdnguyen 11/14/00 - fixed connect internal +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem bgoyal 10/16/98 - Sql for cdemoucb.c +rem bgoyal 10/16/98 - Created +rem +connect / as sysdba; +drop user cdemoucb cascade; +grant connect, resource to cdemoucb identified by CDEMOUCB; + diff --git a/cdemoucbl.c b/cdemoucbl.c new file mode 100644 index 0000000..2ebb344 --- /dev/null +++ b/cdemoucbl.c @@ -0,0 +1,284 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemoucbl.c 14-jul-99.13:18:43 mjaeger Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1998, 1999, Oracle Corporation. All rights reserved. +*/ + +/* + + NAME + cdemoucbl.c - User callback demo program. + + DESCRIPTION + This file contains the routine which is used to + create the shared library to be used for dynamic + callback registration. + + Makefile ociucb.mk is required to compile this file + and for creating shared library. The make command is: + + make -f ociucb.mk user_callback SHARED_LIBNAME=ociucb.so.1.0 \ + OBJS=cdemoucbl.o + + For creating 64-bit shared library make command is: + + make -f ociucb.mk user_callback SHARED_LIBNAME=ociucb.so.1.0 \ + LDFLAGS="\$(LDFLAGS64)" RDBMSLIB="\$(RDBMSLIB64)" \ + LIBHOME="\$(LIBHOME64)" COMPFLAGS="\$(COMPFLAGS64)" \ + LIBD4R= OBJS=cdemoucbl.o + + + The environment variable ORA_OCI_UCBPKG should be set to ociucb. + + setenv ORA_OCI_UCBPKG ociucb + + + PUBLIC FUNCTION(S) + + PRIVATE FUNCTION(S) + + RETURNS + + NOTES + + MODIFIED (MM/DD/YY) + slari 09/10/99 - bg989981: remove envCallback from ociucbInit + slari 08/30/99 - add OCIUcb * + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + slari 11/22/98 - use arglist instead of ellipsis + slari 11/21/98 - conform to new OCIUserCallback with arglist + svedala 10/13/98 - Creation + +*/ + + +#include +#include +#include +#include +#include + + + /* the forward declaration must be done so that + OCIShareLibInit can be passed a pointer to this function + */ + +sword ociucbEnvCallback(OCIEnv *env, ub4 mode, size_t xtramemsz, dvoid *usrmemp, + OCIUcb *ucbDesc); + + +static sword stmtprep_entry_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist); + + +static sword stmtprep_replace_dyncbk_fn(dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist); + +static sword stmtprep_exit_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist); + +struct dyn_ctx_struct /* Context to be passed to */ +{ + char str1[40]; /* dynamic callback function */ +}; + +typedef struct dyn_ctx_struct dyn_ctx_struct; + + + +/*--------------------------------- ociucbInit ---------------------------------*/ + +/* + NAME: + ociucbInit - OCI Shared Library CallBack Main function + + PARAMETERS: + meta - The metacontext + libCtx - The context for this package + argfmt - The package argument format + argc - The number of arguments passed + argv - The arguments to the package + + DESCRIPTION: + This is called by OCI to load and initialize the shared library + (package). + + The OCI shared library initialization is done by passing all the + parameters passed to the the shared library initialization function to + the OCISharedLibInit function. User's environment callback function of + type OCIEnvCallbackType is also passed to the OCISharedLibInit call. + + + RETURNS: + the return code from OCISharedLibInit function. + + NOTES: +*/ + +sword ociucbInit(metaCtx, libCtx, argfmt, argc, argv, envCallback) +dvoid * metaCtx; /* The metacontext */ +dvoid * libCtx; /* The context for this program or package if you + have previously been called. */ +ub4 argfmt; /* What am I supposed to do? */ +sword argc; /* argc if I am being called as a program */ +dvoid * argv[]; /* argv if I am being called as a program */ +{ + return (OCISharedLibInit(metaCtx, libCtx, argfmt, argc, argv, + ociucbEnvCallback)); +} + + + +/* ------------------------------------------------------------- */ +/* Entry point for dynamic callback registration. This routine */ +/* is called if environment variable ORA_OCI_UCBPKG is set */ +/* ------------------------------------------------------------- */ +sword ociucbEnvCallback(env, mode, xtramemsz, usrmemp, ucbDesc) +OCIEnv *env; +ub4 mode; +size_t xtramemsz; +dvoid *usrmemp; +OCIUcb *ucbDesc; +{ + OCISvcCtx *svchp; + OCIError *errhp; + dyn_ctx_struct *dynamic_context; + + dynamic_context = (dyn_ctx_struct *) malloc(sizeof(dyn_ctx_struct)); + + /* copy a string into element str1 of context, this value */ + /* will be printed in dynamic callback function */ + + strcpy(dynamic_context->str1, "Dynamic_Context_Test_String"); + + + /* register the dynamic callback function */ + + + /* Note that the replacement callback function in the + preferred way of using the ucbDesc passed-in in the + EnvCallbackk function */ + + if (OCIUserCallbackRegister(env, OCI_HTYPE_ENV, env, + stmtprep_replace_dyncbk_fn, + dynamic_context, OCI_FNCODE_STMTPREPARE, + OCI_UCBTYPE_REPLACE, ucbDesc)) + { + printf("cdemoucbl: OCIUserCallbackRegister returns error\n"); + return OCI_ERROR; + } + + /* The entry and exit callback functions are registered + using a NULL UCB Descriptor so that the application is + responsible for chaining them */ + + if (OCIUserCallbackRegister(env, OCI_HTYPE_ENV, env, + stmtprep_entry_dyncbk_fn, + dynamic_context, OCI_FNCODE_STMTPREPARE, + OCI_UCBTYPE_ENTRY, (OCIUcb *)0)) + { + printf("cdemoucbl: OCIUserCallbackRegister returns error\n"); + return OCI_ERROR; + } + + if (OCIUserCallbackRegister(env, OCI_HTYPE_ENV, env, + stmtprep_exit_dyncbk_fn, + dynamic_context, OCI_FNCODE_STMTPREPARE, + OCI_UCBTYPE_EXIT, (OCIUcb *)0)) + { + printf("cdemoucbl: OCIUserCallbackRegister returns error\n"); + return OCI_ERROR; + } + + return OCI_CONTINUE; +} + + + +/* ------------------------------------------------------------------ */ +/* Entry callback function registered for OCIStmtPrepare. This */ +/* function is registered dynamically from function ociucbEnvCallback */ +/* ------------------------------------------------------------------ */ +sword stmtprep_entry_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist) +{ + dyn_ctx_struct *loc_ctx; + text *sqlstmt; + + va_arg(arglist, dvoid *); + va_arg(arglist, dvoid *); + sqlstmt = va_arg(arglist, text *); + + loc_ctx = (dyn_ctx_struct *) ctxp; + + printf("In dynamic entry callback function for OCIStmtPrepare:\n"); + printf("sql_stmt = [%s]\n", sqlstmt); + printf("Context string = [%s]\n", loc_ctx->str1); + + return OCI_CONTINUE; +} + + + +/* ------------------------------------------------------------------ */ +/* Replacement callback function registered for OCIStmtPrepare. This */ +/* function is registered dynamically from function ociucbEnvCallback */ +/* ------------------------------------------------------------------ */ +sword stmtprep_replace_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist) +{ + dyn_ctx_struct *loc_ctx; + text *sqlstmt; + + va_arg(arglist, dvoid *); + va_arg(arglist, dvoid *); + sqlstmt = va_arg(arglist, text *); + + loc_ctx = (dyn_ctx_struct *) ctxp; + + printf("In dynamic replacement callback function for OCIStmtPrepare:\n"); + printf("sql_stmt = [%s]\n", sqlstmt); + printf("Context string = [%s]\n", loc_ctx->str1); + + return OCI_CONTINUE; +} + + + +/* ------------------------------------------------------------------ */ +/* Exit callback function registered for OCIStmtPrepare. This */ +/* function is registered dynamically from function ociucbEnvCallback */ +/* ------------------------------------------------------------------ */ +sword stmtprep_exit_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist) +{ + dyn_ctx_struct *loc_ctx; + text *sqlstmt; + + va_arg(arglist, dvoid *); + va_arg(arglist, dvoid *); + sqlstmt = va_arg(arglist, text *); + + loc_ctx = (dyn_ctx_struct *) ctxp; + + printf("In dynamic exit callback function for OCIStmtPrepare:\n"); + printf("sql_stmt = [%s]\n", sqlstmt); + printf("Context string = [%s]\n", loc_ctx->str1); + + return OCI_CONTINUE; +} + + + + + +/* end of file cdemoucbl.c */ + diff --git a/cdemouni.c b/cdemouni.c new file mode 100644 index 0000000..a11f2c7 --- /dev/null +++ b/cdemouni.c @@ -0,0 +1,588 @@ +/* Copyright (c) 2001, 2002, Oracle Corporation. All rights reserved. */ + +/* + + NAME + cdemouni.c - a simple program for OCI UTF16 API + + DESCRIPTION + This is a demo for OCI UTF16 API. + + UTF16 is the encoding scheme of choice for internationalized + application developers, due to the support provided by JAVA + and MS windows platforms. This demo tries to illustrate the + fixed width Unicode support for UTF-16 encoded strings. + + EXPORT FUNCTION(S) + + + INTERNAL FUNCTION(S) + + + STATIC FUNCTION(S) + + + NOTES + + + MODIFIED (MM/DD/YY) + aliu 03/14/02 - add conn to report_error on line 409. + anzhang 12/04/01 - fix bug 2116117 + anzhang 03/12/01 - Merged anzhang_utf16demo + anzhang 03/12/01 - Creation + +*/ + +#ifndef ORASTDLIB +# include +# define ORASTDLIB +#endif /* !ORASTDLIB */ + +#ifndef ORASTDIO +# include +# define ORASTDIO +#endif /* ifndef ORASTDIO */ + +#ifndef ORASTRING +#include +#define ORASTRING +#endif /* ifndef ORASTRING */ + +#ifndef OCI_ORACLE +#include +#endif /* ifndef OCI_ORACLE */ + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + + +#define DISCARD (void) + +/* database connection context */ +struct db_conn { + OCIEnv * envhp; /* OCI environment handle */ + OCIEnv * cnvhp; /* OCI environment handle for conversion */ + OCIServer * srvhp; /* OCI server handle */ + OCIError * errhp; /* OCI error handle */ + OCISvcCtx * svchp; /* OCI service context */ + OCISession * authp; /* OCI session handle */ + + boolean attached; /* if server is attached */ + boolean is_logged_on; /* if we have logged on to server */ +}; +typedef struct db_conn db_conn; + +/*--------------------------------------------------------------------------- + STATIC FUNCTION DECLARATIONS + ---------------------------------------------------------------------------*/ + +/* Static Function */ +static db_conn* db_conn_init(); /* initialize database connection context */ + +static void db_conn_free(); /* Environment clean up */ + +static void connect(); /* function to initialize connection */ + +static sb4 ustrlen(); /* calculate length for UTF16-string */ + +static void report_error(); /* print out error message */ + +static void checkerr(); /* report error if there is one and exit */ + +static void execute(); /* execute a statement */ + +/* display column data for select statement */ +static void display_column(); + +/* convert a native text to unicode */ +static text* text2unicode(); + +/* convert a unicode string to native text */ +static text* unicode2text(); + +/* ----------------------------------------------------------------- */ +/* db_conn_init: initialize a connection context */ +/* ----------------------------------------------------------------- */ +db_conn* +db_conn_init() +{ + sword retval; + /* allocate memory */ + db_conn * conn = (db_conn *)calloc(1,sizeof(db_conn)); + if (conn == NULL) + return NULL; + + conn->envhp = (OCIEnv*)0; + conn->cnvhp = (OCIEnv*)0; + conn->srvhp = (OCIServer*)0; + conn->svchp = (OCISvcCtx*)0; + conn->authp = (OCISession*)0; + conn->attached = FALSE; + conn->is_logged_on = FALSE; + + /* create OCI environment handle */ + if ((retval = OCIEnvCreate((OCIEnv **) &conn->envhp, (ub4) OCI_UTF16, + (dvoid *)0, (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0, (size_t) 0, + (dvoid **) 0)) || + (retval = OCIEnvCreate((OCIEnv **) &conn->cnvhp, (ub4) OCI_DEFAULT, + (dvoid *)0, (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0, (size_t) 0, + (dvoid **) 0))) + { + DISCARD fprintf(stdout, "FAILED: OCIEnvCreate() retval = %d\n", retval); + exit(OCI_ERROR); + } + + /* allocation of service context handle */ + if (retval = OCIHandleAlloc((dvoid *) conn->envhp, (dvoid **) &conn->svchp, + (ub4) OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0)) + { + DISCARD fprintf(stdout, "FAILED: OCIHandleAlloc() on svchp, RC = %d\n", + retval); + db_conn_free(conn); + exit(OCI_ERROR); + } + + /* allocate error handle */ + if (retval = OCIHandleAlloc((dvoid *) conn->envhp, (dvoid **) &conn->errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + { + DISCARD fprintf(stdout, "FAILED: OCIHandleAlloc() on errhp, RC = %d\n", + retval); + db_conn_free(conn); + exit(OCI_ERROR); + } + + /* allocate server handle */ + if (retval = OCIHandleAlloc((dvoid *) conn->envhp, (dvoid **) &conn->srvhp, + (ub4) OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0)) + { + DISCARD fprintf(stdout, "FAILED: OCIHandleAlloc() on srvhp, RC = %d\n", + retval); + db_conn_free(conn); + } + + /* allocation of session handle */ + if (retval = OCIHandleAlloc((dvoid *) conn->envhp, (dvoid **) &conn->authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0)) + { + DISCARD fprintf(stdout, "FAILED: OCIHandleAlloc() on authp, RC = %d\n", + retval); + db_conn_free(conn); + } + + return conn; +} + +/* ----------------------------------------------------------------- */ +/* db_conn_free: Free a connect context, clean up */ +/* ----------------------------------------------------------------- */ +void +db_conn_free(conn) + db_conn * conn; +{ + /* log off the user if we are logged on */ + if (conn->is_logged_on) + DISCARD OCISessionEnd(conn->svchp, conn->errhp, conn->authp, (ub4) 0); + + /* detach server */ + if (conn->attached) + DISCARD OCIServerDetach(conn->srvhp, conn->errhp, (ub4) OCI_DEFAULT); + + /* free server handle */ + if (conn->srvhp) + DISCARD OCIHandleFree((dvoid *) conn->srvhp, (ub4) OCI_HTYPE_SERVER); + /* free service context */ + if (conn->svchp) + DISCARD OCIHandleFree((dvoid *) conn->svchp, (ub4) OCI_HTYPE_SVCCTX); + /* free error handle */ + if (conn->errhp) + DISCARD OCIHandleFree((dvoid *) conn->errhp, (ub4) OCI_HTYPE_ERROR); + /* free environment handle */ + if (conn->authp) + DISCARD OCIHandleFree((dvoid *) conn->authp, (ub4) OCI_HTYPE_SESSION); + /* deallocate connect object */ + free(conn); +} + +/* ----------------------------------------------------------------- */ +/* initialize environment, allocate handles, make connection, etc. */ +/* ----------------------------------------------------------------- */ +void +connect(conn,dblink,username,password) + db_conn *conn; /* database connection */ + text *dblink; /* Connection string */ + text *username; /* username */ + text *password; /* password */ +{ + sword retval; /* return value of OCI funcs */ + + /* log on to server */ + if (retval = OCIServerAttach(conn->srvhp, conn->errhp, dblink, + ustrlen((void *)dblink)*sizeof(utext), OCI_DEFAULT)) + { + DISCARD fprintf(stdout, "FAILED: OCIServerAttach(), RC = %d\n", retval); + db_conn_free(conn); + exit(OCI_ERROR); + } + + conn->attached = TRUE; + + checkerr(conn, OCIAttrSet((dvoid *) conn->svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) conn->srvhp, (ub4) 0, + (ub4) OCI_ATTR_SERVER, conn->errhp)); + + checkerr(conn, OCIAttrSet((dvoid *) conn->authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) username, (ub4) ustrlen((void *)username)*sizeof(utext), + (ub4) OCI_ATTR_USERNAME, conn->errhp)); + + checkerr(conn, OCIAttrSet((dvoid *) conn->authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) password, (ub4) ustrlen((void *)password)*sizeof(utext), + (ub4) OCI_ATTR_PASSWORD, conn->errhp)); + + /* log on to server */ + checkerr(conn, OCISessionBegin(conn->svchp, conn->errhp,conn->authp, + OCI_CRED_RDBMS, OCI_DEFAULT)); + conn->is_logged_on = TRUE; + + checkerr(conn, OCIAttrSet((dvoid *) conn->svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) conn->authp, (ub4) 0, + (ub4) OCI_ATTR_SESSION, conn->errhp)); +} + +/* ----------------------------------------------------------------- */ +/* display_column: display the data after execution */ +/* ----------------------------------------------------------------- */ +void +display_column(stmhp, conn) + OCIStmt *stmhp; + db_conn *conn; +{ + text *pcoln[20]; /* column name: OCI_ATTR_NAME */ + ub2 pcoll[20]; /* column size: OCI_ATTR_DATA_SIZE */ + ub2 podt[20]; /* data type: OCI_ATTR_DATA_TYPE */ + ub1 isnull[20]; /* is this column NULL? */ + ub4 namelen[20]; + + eword i, pos; /* iterators */ + ub4 parmcnt = 0; /* parameter count */ + sword retval = 0; /* return value from OCI functions */ + OCIParam *parmdp; /* a parameter handle */ + + OCIDefine *dfnp[20]; /* define handle pointer */ + text *column[20]; /* buffers to hold data fetched */ + + memset((void *) pcoln, 0, 20 * sizeof(text *)); + /* get parameter count */ + checkerr(conn, OCIAttrGet((dvoid *) stmhp, (ub4)OCI_HTYPE_STMT, + (dvoid *) &parmcnt, + (ub4 *) 0, (ub4)OCI_ATTR_PARAM_COUNT, conn->errhp)); + + /* iterate every column, display data */ + for (pos = 1; pos <= parmcnt; pos++) + { + retval = OCIParamGet((dvoid *)stmhp, (ub4)OCI_HTYPE_STMT, conn->errhp, + (dvoid **)&parmdp, (ub4) pos ); + + if (retval) + { + DISCARD fprintf(stdout,"OCIParamGet RC=%d, position=%d\n", retval, pos); + continue; + } + + /* get the column name */ + checkerr(conn, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &pcoln[pos-1], + (ub4 *) &namelen[pos-1], (ub4) OCI_ATTR_NAME, + (OCIError *) conn->errhp)); + + /* get the data size */ + checkerr(conn, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &pcoll[pos-1], + (ub4 *) 0, (ub4) OCI_ATTR_DATA_SIZE, + (OCIError *) conn->errhp)); + + /* get the data type */ + checkerr(conn, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &podt[pos-1], + (ub4 *) 0, (ub4) OCI_ATTR_DATA_TYPE, + (OCIError *) conn->errhp)); + + /* is column null */ + checkerr(conn, OCIAttrGet((dvoid*) parmdp, (ub4) OCI_DTYPE_PARAM, + (dvoid*) &isnull[pos-1], + (ub4 *) 0, (ub4) OCI_ATTR_IS_NULL, + (OCIError *) conn->errhp)); + + } + + for (i = 1; i <= parmcnt; i++) + { + /* print out the column name */ + DISCARD fprintf(stdout, "%-*s ", pcoll[i-1], + unicode2text(conn, (void *) pcoln[i-1], + ustrlen ((void *)pcoln[i-1]))); + column[i-1] = (text *) calloc( pcoll[i-1] + 1, sizeof(utext)); + + checkerr(conn, OCIDefineByPos(stmhp, &dfnp[i-1], conn->errhp, (ub4)i, + (dvoid *)column[i-1], + (sb4)((pcoll[i-1]+1)*2),(ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, (ub2 *)0, + (ub4)OCI_DEFAULT)); + } + DISCARD fprintf(stdout, "\n========================================\n"); + + /* since we define after execute, we need to fetch */ + checkerr(conn, OCIStmtFetch(stmhp, conn->errhp, (ub4) 1, (ub4) OCI_FETCH_NEXT, + (ub4) OCI_DEFAULT)); + do + { + for (i = 0; i < parmcnt; i++) + { + if (ustrlen((void *)column[i]) != 0) + { + /* display the data */ + DISCARD fprintf(stdout, "%-*s ", pcoll[i], + unicode2text(conn, (void *)column[i], + ustrlen((void *)column[i]))); + /* clean up data */ + memset(column[i], 0, (pcoll[i] + 1)*sizeof(utext)); + } + } + DISCARD fprintf(stdout, "\n"); + } + /* continue to fetch */ + while ((retval = OCIStmtFetch(stmhp, conn->errhp, (ub4) 1, (ub4) OCI_FETCH_NEXT, + (ub4) OCI_DEFAULT)) == OCI_SUCCESS || + retval == OCI_SUCCESS_WITH_INFO); + + + /* Ignore NO DATA FOUND error */ + if (retval != OCI_NO_DATA) + { + checkerr(conn,retval); + } +} + +/* ----------------------------------------------------------------- */ +/* execute: parse and execute a sql statement */ +/* ----------------------------------------------------------------- */ + +void +execute(conn,stmt,func) + db_conn *conn; + text *stmt; + dvoid (*func)(OCIStmt * stmhp, db_conn * conn); +{ + sword retval; + OCIStmt * stmtp; + + /* allocate a statement handle */ + if ( retval = OCIHandleAlloc((dvoid *)conn->envhp, (dvoid **)&stmtp, + OCI_HTYPE_STMT, 0, (dvoid **) 0) ) + { + DISCARD fprintf(stdout, "FAILED: OCIHandleAlloc() on stmtp, RC = %d\n", + retval); + db_conn_free(conn); + exit(OCI_ERROR); + } + + /* Parse the statement */ + if (retval = OCIStmtPrepare (stmtp, conn->errhp, (CONST text *) stmt, + (ub4) ustrlen((void *)stmt)*sizeof(utext), + OCI_NTV_SYNTAX, OCI_DEFAULT)) + { + DISCARD fprintf(stdout, "FAILED: OCIStmtPrepare() on stmtp, RC = %d\n", + retval); + report_error(conn); + db_conn_free(conn); + exit(OCI_ERROR); + } + + if ( retval = OCIStmtExecute (conn->svchp, stmtp, conn->errhp, + 0, 0, (const OCISnapshot *) 0, (OCISnapshot *) 0, OCI_DEFAULT)) + { + report_error(conn); + db_conn_free(conn); + } + + if (func != NULL) + (*func)(stmtp, conn); + + /* free the statement handle */ + if (stmtp) + DISCARD OCIHandleFree((dvoid *) stmtp, (ub4) OCI_HTYPE_STMT); + +} + +/* ----------------------------------------------------------------- */ +/* ustrlen: calculate the length of UTF16 string */ +/* ----------------------------------------------------------------- */ + +sb4 +ustrlen(vustr) + void * vustr; +{ + utext *ustr = (utext *)vustr; + + utext * p = (utext*) ustr; + while (*p) + p++; + return (sb4)(p - ustr); +} + +/* ----------------------------------------------------------------- */ +/* report_error: get error code and message */ +/* ----------------------------------------------------------------- */ +void +report_error(conn) + db_conn * conn; +{ + text msgbuf[1024]; + sb4 errcode; + + DISCARD OCIErrorGet ((dvoid *)conn->errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + + DISCARD fprintf(stdout,(const char*) + unicode2text(conn,(void*)msgbuf,1024)); +} + +/* ----------------------------------------------------------------- */ +/* checkerr: print error message and exit if OCI func failed */ +/* ----------------------------------------------------------------- */ +void checkerr(conn, status) + db_conn *conn; + sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + return; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + report_error(conn); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } + + db_conn_free(conn); + exit(1); +} + +/* ----------------------------------------------------------------- */ +/* text2unicode: convert a string to UTF16 encoding */ +/* ----------------------------------------------------------------- */ +text* text2unicode(conn,src,srclen) + db_conn * conn; + const text* src; + size_t srclen; +{ + text* result = NULL; + size_t resultlen = (srclen+1)*sizeof(utext); + void *temp; + + result = (text*)calloc(resultlen,sizeof(text)); + temp = (void *)result; + + if (OCICharSetToUnicode((dvoid *)conn->cnvhp, (ub2 *)temp, + resultlen, src, srclen, NULL)) + { + fprintf(stderr,"OCICharSetToUnicode failed\n"); + free(temp); + return NULL; + } + result = (text *)temp; + + return result; +} + +/* ----------------------------------------------------------------- */ +/* unicode2text: convert a given UTF16 text */ +/* string to native encoding */ +/* ----------------------------------------------------------------- */ +text* unicode2text(conn,src,srclen) + db_conn * conn; + void* src; + size_t srclen; +{ + text *result = NULL; + size_t resultlen = ustrlen((void *)src) + 1; + result = (text*)calloc(resultlen,sizeof(text)); + + if (OCIUnicodeToCharSet((dvoid*)conn->cnvhp,result, + resultlen, (CONST ub2 *)src, srclen, NULL)) + { + fprintf(stderr,"OCIUnicodeToCharSet failed\n"); + free(result); + return NULL; + } + + return result; +} + +#define LINK "" +#define USER "hr" +#define PASS "hr" +#define SQLS "SELECT FIRST_NAME, LAST_NAME FROM EMPLOYEES" + +/* ----------------------------------------------------------------- */ +/* main routine */ +/* ----------------------------------------------------------------- */ +int main() +{ + db_conn *conn = NULL; /* db connection object */ + text *user = NULL; /* username */ + text *pass = NULL; /* password */ + text *dblink = NULL; /* database descriptor */ + text *sqlstmt = NULL; /* sql statement to be excuted */ + + conn = db_conn_init(); /* initilalize the connect object */ + + /* convert the all text strings to UTF16 encoding */ + dblink = text2unicode(conn,(text*)LINK, strlen(LINK)); + user = text2unicode(conn,(text*)USER, strlen(USER)); + pass = text2unicode(conn,(text*)PASS, strlen(PASS)); + sqlstmt = text2unicode(conn,(text*)SQLS, strlen(SQLS)); + + /* connect to database */ + connect(conn,dblink,user,pass); + execute(conn,sqlstmt,display_column); + + /* clean up */ + db_conn_free(conn); + free(dblink); + free(user); + free(pass); + free(sqlstmt); + + return OCI_SUCCESS; +} + + +/* end of file cdemouni.c */ diff --git a/cdemoup1.c b/cdemoup1.c new file mode 100644 index 0000000..775aee3 --- /dev/null +++ b/cdemoup1.c @@ -0,0 +1,266 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemoup1.c 20-oct-99.14:12:18 svedala Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) Oracle Corporation 1999, 2000. All Rights Reserved. */ + +/* + + NAME + cdemoup1.c - User callback library routine 1. + + DESCRIPTION + The library cdemoup1 for user callback is created using this + file. The command for compiling and creating the library is: + + make -f ociucb.mk user_callback SHARED_LIBNAME=cdemoup1.so.1.0 \ + OBJS=cdemoup1.o + + The make file ociucb.mk is located in the demo directory. + + + PUBLIC FUNCTION(S) + None + + PRIVATE FUNCTION(S) + As described below + + RETURNS + + NOTES + + MODIFIED (MM/DD/YY) + jchai 04/26/00 - fix bug1238864 + svedala 10/20/99 - Creation + +*/ + +#include +#include +#include +#include +#include + + + /* the forward declaration must be done so that OCIShareLibInit + can be passed a pointer to this function */ + +sword cdemoup1EnvCallback(OCIEnv *env, ub4 mode, size_t xtramemsz, + dvoid *usrmemp, OCIUcb *ucbDesc); + + +static sword stmtprep_entry_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist); + + +static sword stmtprep_replace_dyncbk_fn(dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist); + +static sword stmtprep_exit_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist); + +struct dyn_ctx_struct /* Context to be passed to */ +{ + char str1[40]; /* dynamic callback function */ +}; + +static ub4 id = 1; /* library id */ + +typedef struct dyn_ctx_struct dyn_ctx_struct; + + + +/*--------------------------- cdemoup1Init ---------------------------------*/ + +/* + NAME: + cdemoup1Init - OCI Shared Library CallBack Main function + + PARAMETERS: + meta - The metacpmtext for the program manager + mycx - The primary context for the package + argfmt - The behviour that package must undergo + argc - The number arguments passed + argv - The arguments to the package + envCallback - pointer to user's environment callback function + + DESCRIPTION: + This is called by OCI to load and initialize the shared library. + + The OCI shared library initialization is done by passing all the + parameters passed to the the shared library initialization function to + the OCISharedLibInit function. User's environment callback function of + type OCIEnvCallbackType is also passed to the OCISharedLibInit call. + + + RETURNS: + the return code from OCISharedLibInit function. + + NOTES: +*/ + +sword cdemoup1Init(metaCtx, libCtx, argfmt, argc, argv, envCallback) +dvoid *metaCtx; /* The metacontext */ +dvoid *libCtx; /* The context for this program or package if you + have previously been called. */ +ub4 argfmt; /* What am I supposed to do? */ +sword argc; /* argc if I am being called as a program */ +dvoid *argv[]; /* argv if I am being called as a program */ +OCIEnvCallbackType envCallback; /* user's environment callback function */ +{ + return (OCISharedLibInit(metaCtx, libCtx, argfmt, argc, argv, + cdemoup1EnvCallback)); +} + + + +/* ------------------------------------------------------------- */ +/* Entry point for dynamic callback registration. This routine */ +/* is called if environment variable ORA_OCI_UCBPKG is set */ +/* ------------------------------------------------------------- */ +sword cdemoup1EnvCallback(env, mode, xtramemsz, usrmemp, ucbDesc) +OCIEnv *env; +ub4 mode; +size_t xtramemsz; +dvoid *usrmemp; +OCIUcb *ucbDesc; +{ + OCISvcCtx *svchp; + OCIError *errhp; + dyn_ctx_struct *dynamic_context; + + dynamic_context = (dyn_ctx_struct *) malloc(sizeof(dyn_ctx_struct)); + + /* copy a string into element str1 of context, this value */ + /* will be printed in dynamic callback function */ + + strcpy(dynamic_context->str1, "Dynamic_Context_Test_String"); + + + /* register the dynamic callback function */ + + + /* Note that the replacement callback function in the preferred + way of using the ucbDesc passed-in in the EnvCallbackk function */ + + if (OCIUserCallbackRegister(env, OCI_HTYPE_ENV, env, + stmtprep_replace_dyncbk_fn, + dynamic_context, OCI_FNCODE_STMTPREPARE, + OCI_UCBTYPE_REPLACE, ucbDesc)) + { + printf("Library%d: OCIUserCallbackRegister returns error\n", id); + return OCI_ERROR; + } + + if (OCIUserCallbackRegister(env, OCI_HTYPE_ENV, env, + stmtprep_entry_dyncbk_fn, + dynamic_context, OCI_FNCODE_STMTPREPARE, + OCI_UCBTYPE_ENTRY, ucbDesc)) + { + printf("Library%d: OCIUserCallbackRegister returns error\n", id); + return OCI_ERROR; + } + + if (OCIUserCallbackRegister(env, OCI_HTYPE_ENV, env, + stmtprep_exit_dyncbk_fn, + dynamic_context, OCI_FNCODE_STMTPREPARE, + OCI_UCBTYPE_EXIT, ucbDesc)) + { + printf("Library%d: OCIUserCallbackRegister returns error\n", id); + return OCI_ERROR; + } + + return OCI_CONTINUE; +} + + + +/* -------------------------------------------------------------------- */ +/* Entry callback function registered for OCIStmtPrepare. This */ +/* function is registered dynamically from function cdemoup1EnvCallback */ +/* -------------------------------------------------------------------- */ +sword stmtprep_entry_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist) +{ + dyn_ctx_struct *loc_ctx; + text *sqlstmt; + + va_arg(arglist, dvoid *); + va_arg(arglist, dvoid *); + sqlstmt = va_arg(arglist, text *); + + loc_ctx = (dyn_ctx_struct *) ctxp; + + printf( + "Library%d: In dynamic entry callback function for OCIStmtPrepare:\n", id); + printf("Library%d: sql_stmt = [%s]\n", id, sqlstmt); + printf("Library%d: Context string = [%s]\n", id, loc_ctx->str1); + + return OCI_CONTINUE; +} + + + +/* -------------------------------------------------------------------- */ +/* Replacement callback function registered for OCIStmtPrepare. This */ +/* function is registered dynamically from function cdemoup1EnvCallback */ +/* -------------------------------------------------------------------- */ +sword stmtprep_replace_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist) +{ + dyn_ctx_struct *loc_ctx; + text *sqlstmt; + + va_arg(arglist, dvoid *); + va_arg(arglist, dvoid *); + sqlstmt = va_arg(arglist, text *); + + loc_ctx = (dyn_ctx_struct *) ctxp; + + printf( + "Library%d: In dynamic replacement callback function for OCIStmtPrepare:\n", + id); + printf("Library%d: sql_stmt = [%s]\n", id, sqlstmt); + printf("Library%d: Context string = [%s]\n", id, loc_ctx->str1); + + return OCI_CONTINUE; +} + + + +/* -------------------------------------------------------------------- */ +/* Exit callback function registered for OCIStmtPrepare. This */ +/* function is registered dynamically from function cdemoup1EnvCallback */ +/* -------------------------------------------------------------------- */ +sword stmtprep_exit_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist) +{ + dyn_ctx_struct *loc_ctx; + text *sqlstmt; + + va_arg(arglist, dvoid *); + va_arg(arglist, dvoid *); + sqlstmt = va_arg(arglist, text *); + + loc_ctx = (dyn_ctx_struct *) ctxp; + + printf( + "Library%d: In dynamic exit callback function for OCIStmtPrepare:\n", id); + printf("Library%d: sql_stmt = [%s]\n", id, sqlstmt); + printf("Library%d: Context string = [%s]\n", id, loc_ctx->str1); + + return OCI_CONTINUE; +} + + + + +/* end of file cdemoup1.c */ + diff --git a/cdemoup2.c b/cdemoup2.c new file mode 100644 index 0000000..4871cb2 --- /dev/null +++ b/cdemoup2.c @@ -0,0 +1,267 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemoup2.c 20-oct-99.14:15:13 svedala Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) Oracle Corporation 1999, 2000. All Rights Reserved. */ + +/* + + NAME + cdemoup2.c - User callback library routine 2. + + DESCRIPTION + The library cdemoup2 for user callback is created using this + file. The command for compiling and creating the library is: + + make -f ociucb.mk user_callback SHARED_LIBNAME=cdemoup2.so.1.0 \ + OBJS=cdemoup2.o + + The make file ociucb.mk is located in the demo directory. + + + PUBLIC FUNCTION(S) + None. + + PRIVATE FUNCTION(S) + As described below. + + RETURNS + + NOTES + + MODIFIED (MM/DD/YY) + jchai 04/26/00 - fix bug1238864 + svedala 10/20/99 - Creation + +*/ + +#include +#include +#include +#include +#include + + + /* the forward declaration must be done so that OCIShareLibInit + can be passed a pointer to this function */ + +sword cdemoup2EnvCallback(OCIEnv *env, ub4 mode, size_t xtramemsz, dvoid + *usrmemp, OCIUcb *ucbDesc); + + +static sword stmtprep_entry_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist); + + +static sword stmtprep_replace_dyncbk_fn(dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist); + +static sword stmtprep_exit_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist); + +struct dyn_ctx_struct /* Context to be passed to */ +{ + char str1[40]; /* dynamic callback function */ +}; + +static ub4 id = 2; /* library id */ + +typedef struct dyn_ctx_struct dyn_ctx_struct; + + + +/*---------------------------- cdemoup2Init ---------------------------------*/ + +/* + NAME: + cdemoup2Init - OCI Shared Library CallBack Main function + + PARAMETERS: + meta - The metacpmtext for the program manager + mycx - The primary context for the package + argfmt - The behviour that package must undergo + argc - The number arguments passed + argv - The arguments to the package + envCallback - pointer to user's environment callback function + + DESCRIPTION: + This is called by OCI to load and initialize the shared library. + + The OCI shared library initialization is done by passing all the + parameters passed to the the shared library initialization function to + the OCISharedLibInit function. User's environment callback function of + type OCIEnvCallbackType is also passed to the OCISharedLibInit call. + + + RETURNS: + the return code from OCISharedLibInit function. + + NOTES: +*/ + +sword cdemoup2Init(metaCtx, libCtx, argfmt, argc, argv, envCallback) +dvoid * metaCtx; /* The metacontext */ +dvoid * libCtx; /* The context for this program or package if you + have previously been called. */ +ub4 argfmt; /* What am I supposed to do? */ +sword argc; /* argc if I am being called as a program */ +dvoid * argv[]; /* argv if I am being called as a program */ +OCIEnvCallbackType envCallback; /* user's environment callback function */ +{ + return (OCISharedLibInit(metaCtx, libCtx, argfmt, argc, argv, + cdemoup2EnvCallback)); +} + + + +/* ------------------------------------------------------------- */ +/* Entry point for dynamic callback registration. This routine */ +/* is called if environment variable ORA_OCI_UCBPKG is set */ +/* ------------------------------------------------------------- */ +sword cdemoup2EnvCallback(env, mode, xtramemsz, usrmemp, ucbDesc) +OCIEnv *env; +ub4 mode; +size_t xtramemsz; +dvoid *usrmemp; +OCIUcb *ucbDesc; +{ + OCISvcCtx *svchp; + OCIError *errhp; + dyn_ctx_struct *dynamic_context; + + dynamic_context = (dyn_ctx_struct *) malloc(sizeof(dyn_ctx_struct)); + + /* copy a string into element str1 of context, this value */ + /* will be printed in dynamic callback function */ + + strcpy(dynamic_context->str1, "Dynamic_Context_Test_String"); + + + /* register the dynamic callback function */ + + + /* Note that the replacement callback function in the + preferred way of using the ucbDesc passed-in in the + EnvCallbackk function */ + + if (OCIUserCallbackRegister(env, OCI_HTYPE_ENV, env, + stmtprep_replace_dyncbk_fn, + dynamic_context, OCI_FNCODE_STMTPREPARE, + OCI_UCBTYPE_REPLACE, ucbDesc)) + { + printf("Library%d: OCIUserCallbackRegister returns error\n", id); + return OCI_ERROR; + } + + if (OCIUserCallbackRegister(env, OCI_HTYPE_ENV, env, + stmtprep_entry_dyncbk_fn, + dynamic_context, OCI_FNCODE_STMTPREPARE, + OCI_UCBTYPE_ENTRY, ucbDesc)) + { + printf("Library%d: OCIUserCallbackRegister returns error\n", id); + return OCI_ERROR; + } + + if (OCIUserCallbackRegister(env, OCI_HTYPE_ENV, env, + stmtprep_exit_dyncbk_fn, + dynamic_context, OCI_FNCODE_STMTPREPARE, + OCI_UCBTYPE_EXIT, ucbDesc)) + { + printf("Library%d: OCIUserCallbackRegister returns error\n", id); + return OCI_ERROR; + } + + return OCI_CONTINUE; +} + + + +/* -------------------------------------------------------------------- */ +/* Entry callback function registered for OCIStmtPrepare. This */ +/* function is registered dynamically from function cdemoup2EnvCallback */ +/* -------------------------------------------------------------------- */ +sword stmtprep_entry_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist) +{ + dyn_ctx_struct *loc_ctx; + text *sqlstmt; + + va_arg(arglist, dvoid *); + va_arg(arglist, dvoid *); + sqlstmt = va_arg(arglist, text *); + + loc_ctx = (dyn_ctx_struct *) ctxp; + + printf("Library%d: In dynamic entry callback function for OCIStmtPrepare:\n", + id); + printf("Library%d: sql_stmt = [%s]\n", id, sqlstmt); + printf("Library%d: Context string = [%s]\n", id, loc_ctx->str1); + + return OCI_CONTINUE; +} + + + +/* -------------------------------------------------------------------- */ +/* Replacement callback function registered for OCIStmtPrepare. This */ +/* function is registered dynamically from function cdemoup2EnvCallback */ +/* -------------------------------------------------------------------- */ +sword stmtprep_replace_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist) +{ + dyn_ctx_struct *loc_ctx; + text *sqlstmt; + + va_arg(arglist, dvoid *); + va_arg(arglist, dvoid *); + sqlstmt = va_arg(arglist, text *); + + loc_ctx = (dyn_ctx_struct *) ctxp; + + printf( + "Library%d: In dynamic replacement callback function for OCIStmtPrepare:\n", + id); + printf("Library%d: sql_stmt = [%s]\n", id, sqlstmt); + printf("Library%d: Context string = [%s]\n", id, loc_ctx->str1); + + return OCI_CONTINUE; +} + + + +/* -------------------------------------------------------------------- */ +/* Exit callback function registered for OCIStmtPrepare. This */ +/* function is registered dynamically from function cdemoup2EnvCallback */ +/* -------------------------------------------------------------------- */ +sword stmtprep_exit_dyncbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist) +{ + dyn_ctx_struct *loc_ctx; + text *sqlstmt; + + va_arg(arglist, dvoid *); + va_arg(arglist, dvoid *); + sqlstmt = va_arg(arglist, text *); + + loc_ctx = (dyn_ctx_struct *) ctxp; + + printf("Library%d: In dynamic exit callback function for OCIStmtPrepare:\n", + id); + printf("Library%d: sql_stmt = [%s]\n", id, sqlstmt); + printf("Library%d: Context string = [%s]\n", id, loc_ctx->str1); + + return OCI_CONTINUE; +} + + + + +/* end of file cdemoup2.c */ + diff --git a/cdemoupk.c b/cdemoupk.c new file mode 100644 index 0000000..8e70a18 --- /dev/null +++ b/cdemoupk.c @@ -0,0 +1,466 @@ +#ifdef RCSID +static char *RCSid = + "$Header: cdemoupk.c 15-feb-2007.10:21:02 aliu Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 2007, Oracle. All rights reserved. */ + +/* + + NAME + cdemoupk.c - User callbacks demo program with multiple packages. + + DESCRIPTION + This programs tests loading of multiple packages. + + The dynamic callback files cdemoup1.c and cdemoup2.c need + to be linked into shared libraries using the make file provided, + see comments in cdemoup1.c for more details. + + Callback "chaining" is demonstrated as follows: If + ORA_OCI_UCBPKG is set then the dynamic callbacks are + registered first for OCIStmtPrepare. The environment + variable can be set to upto 5 package names, delimited + by semi-colons. + + PUBLIC FUNCTION(S) + None + + PRIVATE FUNCTION(S) + As described below + + RETURNS + + NOTES + Multiple packages can be specified by setting the + environment variable ORA_OCI_UCBPKG as follows: + + setenv ORA_OCI_UCBPKG "cdemoup1;cdemoup2" + + The above setting specifies two packages are to be used. + A maximum of 5 packages can be specified separated by + semi-colons. + + MODIFIED (MM/DD/YY) + aliu 02/15/07 - fix lrg 2863937: initialize variables + mpjoshi 11/04/99 - do not use wrapper functions + svedala 10/20/99 - Creation + +*/ + +#include +#include +#include +#include +#include + +static text *username = (text *) "CDEMOUPK"; +static text *password = (text *) "CDEMOUPK"; + +static text *crstmt = (text *) "CREATE TABLE TAB1 (COL1 VARCHAR2(40))"; + +static OCIEnv *envhp; +static OCIServer *srvhp; +static OCIError *errhp; +static OCISvcCtx *svchp; +static OCIStmt *stmthp; +static OCISession *authp = (OCISession *) 0; + +struct stat_ctx_struct +{ + OCIUserCallback *entry_funcptr; + dvoid *entry_ctxptr; + OCIUserCallback *exit_funcptr; + dvoid *exit_ctxptr; +}; + +typedef struct stat_ctx_struct stat_ctx_struct; + +static void checkerr(/*_ OCIError *errhp, sword status _*/); +static void cleanup(/*_ void _*/); + +sword stmtprep_entry_statcbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist); + +sword stmtprep_exit_statcbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist); + + +int main(/*_ int argc, char *argv[] _*/); + +static sword status; + +int main(argc, argv) +int argc; +char *argv[]; +{ + + static ub4 pos; + ub4 attrval; + ub4 attrsiz; + text errbuf[512]; + sb4 errcode = 0; + text sversion[512]; + + stat_ctx_struct *static_context = (stat_ctx_struct *) 0; + + (void) printf("Initializing and Connecting\n\n"); + + if (init_handles()) + { + (void) printf("FAILED: init_handles()\n"); + return OCI_ERROR; + } + + if (log_on()) + { + (void) printf("FAILED: log_on()\n"); + return OCI_ERROR; + } + + if (status = OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp, + OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + + /* Register the static callback routine "stmtprep_entry_statcbk_fn" */ + /* for OCIStmtPrepare, entry-time. This will overwrite the */ + /* of entry dynamic callback if one was registered */ + + if (OCIUserCallbackRegister(envhp, OCI_HTYPE_ENV, errhp, + stmtprep_entry_statcbk_fn, static_context, + OCI_FNCODE_STMTPREPARE, OCI_UCBTYPE_ENTRY, + (OCIUcb *)0)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + + /* Register the exit static callback function for OCIStmtPrepare */ + + if (OCIUserCallbackRegister(envhp, OCI_HTYPE_ENV, errhp, + stmtprep_exit_statcbk_fn, static_context, + OCI_FNCODE_STMTPREPARE, OCI_UCBTYPE_EXIT, + (OCIUcb *)0)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + if (status = OCIStmtPrepare(stmthp, errhp, crstmt, + (ub4) strlen((char *) crstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + if ((status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL, OCI_DEFAULT)) + && (status != OCI_NO_DATA)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + if (status = OCITransCommit(svchp, errhp, 0)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + + if (status = OCISessionEnd(svchp, errhp, authp, (ub4) 0)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + (void) printf("\nDetach and deallocate handles\n"); + + if (status = OCIServerDetach( srvhp, errhp, OCI_DEFAULT)) + { + checkerr(errhp, status); + cleanup(); + return OCI_ERROR; + } + + cleanup(); +} + + +void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + (void) printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + (void) printf("Error - OCI_NODATA\n"); + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + (void) printf("Error - %.*s\n", 512, errbuf); + break; + case OCI_INVALID_HANDLE: + (void) printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + (void) printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + (void) printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} + + +/* ----------------------------------------------------------------- */ +/* initialize environment, allocate handles, etc. */ +/* ----------------------------------------------------------------- */ + +sb4 init_handles() +{ + if (OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0 )) + { + (void) printf("FAILED: OCIInitialize()\n"); + return OCI_ERROR; + } + + /* initialize environment handle */ + if (OCIEnvInit((OCIEnv **) &envhp, (ub4) OCI_DEFAULT, + (size_t) 0, (dvoid **) 0 )) + { + (void) printf("FAILED: OCIEnvInit()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &stmthp, + (ub4) OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0)) + { + (void) printf("FAILED: OCIHandleAlloc()\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + + +/* ----------------------------------------------------------------- */ +/* attach to the server and log on */ +/* ----------------------------------------------------------------- */ + +sb4 log_on() +{ + text *uid = (text *)"CDEMOUPK"; + text *pwd = (text *)"CDEMOUPK"; + text *cstring = (text *) ""; + + /* attach to the server */ + if (OCIServerAttach(srvhp, errhp, (text *) cstring, + (sb4) strlen((char *)cstring), (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCIServerAttach()\n"); + return OCI_ERROR; + } + + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) uid, (ub4) strlen((char *)uid), + (ub4) OCI_ATTR_USERNAME, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) pwd, (ub4) strlen((char *)pwd), + (ub4) OCI_ATTR_PASSWORD, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + /* set the server attribute in the service context */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, (ub4) OCI_ATTR_SERVER, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + /* log on */ + if (OCISessionBegin(svchp, errhp, authp, (ub4) OCI_CRED_RDBMS, + (ub4) OCI_DEFAULT)) + { + (void) printf("FAILED: OCISessionBegin()\n"); + return OCI_ERROR; + } + + /* set the session attribute in the service context */ + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, (dvoid *) authp, + (ub4) 0, (ub4) OCI_ATTR_SESSION, errhp)) + { + (void) printf("FAILED: OCIAttrSet()\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; + +} + + +/* ----------------------------------------------------------------- */ +/* Exit program with an exit code. */ +/* ----------------------------------------------------------------- */ +void cleanup() +{ + sword status; + + if (stmthp) + { + if (status = OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT)) + { + (void) printf("Status = %d\n", status); + checkerr(errhp, status); + } + } + + if (srvhp) + { + if (status = OCIHandleFree((dvoid *) srvhp, OCI_HTYPE_SERVER)) + { + (void) printf("Status = %d\n", status); + checkerr(errhp, status); + } + } + + if (errhp) + { + (void) OCIHandleFree((dvoid *) errhp, OCI_HTYPE_ERROR); + } + return; +} + + + +/* ----------------------------------------------------------------- */ +/* Entry callback function for OCIStmtPrepare. This function is */ +/* statically registered (i.e. from within this file). Since, it */ +/* uses (via va_arg) the parametes passed to it, it calls a wrapper */ +/* function that recreates the arglist to be passed to the dynamic */ +/* callback. */ +/* ----------------------------------------------------------------- */ +sword stmtprep_entry_statcbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist) +{ + stat_ctx_struct *loc_ctx; + OCIStmt *stmthp; + OCIError *errhp; + text *sqlstmt; + ub4 stmtlen; + ub4 language; + ub4 mode; + sword retCode = OCI_CONTINUE; + + + /* Retrieve all arguments of OCIStmtPrepare and save */ + /* them so they can be passed on to dynamic-registered */ + /* callback if one was registered */ + + stmthp = va_arg(arglist, OCIStmt *); + errhp = va_arg(arglist, OCIError *); + sqlstmt = va_arg(arglist, text *); + stmtlen = va_arg(arglist, ub4); + language = va_arg(arglist, ub4); + mode = va_arg(arglist, ub4); + + printf("In static entry callback routine for OCIStmtPrepare:\n"); + printf("sql_stmt = [%s]\n\n", sqlstmt); + + + return retCode; +} + + +/* ----------------------------------------------------------------- */ +/* Exit callback function (static) for OCIStmtPrepare. Since it */ +/* does not utilize any parameters in the arglist, it can pass */ +/* the arglist directly to the dynamic callback. */ +/* ----------------------------------------------------------------- */ +sword stmtprep_exit_statcbk_fn (dvoid *ctxp, dvoid *hndlp, ub4 type, + ub4 fcode, ub4 when, sword returnCode, + sb4 *errnop, va_list arglist) +{ + stat_ctx_struct *loc_ctx; + sword retCode = OCI_CONTINUE; + + + printf("\nIn static exit callback routine for OCIStmtPrepare\n"); + + return retCode; +} + + + +/* end of file cdemoupk.c */ + diff --git a/cdemoupk.sql b/cdemoupk.sql new file mode 100644 index 0000000..c3c048d --- /dev/null +++ b/cdemoupk.sql @@ -0,0 +1,34 @@ +Rem +Rem $Header: cdemoupk.sql 10-apr-2007.18:07:13 azhao Exp $ +Rem +Rem cdemoupk.sql +Rem +Rem Copyright (c) 2004, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem cdemoupk.sql - create user for cdemooupk +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem azhao 04/10/07 - case sensitive password +Rem jchai 03/23/04 - jchai_add_cdemoucb_cdempupk_shiptest +Rem jchai 03/18/04 - Created +Rem + +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +connect system/manager; +drop user cdemoupk cascade; +grant connect, resource to cdemoupk identified by CDEMOUPK; + + diff --git a/cdemoxml.c b/cdemoxml.c new file mode 100644 index 0000000..e02fdbd --- /dev/null +++ b/cdemoxml.c @@ -0,0 +1,649 @@ +/* Copyright (c) 2001, 2006, Oracle. All rights reserved. +*/ + +/* + + NAME + cdemoxml.c - XMLType demo program in OCI + + DESCRIPTION - demo of selection and insertion of XMLType column + using OCI interface. + + Note: Before running this program, ensure that the database is + started up with compatible=9.0.0.0.0 and an table CDEMOXML_FOO does + not exist in the SCOTT/TIGER sample account. + + + + MODIFIED (MM/DD/YY) + azhao 10/10/06 - case-senstive password change + aliu 07/05/01 - update SQLCS_IMPLICIT to OCI_DEFAULT for OCILobCreateTemporary. + aliu 06/27/01 - Change table name not to be conflict with other tests. + aliu 04/24/01 - Merged aliu_dt_demo_oci + aliu 04/24/01 - Modify variable names and main prototype. + aliu 04/24/01 - Update lint warnings. + aliu 04/23/01 - Add more comments. + aliu 04/10/00 - Creation + +*/ + +#ifndef CDEMOXML +#define CDEMOXML + +/*------------------------------------------------------------------------ + * Include Files + */ + +#ifndef STDIO +#include +#endif + +#ifndef STDLIB +#include +#endif + +#ifndef STRING +#include +#endif + +#ifndef OCI_ORACLE +#include +#endif + +/*----------------- End of including files -----------------*/ + +/*--------------------- Public Constants and Variables ----------------------*/ + +/* constants */ +#define MAXBUFLEN 2000 + +/* database login information */ +static text *user=(text *)"SCOTT"; +static text *password=(text *)"tiger"; + +/* OCI Handles and Variables */ +static OCIEnv *envhp; +static OCIServer *srvhp; +static OCISvcCtx *svchp; +static OCIError *errhp; +static OCISession *authp; +static OCIStmt *stmthp; +static OCIDefine *defnp = (OCIDefine *) 0; +static OCIBind *bndhp1 = (OCIBind *) 0, *bndhp2 = (OCIBind *) 0; + +/* Misellaneous */ +static sword status; +static boolean tab_exists = FALSE; + +/*----------------- End of Constants and Variables -----------------*/ + +/*--------------------- Functions Declaration --------------------*/ + +int main(/*_ void _*/); +static void checkerr(/*_ OCIError *errhp, sword status _*/); +static void cleanup(/*_ void _*/); +static sb4 connect_server(/*_ void _*/); +static void disconnect_server(/*_ void _*/); +static void drop_table(/*_ void _*/); +static sb4 init_env_handle(/*_ void _*/); +static sb4 init_table(/*_ void _*/); +static sb4 insert_xml(/*_ ub4 rownum _*/); +static sb4 select_xml(/*_ ub4 rownum _*/); + +/*--------------------- End of Functions Declaration --------------------*/ + +#endif + + +/*---------------------------Main function -----------------------------*/ +int main() +{ + ub4 rownum; + + /* Initialize the environment and allocate handles */ + if (init_env_handle()) + { + printf("FAILED: init_env_handle()!\n"); + return OCI_ERROR; + } + + /* Log on to the server and begin a session */ + if (connect_server()) + { + printf("FAILED: connect_server()!\n"); + cleanup(); + return OCI_ERROR; + } + + /* Initialize the demo table */ + if (init_table()) + { + printf("FAILED: init_table()\n"); + disconnect_server(); + return OCI_ERROR; + } + + rownum = 1; + /* Insertion */ + if (insert_xml(rownum)) + { + printf("FAILED: insert_xml()!\n"); + disconnect_server(); + return OCI_ERROR; + } + + /* Selection */ + if (select_xml(rownum)) + { + printf("FAILED: select_xml()!\n"); + disconnect_server(); + return OCI_ERROR; + } + + /* Detach from a server and clean up the environment */ + disconnect_server(); + + return OCI_SUCCESS; +} + + +/*---------------------------Subfunctions -----------------------------*/ + +/*--------------------------------------------------------*/ +/* Return corresponding messages in differrent cases */ +/*--------------------------------------------------------*/ +void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text msgbuf[512]; + sb4 errcode = 0; + + memset((void *) msgbuf, (int)'\0', (size_t)512); + + switch (status) + { + case OCI_SUCCESS: break; + case OCI_SUCCESS_WITH_INFO: + printf("status = OCI_SUCCESS_WITH_INFO\n"); + OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + printf("ERROR CODE = %d\n", errcode); + printf("%.*s\n", 512, msgbuf); + if (errcode == 436 || errcode == 437 || errcode == 438 || errcode == 439) + exit(1); + break; + case OCI_NEED_DATA: + printf("status = OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + printf("status = OCI_NO_DATA\n"); + break; + case OCI_ERROR: + printf("status = OCI_ERROR\n"); + OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); + printf("ERROR CODE = %d\n", errcode); + printf("%.*s\n", 512, msgbuf); + if (errcode == 436 || errcode == 437 || errcode == 438 || errcode == 439) + exit(1); + break; + case OCI_INVALID_HANDLE: + printf("status = OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + printf("status = OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + printf("status = OCI_CONTINUE\n"); + break; + default: + break; + } + + return; +} + + +/*--------------------------------------------------------*/ +/* Free the envhp whenever there is an error */ +/*--------------------------------------------------------*/ +void cleanup() +{ + if (envhp) { + OCIHandleFree((dvoid *)envhp, OCI_HTYPE_ENV); + } + + return; +} + + +/*--------------------------------------------------------*/ +/* attach to server, set attributes, and begin session */ +/*--------------------------------------------------------*/ +sb4 connect_server() +{ + /* attach to server */ + if (status = OCIServerAttach((OCIServer *) srvhp, (OCIError *) errhp, + (text *) "", (sb4) strlen(""), (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIServerAttach() on srvhp\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* set server attribute to service context */ + if (status = OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, (ub4) OCI_ATTR_SERVER, + (OCIError *) errhp)) + { + printf("FAILED: OCIAttrSet() on svchp\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* set user attribute to session */ + if (status = OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) user, (ub4) strlen((char *)user), + (ub4) OCI_ATTR_USERNAME, (OCIError *) errhp)) + { + printf("FAILED: OCIAttrSet() on authp for user\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* set password attribute to session */ + if (status = OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) password, (ub4) strlen((char *)password), + (ub4) OCI_ATTR_PASSWORD, (OCIError *) errhp)) + { + printf("FAILED: OCIAttrSet() on authp for password\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* Begin a session */ + if (status = OCISessionBegin((OCISvcCtx *) svchp, (OCIError *) errhp, + (OCISession *) authp, (ub4) OCI_CRED_RDBMS, + (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCISessionBegin()\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* set session attribute to service context */ + if (status = OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) authp, (ub4) 0, (ub4) OCI_ATTR_SESSION, + (OCIError *) errhp)) + { + printf("FAILED: OCIAttrSet() on svchp\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* End the session, detach server and free handles. */ +/*--------------------------------------------------------*/ +void disconnect_server() +{ + printf("\n\nLogged off and detached from server.\n"); + + /* Drop the demo table if any */ + if (tab_exists) + drop_table(); + + /* End a session */ + if (status = OCISessionEnd((OCISvcCtx *)svchp, (OCIError *)errhp, + (OCISession *)authp, (ub4) OCI_DEFAULT)) { + checkerr(errhp, status); + cleanup(); + return; + } + + /* Detach from the server */ + if (status = OCIServerDetach((OCIServer *)srvhp, (OCIError *)errhp, + (ub4)OCI_DEFAULT)) { + checkerr(errhp, status); + cleanup(); + return; + } + + /* Free the handles */ + if (stmthp) { + OCIHandleFree((dvoid *)stmthp, (ub4) OCI_HTYPE_STMT); + } + if (authp) { + OCIHandleFree((dvoid *)authp, (ub4) OCI_HTYPE_SESSION); + } + if (svchp) { + OCIHandleFree((dvoid *)svchp, (ub4) OCI_HTYPE_SVCCTX); + } + if (srvhp) { + OCIHandleFree((dvoid *)srvhp, (ub4) OCI_HTYPE_SERVER); + } + if (errhp) { + OCIHandleFree((dvoid *)errhp, (ub4) OCI_HTYPE_ERROR); + } + if (envhp) { + OCIHandleFree((dvoid *)envhp, (ub4) OCI_HTYPE_ENV); + } + + return; +} + + +/*--------------------------------------------------------*/ +/* Drop table CDEMOXML_FOO before logging off from the server */ +/*--------------------------------------------------------*/ +void drop_table() +{ + text *dropstmt = (text *) "DROP TABLE CDEMOXML_FOO"; + + /* prepare drop statement */ + if (OCIStmtPrepare(stmthp, errhp, dropstmt, (ub4) strlen((char *) dropstmt), (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIStmtPrepare() dropstmt\n"); + return; + } + /* execute drop statement */ + if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) 0, (OCISnapshot *) 0, + (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIStmtExecute() dropstmt\n"); + return; + } + + return; +} + + +/*--------------------------------------------------------*/ +/* Initialize the environment and allocate handles */ +/*--------------------------------------------------------*/ +sb4 init_env_handle() +{ + /* Environment initialization and creation */ + if (OCIEnvCreate((OCIEnv **) &envhp, (ub4) OCI_OBJECT, (dvoid *) 0, + (dvoid * (*)(dvoid *,size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t)) 0, + (void (*)(dvoid *, dvoid *)) 0, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIEnvCreate()\n"); + return OCI_ERROR; + } + + /* allocate error handle */ + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on errhp\n"); + return OCI_ERROR; + } + + /* allocate server handle */ + if (status = OCIHandleAlloc((dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on srvhp\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* allocate service context handle */ + if (status = OCIHandleAlloc((dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on svchp\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* allocate session handle */ + if (status = OCIHandleAlloc((dvoid *) envhp, (dvoid **) &authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on authp\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* Allocate statement handle */ + if (status = OCIHandleAlloc((dvoid *) envhp, (dvoid **) &stmthp, + (ub4) OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on stmthp\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* create a table CDEMOXML_FOO with one XMLType column */ +/*--------------------------------------------------------*/ +sb4 init_table() +{ + int colc; + text *crtstmt = (text *) "CREATE TABLE CDEMOXML_FOO (xml_col sys.xmltype, int_col INTEGER)"; + + /* prepare create statement */ + if (status = OCIStmtPrepare(stmthp, errhp, crtstmt, (ub4) strlen((char *) crtstmt), (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIStmtPrepare() crtstmt\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + /* execute create statement */ + if (status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot *) 0, (OCISnapshot *) 0, + (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIStmtExecute() crtstmt\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + /* commit the Xn */ + OCITransCommit(svchp, errhp, (ub4)0); + + /* set flag to be used by disconnect_server() to drop the table */ + tab_exists = TRUE; + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* insert xml into the table */ +/*--------------------------------------------------------*/ +sb4 insert_xml(rownum) +ub4 rownum; +{ + ub4 colc = rownum; + ub4 amtp, nbytes; + ub1 bufp[MAXBUFLEN] = "\nRachel"; + text *insstmt = (text *)"INSERT INTO CDEMOXML_FOO (xml_col, int_col) VALUES (sys.xmltype.createxml(:xmlval), :intval)"; + OCILobLocator *clob; + + printf("\n=> Inserting to row %d......\n", rownum); + + /* Allocate the lob descriptor */ + if (OCIDescriptorAlloc((dvoid *) envhp, (dvoid **) &clob, + (ub4)OCI_DTYPE_LOB, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIDescriptorAlloc()\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* initialize a lob */ + if (status = OCILobCreateTemporary(svchp,errhp,clob, + (ub2)OCI_DEFAULT,(ub1)OCI_DEFAULT,OCI_TEMP_CLOB,FALSE, + OCI_DURATION_SESSION)) + { + printf("ERROR: OCILobCreateTemporary()\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + nbytes = MAXBUFLEN-1; + amtp = (ub4)strlen((char *)bufp); + if ( status = OCILobWrite(svchp, errhp, clob, &amtp, 1, + (dvoid *) bufp, (ub4) nbytes, OCI_ONE_PIECE, (dvoid *)0, + (sb4 (*)(dvoid *, dvoid *, ub4 *, ub1 *)) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT)) + { + printf("ERROR: OCILobWrite()\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* prepare insert statement */ + if (status = OCIStmtPrepare(stmthp, errhp, (text *)insstmt, + (ub4) strlen((char *)insstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIStmtPrepare() insstmt\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* associate variables with bind placeholders in the SQL statement */ + if ((status = OCIBindByName(stmthp, &bndhp1, errhp, + (CONST text *)":xmlval",(sb4) strlen((char *) ":xmlval"), + (dvoid *)&clob, (sb4) -1, SQLT_CLOB, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + || (status = OCIBindByName(stmthp, &bndhp2, errhp, + (CONST text *)":intval",(sb4) strlen((char *) ":intval"), + (dvoid *)&colc, (sb4) sizeof(colc), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT))) + { + printf("FAILED: OCIBindByName()\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* execute the statement */ + if (status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIStmtExecute() insstmt\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + printf("\n=> Insertion done\n"); + + /* Free the lob locator */ + if (clob) { + OCIDescriptorFree((dvoid *) clob, (ub4) OCI_DTYPE_LOB); + } + + return OCI_SUCCESS; +} + + +/*--------------------------------------------------------*/ +/* select xml column from the table */ +/*--------------------------------------------------------*/ +sb4 select_xml(rownum) +ub4 rownum; +{ + ub4 colc = rownum; + ub4 amtp, nbytes; + ub1 bufp[MAXBUFLEN]; + text *selstmt =(text *)"SELECT t.xml_col.getClobVal() FROM CDEMOXML_FOO t WHERE t.int_col = :1"; + OCILobLocator *clob; + + printf("\n=> Selecting row %d......\n", rownum); + + /* Allocate the lob descriptor */ + if (OCIDescriptorAlloc((dvoid *) envhp, (dvoid **) &clob, + (ub4)OCI_DTYPE_LOB, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIDescriptorAlloc()\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* prepare select statement */ + if (status = OCIStmtPrepare(stmthp, errhp, (text *)selstmt, + (ub4) strlen((char *)selstmt), + (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIStmtPrepare() selstmt\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* associate variable colc with bind placeholder #1 in the SQL statement */ + if (status = OCIBindByPos(stmthp, &bndhp1, errhp, (ub4) 1, + (dvoid *) &colc, (sb4) sizeof(colc), SQLT_INT, + (dvoid *) 0, (ub2 *)0, (ub2 *)0, + (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIBindByPos()\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* associate lob var with its define handle */ + if (status = OCIDefineByPos(stmthp, &defnp, errhp, (ub4) 1, + (dvoid *) &clob, (sb4) -1, (ub2) SQLT_CLOB, + (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIDefineByPos() CLOB\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* execute the select statement */ + if (status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, + (CONST OCISnapshot*) 0, (OCISnapshot*) 0, + (ub4) OCI_DEFAULT)) + { + printf("FAILED: OCIStmtExecute() selstmt\n"); + checkerr(errhp, status); + return OCI_ERROR; + } + + /* read the fetched value into a buffer */ + amtp = nbytes = MAXBUFLEN-1; + if (status = OCILobRead(svchp, errhp, clob, &amtp, + (ub4) 1, (dvoid *) bufp, (ub4) nbytes, (dvoid *)0, + (sb4 (*)(dvoid *, CONST dvoid *, ub4, ub1)) 0, + (ub2) 0, (ub1) SQLCS_IMPLICIT)) + { + printf("FAILED: OCILobRead() \n"); + checkerr(errhp, status); + return OCI_ERROR; + } + bufp[amtp] = '\0'; + + /* Print out the buffer */ + if (amtp > 0) { + printf("\n=> Query result of %s on row %d: \n%s\n", selstmt, rownum, bufp); + } + else { + printf("\nEmpty value\n"); + } + + /* Free the lob locator */ + if (clob) { + OCIDescriptorFree((dvoid *) clob, (ub4) OCI_DTYPE_LOB); + } + + return OCI_SUCCESS; +} + + +/* end of file cdemoxml.c */ diff --git a/clobdemo.dat b/clobdemo.dat new file mode 100644 index 0000000..a6d6923 --- /dev/null +++ b/clobdemo.dat @@ -0,0 +1,6 @@ +This is .dat file for clob demo. This .dat file content will be +printed using lob stream interface . If these contents are +printed properly, this demo program is working well. +Otherwise there is a problem in printing. Hope this demo will +work properly. + diff --git a/dattime1.sql b/dattime1.sql new file mode 100644 index 0000000..262f649 --- /dev/null +++ b/dattime1.sql @@ -0,0 +1,79 @@ +Rem +Rem $Header: rdbms/demo/dattime1.sql /main/3 2009/07/04 16:43:57 wezhu Exp $ +Rem +Rem dattime1.sql +Rem +Rem Copyright (c) 2007, 2009, Oracle and/or its affiliates. +Rem All rights reserved. +Rem +Rem NAME +Rem dattime1.sql - create table with 5 different data type +Rem TIMESTAMP +Rem TIMESTAMP WITH TIME ZONE +Rem TIMESTAMP WITH LOCAL TIME ZONE +Rem INTERVAL YEAR TO MONTH +Rem INTERVAL DAY TO SECOND +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem wezhu 07/01/09 - add default session time zone +Rem chli 04/09/07 - fix password issue +Rem jxfan 04/10/01 - Merged jxfan_demo +Rem jxfan 04/10/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO OFF + +COL c1 FORMAT A30 +COL c2 FORMAT A48 +COL c3 FORMAT A30 +COL c4 FORMAT A48 +COL c5 FORMAT A30 + +COL c1 HEADING TIMESTAMP +COL c2 HEADING "TIMESTAMP WITH TIME ZONE" +COL c3 HEADING "TIMESTAMP WITH LOCAL TIME ZONE" +COL c4 HEADING "INTERVAL YEAR TO MONTH" +COL c5 HEADING "INTERVAL DAY TO SECOND" + +CONNECT oe/oe + +ALTER SESSION SET time_zone = 'US/Pacific'; + +CREATE TABLE dattime ( + c1 TIMESTAMP, + c2 TIMESTAMP WITH TIME ZONE, + c3 TIMESTAMP WITH LOCAL TIME ZONE, + c4 INTERVAL YEAR TO MONTH, + c5 INTERVAL DAY TO SECOND); + +INSERT INTO dattime +VALUES ( TIMESTAMP'1980-1-12 15:13:23.33', + TIMESTAMP'2000-10-28 11:26:38 AMERICA/LOS_ANGELES', + TIMESTAMP'1985-3-1 1:11:11.11', + INTERVAl '1-2' YEAR TO MONTH, + INTERVAL '90 00:00:00' DAY TO SECOND); + +INSERT INTO dattime +VALUES (TO_TIMESTAMP('08-11-83 3:43:55.49','DD-MM-RR HH24:MI:SSXFF'), + TO_TIMESTAMP_TZ('2-4-58 14:2:56.18+8:53','DD-MM-RR HH24:MI:SSXFFTZH:TZM'), + TO_TIMESTAMP('12-8-38 1:2:56.1','DD-MM-RR HH24:MI:SSXFF'), + TO_YMINTERVAL('02-03'), + TO_DSINTERVAL('65 10:00:00')); + + +SELECT * FROM dattime; + +DROP TABLE dattime; + diff --git a/dattime2.sql b/dattime2.sql new file mode 100644 index 0000000..b805d59 --- /dev/null +++ b/dattime2.sql @@ -0,0 +1,71 @@ +Rem +Rem $Header: dattime2.sql 10-apr-2001.15:02:35 jxfan Exp $ +Rem +Rem dattime2.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem dattime2.sql - Daylight Saving Time (DST) +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem jxfan 04/10/01 - Merged jxfan_demo +Rem jxfan 04/10/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO OFF + +CONNECT OE/OE + +PROMPT Calculate Daylight Saving Time (DST) when the session TIME_ZONE is a region +PROMPT +SET ECHO ON +UPDATE orders +SET order_date = TIMESTAMP '2000-4-1 23:24:54 AMERICA/LOS_ANGELES' +WHERE order_id = 2457; +ALTER SESSION SET TIME_ZONE='AMERICA/LOS_ANGELES'; +SELECT order_date + INTERVAL '8' HOUR FROM orders +WHERE order_id = 2457; + +SET ECHO OFF +PROMPT +PAUSE Press enter to continue ... +PROMPT +PROMPT The time period from 02:00:00 AM to 02:59:59 AM does not exist +PROMPT during APRIL boundary +PROMPT + +SET ECHO ON +UPDATE orders +SET order_date = TIMESTAMP'2000-04-02 02:30:30 AMERICA/LOS_ANGELES' +WHERE order_id = 2457; + +SET ECHO OFF +PROMPT +PROMPT +PAUSE Press enter to continue ... +PROMPT +PROMPT The time period from 01:00:01 AM to 02:00:00 AM is repeated during +PROMPT OCTOBER boundary +PROMPT + +SET ECHO ON +ALTER SESSION SET ERROR_ON_OVERLAP_TIME = TRUE; + +UPDATE orders +SET order_date = TIMESTAMP '2000-10-29 01:00:01 AMERICA/LOS_ANGELES' +WHERE order_id = 2457; + + diff --git a/dattime3.sql b/dattime3.sql new file mode 100644 index 0000000..0b735e5 --- /dev/null +++ b/dattime3.sql @@ -0,0 +1,79 @@ +Rem +Rem $Header: dattime3.sql 09-apr-2007.15:52:50 chli Exp $ +Rem +Rem dattime3.sql +Rem +Rem Copyright (c) 2001, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem dattime3.sql - Using Built-in SQL function +Rem TO_YMINTERVAL(); +Rem TO_DSINTERVAL(); +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem chli 04/09/07 - lowercase password +Rem jxfan 04/10/01 - Merged jxfan_demo +Rem jxfan 04/10/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO OFF + +COL employee_id FORMAT 9999 +COL first_name FORMAT A20 +COL last_name FORMAT A20 +COL employee_id HEADING ID +COL first_name HEADING "FIRST NAME" +COL last_name HEADING "LAST NAME" +COL hire_date HEADING "HIRE DATE" +CONNECT HR/hr + +PROMPT +PROMPT +PROMPT Add 1 year 2 months to hire date by using Built-in SQL function TO_YMINTERVAL +PROMPT +PROMPT + +SELECT employee_id, first_name, last_name, hire_date, + hire_date + TO_YMINTERVAL('01-02') "NEW DATE" +FROM employees +WHERE department_id = 30; + +PROMPT +PROMPT +rem PAUSE Press enter to continue ... +PROMPT +PROMPT Subtract 10 days from hire date by using Built-in SQL function TO_DSINTERVAL +PROMPT +PROMPT + +SELECT employee_id, first_name, last_name, hire_date, + hire_date - TO_DSINTERVAL('10 00:00:00') "NEW DATE" +FROM employees +WHERE department_id = 30; + +PROMPT +PROMPT +rem PAUSE Press enter to continue ... +PROMPT +PROMPT Add 24 hours to hire date using INTERVAL +PROMPT +PROMPT +SELECT employee_id, first_name, last_name, hire_date, + hire_date + INTERVAL '24' HOUR "NEW DATE" +FROM employees +WHERE department_id = 30; +PROMPT +PROMPT + diff --git a/dattime4.sql b/dattime4.sql new file mode 100644 index 0000000..bd892a6 --- /dev/null +++ b/dattime4.sql @@ -0,0 +1,332 @@ +Rem +Rem $Header: dattime4.sql 30-mar-2006.08:56:23 lburgess Exp $ +Rem +Rem dattime4.sql +Rem +Rem Copyright (c) 2001, 2006, Oracle. All rights reserved. +Rem +Rem NAME +Rem dattime4.sql - A Comprehensive DateTime Demo +Rem +Rem DESCRIPTION +Rem This is a sample program to demonstrate +Rem -the usage of datetime types available in 9i database. +Rem -different possible combination of datetime assignments +Rem -the usage of datetime built-ins +Rem -the usage of datetime arithmetic +Rem -the usage of ERROR_ON_OVERLAP_TIME Session parameter +Rem +Rem NOTES +Rem TS stands for TIMESTAMP +Rem TSTZ stands for TIMESTAMP WITH TIME ZONE +Rem TSLTZ stands for TIMESTAMP WITH LOCAL TIME ZONE +Rem +Rem MODIFIED (MM/DD/YY) +Rem lburgess 03/30/06 - lowercase passwords +Rem nmeng 10/23/02 - +Rem rchennoj 10/22/02 - Query from v$timezone_names +Rem rchennoj 05/07/01 - +Rem rchennoj 04/30/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 132 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +CONNECT SYSTEM/manager; + +DROP USER dtdemo CASCADE; +GRANT CONNECT, RESOURCE TO dtdemo IDENTIFIED BY dtdemo; + +CONNECT dtdemo/dtdemo; + + +ALTER SESSION SET TIME_ZONE='-08:00'; +SELECT dbtimezone, sessiontimezone from dual; + + +------------------------------------------------------ +--1. TIMESTAMP datatype +------------------------------------------------------ + +CREATE TABLE tab_ts (c_id number, c_ts TIMESTAMP); + +--Use fractional seconds +INSERT INTO tab_ts +VALUES (1, TIMESTAMP'1980-1-12 15:13:23.33'); + +--Use TimeZone info, should truncate the zone info as +--Timestamp type doesnot store zone info. +INSERT INTO tab_ts +VALUES (2, TIMESTAMP'1980-1-12 15:13:23 -07:00'); + + +ALTER SESSION SET NLS_TIMESTAMP_FORMAT='YYYY-MM-DD HH24:MI:SSXFF'; +SELECT c_id, c_ts from tab_ts order by c_id; + +ALTER SESSION SET NLS_TIMESTAMP_FORMAT='DD-MON-YYYY HH:MI:SSXFF AM'; +SELECT c_id, c_ts from tab_ts order by c_id; + + +------------------------------------------------------ +--2. TIMESTAMP WITH TIME ZONE datatype +------------------------------------------------------ + +CREATE TABLE tab_tstz (c_id number, c_tstz TIMESTAMP WITH TIME ZONE); + +--Use No TimeZone info, should take Sessiontimezone +INSERT INTO tab_tstz +VALUES ( 1, TIMESTAMP'2000-10-28 11:26:38'); + +--Use TimeZone Offset +INSERT INTO tab_tstz +VALUES ( 2, TIMESTAMP'2000-10-28 11:26:38 -07:00'); + +--Use TimeZone Region Name +INSERT INTO tab_tstz +VALUES ( 3, TIMESTAMP'2000-10-28 11:26:38 AMERICA/LOS_ANGELES'); + +INSERT INTO tab_tstz +VALUES ( 4, TIMESTAMP'2000-01-28 11:26:38 AMERICA/LOS_ANGELES PST'); + +INSERT INTO tab_tstz +VALUES ( 5, TIMESTAMP'2000-01-28 11:26:38 GMT'); + + +--show zone info in OFFSET format +ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT='DD-MON-YYYY HH:MI:SSXFF AM TZH:TZM'; +SELECT c_id, c_tstz from tab_tstz order by c_id; + +--show zone info in Regionname if one inserted +ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT='DD-MON-YYYY HH:MI:SSXFF AM TZR'; +SELECT c_id, c_tstz from tab_tstz order by c_id; + +--show zone info in Regionname and Zone Abbreviation if one inserted +ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT='DD-MON-YYYY HH:MI:SSXFF AM TZR TZD'; +SELECT c_id, c_tstz from tab_tstz order by c_id; + + +------------------------------------------------------ +--3. TIMESTAMP WITH LOCAL TIME ZONE datatype +------------------------------------------------------ + +CREATE TABLE tab_tsltz (c_id number, c_tsltz TIMESTAMP WITH LOCAL TIME ZONE); + +--Use fractional seconds +INSERT INTO tab_tsltz +VALUES (1, TIMESTAMP'1980-1-12 15:13:23.33'); + +--Use TimeZone info, should convert the value from specified time zone +--to Sessiontimezone +INSERT INTO tab_tsltz +VALUES (2, TIMESTAMP'1980-1-12 15:13:23 -07:00'); + + +ALTER SESSION SET NLS_TIMESTAMP_FORMAT='YYYY-MM-DD HH24:MI:SSXFF'; +SELECT c_id, c_tsltz from tab_tsltz order by c_id; + +ALTER SESSION SET NLS_TIMESTAMP_FORMAT='DD-MON-YYYY HH:MI:SSXFF AM'; +SELECT c_id, c_tsltz from tab_tsltz order by c_id; + + +--Change Sessiontimezone. TSLTZ value should be adjusted to the +--new sessiontimezone +ALTER SESSION SET TIME_ZONE='GMT'; +SELECT c_id, c_tsltz from tab_tsltz order by c_id; + +ALTER SESSION SET TIME_ZONE='Asia/Calcutta'; +SELECT c_id, c_tsltz from tab_tsltz order by c_id; + + +------------------------------------------------------ +--4. INTERVAL YEAR TO MONTH datatype +------------------------------------------------------ + +CREATE TABLE tab_iym (c_id number, c_iym INTERVAL YEAR(3) TO MONTH); + +INSERT INTO tab_iym +VALUES(1, INTERVAL '01-01' YEAR TO MONTH); + +INSERT INTO tab_iym +VALUES(2, INTERVAL '-01-01' YEAR TO MONTH); + +INSERT INTO tab_iym +VALUES(3, INTERVAL '100-10' YEAR(3) TO MONTH); + + +SELECT c_id, c_iym from tab_iym order by c_id; + + +------------------------------------------------------ +--5. INTERVAL DAY TO SECOND datatype +------------------------------------------------------ + +CREATE TABLE tab_ids (c_id number, c_ids INTERVAL DAY(3) TO SECOND(9)); + +INSERT INTO tab_ids +VALUES(1, INTERVAL '01 01:01:01.000001' DAY TO SECOND); + +INSERT INTO tab_ids +VALUES(2, INTERVAL '100 10:10:10' DAY(3) TO SECOND); + +INSERT INTO tab_ids +VALUES(3, INTERVAL '100 10:10:10.123456789' DAY(3) TO SECOND(9)); + + +SELECT c_id, c_ids from tab_ids order by c_id; + + +------------------------------------------------------ +--6. Use Datetime Builtins +------------------------------------------------------ + +--------FROM_TZ +SELECT FROM_TZ(TIMESTAMP'1997-01-01 01:00:00', 'US/Pacific') FROM DUAL; +SELECT FROM_TZ(TIMESTAMP'1999-04-04 01:59:59', 'US/Pacific') FROM DUAL; +SELECT FROM_TZ(TIMESTAMP'1999-04-04 03:00:00', 'US/Pacific') FROM DUAL; + +--------EXTRACT +SELECT EXTRACT(TIMEZONE_HOUR FROM TIMESTAMP'1999-12-31 01:30:00 US/Pacific') + FROM DUAL; +SELECT EXTRACT(TIMEZONE_MINUTE FROM TIMESTAMP'1999-12-31 01:30:00 US/Pacific') + FROM DUAL; +SELECT EXTRACT(TIMEZONE_REGION FROM TIMESTAMP'1999-12-31 01:30:00 US/Pacific') + FROM DUAL; +SELECT EXTRACT(TIMEZONE_ABBR FROM TIMESTAMP'1999-12-31 01:30:00 US/Pacific') + FROM DUAL; + +--------TZ_OFFSET +SELECT TZ_OFFSET('GMT') FROM DUAL; +SELECT TZ_OFFSET('Asia/Calcutta') FROM DUAL; + +--------TO_CHAR +SELECT TO_CHAR(TIMESTAMP '1997-01-01 01:00:00 US/Pacific', + 'YYYY-MM-DD HH24:MI:SS TZR') + FROM DUAL; +SELECT TO_CHAR(TIMESTAMP '1997-01-01 01:00:00 US/Pacific PST', + 'YYYY-MM-DD HH24:MI:SS TZR TZD') + FROM DUAL; + +--------CAST +SELECT CAST(TIMESTAMP'1999-10-31 01:01:01.123 US/Pacific' + AS TIMESTAMP(0)) + FROM DUAL; + +SELECT CAST(TIMESTAMP'1999-10-31 01:01:01.123 US/Pacific PST' + AS TIMESTAMP(6)) + FROM DUAL; + +-------TO_TIMESTAMP_TZ +SELECT TO_TIMESTAMP_TZ('14-MAR-1970 01:00:00 AM US/Pacific PST', + 'DD-MON-YYYY HH:MI:SS AM TZR TZD') + FROM DUAL; +SELECT TO_TIMESTAMP_TZ('14-MAR-1970 01:00:00 US/Pacific PST', + 'DD-MON-YYYY HH24:MI:SS TZR TZD') + FROM DUAL; + +-------TO_DSINTERVAL +SELECT TO_DSINTERVAL('100 10:00:00') FROM dual; + +-------TO_YMINTERVAL +SELECT TO_YMINTERVAL('01-02') FROM dual; + +-------NUMTODSINTERVAL +SELECT NUMTODSINTERVAL(12, 'DAY') FROM dual; +SELECT NUMTODSINTERVAL(12, 'MINUTE') FROM dual; + +-------NUMTOYMINTERVAL +SELECT NUMTOYMINTERVAL('01', 'YEAR') FROM dual; +SELECT NUMTOYMINTERVAL('01', 'MONTH') FROM dual; + +-------SYS_EXTRACT_UTC +--extracts the UTC(GMT) from a datetime with timezone displacement +SELECT SYS_EXTRACT_UTC(TIMESTAMP'2000-03-28 11:30:00 -08:00') + FROM dual; + +-------SYSTIMESTAMP, returns TSTZ type +--returns the system date and timezone of the system the database resides +SELECT SYSTIMESTAMP FROM dual; + +-------CURRENT_TIMESTAMP, returns TSTZ type +--returns the current date and time in session time zone +SELECT CURRENT_TIMESTAMP FROM dual; + +-------LOCALTIMESTAMP, returns TS type +--returns the current date and time in session time zone +SELECT LOCALTIMESTAMP FROM dual; +------------------------------------------------------ +--7. Use AT TIME ZONE +------------------------------------------------------ + +SELECT TIMESTAMP'1999-01-01 01:01:01' AT TIME ZONE 'US/Pacific' + FROM dual; + +SELECT TIMESTAMP'1999-01-01 01:01:01' AT TIME ZONE TZ_OFFSET('GMT') FROM DUAL; + +CREATE OR REPLACE FUNCTION myzone RETURN varchar2 IS +BEGIN + RETURN('US/Pacific'); +END; +/ +show errors + +SELECT TIMESTAMP'1997-01-01 01:00:00' AT TIME ZONE myzone FROM dual; + + +------------------------------------------------------ +--8. Datetime Arithmetic +------------------------------------------------------ +--Expect 10-NOV-99 01.30.00.000000000 AM -07:00 +SELECT TIMESTAMP'1999-10-31 01:30:00 -7:00' + +INTERVAL '10 00:00:00' DAY TO SECOND FROM dual; + +--Expect 1999-10-30 11:00:00 -07:00 +SELECT TIMESTAMP'1999-10-31 10:00:00 US/Pacific PST' + + INTERVAL '24' HOUR FROM dual; + +--Expect 1999-04-04 12:00:00.000000000-08:00 +SELECT TIMESTAMP'1999-04-05 01:00:00 US/Pacific PDT' + -INTERVAL '1440' MINUTE FROM dual; + +SELECT TIMESTAMP'1997-01-01 01:00:00 GMT' + +NUMTOYMINTERVAL('01','YEAR') FROM dual; + + +------------------------------------------------------ +--9. Use ERROR_ON_OVERLAP_TIME session parameter +------------------------------------------------------ + +--ERROR_ON_OVERLAP_TIME=TRUE +ALTER SESSION SET ERROR_ON_OVERLAP_TIME=TRUE; + +--error ORA-01883 +SELECT TIMESTAMP'1999-10-31 01:30:00 US/Pacific' FROM dual; + +SELECT TIMESTAMP'1999-10-31 01:30:00 US/Pacific PST' FROM dual; + + +--ERROR_ON_OVERLAP_TIME=FALSE +ALTER SESSION SET ERROR_ON_OVERLAP_TIME=FALSE; + +SELECT TIMESTAMP'1999-10-31 01:30:00 US/Pacific' FROM dual; + +SELECT TIMESTAMP'1999-10-31 01:30:00 US/Pacific PST' FROM dual; + +------------------------------------------------------ +--10. Query from v$timezone_names +------------------------------------------------------ + +CONNECT sys/change_on_install as sysdba; +SELECT DISTINCT tzname FROM v_$timezone_names + WHERE upper(tzname) LIKE '%AMERICA%' + ORDER BY tzname; + + + +connect system/manager; +drop user dtdemo cascade; +exit; diff --git a/demo_rdbms.mk b/demo_rdbms.mk new file mode 100644 index 0000000..f98da3c --- /dev/null +++ b/demo_rdbms.mk @@ -0,0 +1,326 @@ +# +# Example for building demo OCI programs: +# +# 1. All OCI demos (including extdemo2, extdemo4 and extdemo5): +# +# make -f demo_rdbms.mk demos +# +# 2. A single OCI demo: +# +# make -f demo_rdbms.mk build EXE=demo OBJS="demo.o ..." +# e.g. make -f demo_rdbms.mk build EXE=oci02 OBJS=oci02.o +# +# 3. A single OCI demo with static libraries: +# +# make -f demo_rdbms.mk build_static EXE=demo OBJS="demo.o ..." +# e.g. make -f demo_rdbms.mk build_static EXE=oci02 OBJS=oci02.o +# +# 4. To re-generate shared library: +# +# make -f demo_rdbms.mk generate_sharedlib +# +# 5. All OCCI demos +# +# make -f demo_rdbms.mk occidemos +# +# 6. A single OCCI demo: +# +# make -f demo_rdbms.mk +# e.g. make -f demo_rdbms.mk occidml +# OR +# make -f demo_rdbms.mk buildocci EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms.mk buildocci EXE=occidml OBJS=occidml.o +# +# 7. A single OCCI demo with static libraries: +# +# make -f demo_rdbms.mk buildocci_static EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms.mk buildocci_static EXE=occiblob OBJS=occiblob.o +# +# 8. All OCI Connection Pooling, Session Pooling and Statement Cache demos +# +# make -f demo_rdbms.mk cpdemos +# +# 9. A single OCI Connection Pooling demo: +# +# make -f demo_rdbms.mk +# e.g. make -f demo_rdbms.mk cdemocp +# OR +# make -f demo_rdbms.mk buildcp EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms.mk buildcp EXE=cdemocp OBJS=cdemocp.o +# +# 10. A single OCI Connection Pooling demo with static libraries: +# +# make -f demo_rdbms.mk buildcp_static EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms.mk buildcp_static EXE=cdemocp OBJS=cdemocp.o +# +# 11. A single OCI Session Pooling demo: +# +# make -f demo_rdbms.mk +# e.g. make -f demo_rdbms.mk cdemosp +# OR +# make -f demo_rdbms.mk buildcp EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms.mk buildcp EXE=cdemosp OBJS=cdemosp.o +# +# 12. A single OCI Session Pooling demo with static libraries: +# +# make -f demo_rdbms.mk buildcp_static EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms.mk buildcp_static EXE=cdemosp OBJS=cdemosp.o +# +# 13. A single OCI Statement Cache demo: +# +# make -f demo_rdbms.mk +# e.g. make -f demo_rdbms.mk cdemostc +# OR +# make -f demo_rdbms.mk buildcp EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms.mk buildcp EXE=cdemostc OBJS=cdemostc.o +# +# 14. A single OCI Statement Cache demo with static libraries: +# +# make -f demo_rdbms.mk buildcp_static EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms.mk buildcp_static EXE=cdemostc OBJS=cdemostc.o +# +# Example for building demo DIRECT PATH API programs: +# +# 1. All DIRECT PATH API demos: +# +# make -f demo_rdbms.mk demos_dp +# +# 2. A single DIRECT PATH API demo: +# +# make -f demo_rdbms.mk build_dp EXE=demo OBJS="demo.o ..." +# e.g. make -f demo_rdbms.mk build_dp EXE=cdemdplp OBJS=cdemdplp.o +# +# +# Example for building external procedures demo programs: +# +# 1. All external procedure demos: +# +# 2. A single external procedure demo whose 3GL routines do not use the +# "with context" argument: +# +# make -f demo_rdbms.mk extproc_no_context SHARED_LIBNAME=libname +# OBJS="demo.o ..." +# e.g. make -f demo_rdbms.mk extproc_no_context SHARED_LIBNAME=epdemo.so +# OBJS="epdemo1.o epdemo2.o" +# +# 3. A single external procedure demo where one or more 3GL routines use the +# "with context" argument: +# +# make -f demo_rdbms.mk extproc_with_context SHARED_LIBNAME=libname +# OBJS="demo.o ..." +# e.g. make -f demo_rdbms.mk extproc_with_context SHARED_LIBNAME=epdemo.so +# OBJS="epdemo1.o epdemo2.o" +# e.g. make -f demo_rdbms.mk extproc_with_context +# SHARED_LIBNAME=extdemo2.so OBJS="extdemo2.o" +# e.g. or For EXTDEMO2 DEMO ONLY: make -f demo_rdbms.mk demos +# +# 4. To link C++ demos: +# +# make -f demo_rdbms.mk cppdemos +# +# Example for building OCI programs with no pthread dependency +# +# 1. A single OCI demo: +# +# make -f demo_rdbms.mk build_nopthread EXE=demo OBJS="demo.o ..." +# e.g. make -f demo_rdbms.mk build_nopthread EXE=oci02 OBJS=oci02.o +# +# +# NOTE: 1. ORACLE_HOME must be either: +# . set in the user's environment +# . passed in on the command line +# . defined in a modified version of this makefile +# +# 2. If the target platform support shared libraries (e.g. Solaris) +# look in the platform specific documentation for information +# about environment variables that need to be properly +# defined (e.g. LD_LIBRARY_PATH in Solaris). +# + +include $(ORACLE_HOME)/rdbms/lib/env_rdbms.mk + +# flag for linking with non-deferred option (default is deferred mode) +NONDEFER=false + +DEMO_DIR=$(ORACLE_HOME)/rdbms/demo +DEMO_MAKEFILE = $(DEMO_DIR)/demo_rdbms.mk + +DEMOS = cdemo1 cdemo2 cdemo3 cdemo4 cdemo5 cdemo81 cdemo82 \ + cdemobj cdemolb cdemodsc cdemocor cdemolb2 cdemolbs \ + cdemodr1 cdemodr2 cdemodr3 cdemodsa obndra \ + cdemoext cdemothr cdemofil cdemofor \ + oci02 oci03 oci04 oci05 oci06 oci07 oci08 oci09 oci10 \ + oci11 oci12 oci13 oci14 oci15 oci16 oci17 oci18 oci19 oci20 \ + oci21 oci22 oci23 oci24 oci25 readpipe cdemosyev \ + ociaqdemo00 ociaqdemo01 ociaqdemo02 cdemoucb nchdemo1 \ + ociaqarraydeq ociaqarrayenq strmmon + +DEMOS_DP = cdemdpco cdemdpin cdemdpit cdemdplp cdemdpno cdemdpro cdemdpss + +CPPDEMOS = cdemo6 +# OCCI Demos +OCCIDEMOS = occiblob occiclob occicoll occidesc occidml occipool occiproc \ + occistre occiaqlis occiscp occixa occiuni1 occimb1 occilbar +OCCIOTTDEMOS = occiobj occiinh occipobj occiaqop +OCCIOTTUSR = hr +OCCIOTTPWD = hr +OCCI_UNICODE_OPT = none +# OTT Markers Support +OCCIOTTDEMOSWITHMARKER = mdemo1 +OTTUSR = scott +OTTPWD = tiger +CPDEMOS = cdemocp cdemocpproxy cdemosp cdemostc + +.SUFFIXES: .o .cob .for .c .pc .cc .cpp + +demos: $(DEMOS) extdemo2 extdemo4 extdemo5 extdemo6 + +demos_dp: $(DEMOS_DP) + +generate_sharedlib: + $(SILENT)$(ECHO) "Building client shared library ..." + $(SILENT)$(ECHO) "Calling script $$ORACLE_HOME/bin/genclntsh ..." + $(GENCLNTSH) + $(SILENT)$(ECHO) "The library is $$ORACLE_HOME/lib/libclntsh.so... DONE" + $(SILENT)$(ECHO) "Building occi shared library ..." + $(SILENT)$(ECHO) "Calling script $$ORACLE_HOME/bin/genoccish ..." + $(GENOCCISH) + $(SILENT)$(ECHO) "The library is $$ORACLE_HOME/lib/libocci.so... DONE" + +BUILD=build +$(DEMOS): + $(MAKE) -f $(DEMO_MAKEFILE) $(BUILD) EXE=$@ OBJS=$@.o + +$(DEMOS_DP): cdemodp.c cdemodp0.h cdemodp.h + $(MAKE) -f $(DEMO_MAKEFILE) build_dp EXE=$@ OBJS=$@.o + +cppdemos: $(CPPDEMOS) + +$(CPPDEMOS): + $(MAKE) -f $(DEMO_MAKEFILE) buildcpp EXE=$@ OBJS=$@.o + +buildcpp: $(OBJS) + $(MAKECPLPLDEMO) + +occidemos: $(OCCIDEMOS) $(OCCIOTTDEMOS) $(OCCIOTTDEMOSWITHMARKER) + +$(OCCIDEMOS): + $(MAKE) -f $(DEMO_MAKEFILE) buildocci EXE=$@ OBJS=$@.o + +$(OCCIOTTDEMOS): + $(MAKE) -f $(DEMO_MAKEFILE) occiott OCCIOTTFILE=$@ + $(MAKE) -f $(DEMO_MAKEFILE) buildocci EXE=$@ OBJS="$@.o $@o.o $@m.o" + +# OTT Markers Support +$(OCCIOTTDEMOSWITHMARKER): + $(MAKE) -f $(DEMO_MAKEFILE) ott_mrkr OTTFILE=$@ + $(MAKE) -f $(DEMO_MAKEFILE) buildocci EXE=$@ OBJS="$@.o $@o.o $@m.o" + + +buildocci: $(OBJS) + $(MAKEOCCISHAREDDEMO) + +buildocci_static: $(OBJS) + $(MAKEOCCISTATICDEMO) + +occiott: + $(ORACLE_HOME)/bin/ott \ + userid=$(OCCIOTTUSR)/$(OCCIOTTPWD) \ + intype=$(OCCIOTTFILE).typ \ + outtype=$(OCCIOTTFILE)out.type \ + code=cpp \ + hfile=$(OCCIOTTFILE).h \ + cppfile=$(OCCIOTTFILE)o.cpp \ + attraccess=private \ + unicode=$(OCCI_UNICODE_OPT) + +# OTT Markers Suppport +ott_mrkr: + $(ORACLE_HOME)/bin/ott \ + userid=$(OTTUSR)/$(OTTPWD) \ + intype=$(OTTFILE).typ \ + outtype=$(OTTFILE)out.type \ + code=cpp \ + hfile=$(OTTFILE).h \ + cppfile=$(OTTFILE)o.cpp \ + use_marker=true + +cpdemos: $(CPDEMOS) +$(CPDEMOS): + $(MAKE) -f $(DEMO_MAKEFILE) buildcp EXE=$@ OBJS=$@.o +buildcp: $(OBJS) + $(MAKECPSHAREDDEMO) +buildcp_static: $(OBJS) + $(MAKECPSTATICDEMO) + +# Pro*C rules +# SQL Precompiler macros + +pc1: + $(PCC2C) + +.pc.c: + $(MAKE) -f $(DEMO_MAKEFILE) PCCSRC=$* I_SYM=include= pc1 + +.pc.o: + $(MAKE) -f $(DEMO_MAKEFILE) PCCSRC=$* I_SYM=include= pc1 + $(PCCC2O) + +.cc.o: + $(CCC2O) + +.cpp.o: + $(CCC2O) + +build: $(LIBCLNTSH) $(OBJS) + $(BUILDEXE) + +extdemo2: + $(MAKE) -f $(DEMO_MAKEFILE) extproc_with_context SHARED_LIBNAME=extdemo2.so OBJS="extdemo2.o" + +extdemo4: + $(MAKE) -f $(DEMO_MAKEFILE) extproc_with_context SHARED_LIBNAME=extdemo4.so OBJS="extdemo4.o" + +extdemo5: + $(MAKE) -f $(DEMO_MAKEFILE) extproc_with_context SHARED_LIBNAME=extdemo5.so OBJS="extdemo5.o" + +extdemo6: + $(MAKE) -f $(DEMO_MAKEFILE) extproc_with_context SHARED_LIBNAME=extdemo6.so OBJS="extdemo6.o" + +.c.o: + $(C2O) + +build_dp: $(LIBCLNTSH) $(OBJS) cdemodp.o + $(DPTARGET) + +build_static: $(OBJS) + $(O2STATIC) + +# These 3 macros should be supplied by platform-specific files +#LLIBCLNTSH_NPT=$(LDLIBFLAG)$(LIBCLNTSHNAME)_nopthread +#LIBCLNTSH_NPT=$(LIBHOME)$(LIB_PREFIX)$(LIBCLNTSHNAME)_nopthread.$(SO_EXT) +#SYSLIBS_NPT=`$(CAT) $(SYSLIBLIST) | sed 's/-lpthread//g' ` + +build_clntshared : + $(MAKECLNTSHAREDDEMO) + +# You can build OCI programs with no pthread dependency using +# the following target. +build_nopthread: $(LIBCLNTSH_NPT) $(OBJS) + $(SILENT)$(MAKE) -f $(DEMO_MAKEFILE) build EXE=$(EXE) OBJS=$(OBJS) \ + LLIBCLNTSH=$(LLIBCLNTSH_NPT) SYSLIBS='$(SYSLIBS_NPT)' + +# extproc_no_context and extproc_with_context are the current names of these +# targets. The old names, extproc_nocallback and extproc_callback are +# preserved for backward compatibility. + +extproc_no_context extproc_nocallback: $(OBJS) + $(BUILDLIB_NO_CONTEXT) + +extproc_with_context extproc_callback: $(OBJS) $(LIBCLNTSH) + $(BUILDLIB_WITH_CONTEXT) + +clean: + $(RM) -f $(DEMOS) $(CPDEMOS) extdemo2 extdemo4 extdemo5 extdemo6 *.o *.so + $(RM) -f $(OCCIDEMOS) $(OCCIOTTDEMOS) $(OCCIOTTDEMOSWITHMARKER) occi*m.cpp occi*o.cpp occi*.type occiobj*.h occiinh*.h occipobj*.h + $(RM) -f $(DEMOS_DP) diff --git a/demo_rdbms32.mk b/demo_rdbms32.mk new file mode 100644 index 0000000..535a1f2 --- /dev/null +++ b/demo_rdbms32.mk @@ -0,0 +1,337 @@ +# This makefile is similar to demo_rdbms.mk, but this one builds +# 32-bit client executables. (It uses demo_rdbms.mk to build any +# shared-libraries that are loaded into the database server, e.g. for +# external procedure call.) +# +# Example for building demo OCI programs: +# +# 1. All OCI demos (including extdemo2, extdemo4 and extdemo5): +# +# make -f demo_rdbms32.mk demos +# +# 2. A single OCI demo: +# +# make -f demo_rdbms32.mk build EXE=demo OBJS="demo.o ..." +# e.g. make -f demo_rdbms32.mk build EXE=oci02 OBJS=oci02.o +# +# 3. A single OCI demo with static libraries: +# +# make -f demo_rdbms32.mk build_static EXE=demo OBJS="demo.o ..." +# e.g. make -f demo_rdbms32.mk build_static EXE=oci02 OBJS=oci02.o +# +# 4. To re-generate shared library: +# +# make -f demo_rdbms32.mk generate_sharedlib +# +# 5. All OCCI demos +# +# make -f demo_rdbms32.mk occidemos +# +# 6. A single OCCI demo: +# +# make -f demo_rdbms32.mk +# e.g. make -f demo_rdbms32.mk occidml +# OR +# make -f demo_rdbms32.mk buildocci EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms32.mk buildocci EXE=occidml OBJS=occidml.o +# +# 7. A single OCCI demo with static libraries: +# +# make -f demo_rdbms32.mk buildocci_static EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms32.mk buildocci_static EXE=occiblob OBJS=occiblob.o +# +# 8. All OCI Connection Pooling, Session Pooling and Statement Cache demos +# +# make -f demo_rdbms32.mk cpdemos +# +# 9. A single OCI Connection Pooling demo: +# +# make -f demo_rdbms32.mk +# e.g. make -f demo_rdbms32.mk cdemocp +# OR +# make -f demo_rdbms32.mk buildcp EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms32.mk buildcp EXE=cdemocp OBJS=cdemocp.o +# +# 10. A single OCI Connection Pooling demo with static libraries: +# +# make -f demo_rdbms32.mk buildcp_static EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms32.mk buildcp_static EXE=cdemocp OBJS=cdemocp.o +# +# 11. A single OCI Session Pooling demo: +# +# make -f demo_rdbms32.mk +# e.g. make -f demo_rdbms32.mk cdemosp +# OR +# make -f demo_rdbms32.mk buildcp EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms32.mk buildcp EXE=cdemosp OBJS=cdemosp.o +# +# 12. A single OCI Session Pooling demo with static libraries: +# +# make -f demo_rdbms32.mk buildcp_static EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms32.mk buildcp_static EXE=cdemosp OBJS=cdemosp.o +# +# +# 13. A single OCI Statement Cache demo: +# +# make -f demo_rdbms32.mk +# e.g. make -f demo_rdbms32.mk cdemostc +# OR +# make -f demo_rdbms32.mk buildcp EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms32.mk buildcp EXE=cdemostc OBJS=cdemostc.o +# +# 14. A single OCI Statement Cache demo with static libraries: +# +# make -f demo_rdbms32.mk buildcp_static EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms32.mk buildcp_static EXE=cdemostc OBJS=cdemostc.o +# +# +# Example for building demo DIRECT PATH API programs: +# +# 1. All DIRECT PATH API demos: +# +# make -f demo_rdbms32.mk demos_dp +# +# 2. A single DIRECT PATH API demo: +# +# make -f demo_rdbms32.mk build_dp EXE=demo OBJS="demo.o ..." +# e.g. make -f demo_rdbms32.mk build_dp EXE=cdemdplp OBJS=cdemdplp.o +# +# +# Example for building external procedures demo programs: +# +# 1. All external procedure demos: +# +# 2. A single external procedure demo whose 3GL routines do not use the +# "with context" argument: +# +# make -f demo_rdbms32.mk extproc_no_context SHARED_LIBNAME=libname +# OBJS="demo.o ..." +# e.g. make -f demo_rdbms32.mk extproc_no_context SHARED_LIBNAME=epdemo.so +# OBJS="epdemo1.o epdemo2.o" +# +# 3. A single external procedure demo where one or more 3GL routines use the +# "with context" argument: +# +# make -f demo_rdbms32.mk extproc_with_context SHARED_LIBNAME=libname +# OBJS="demo.o ..." +# e.g. make -f demo_rdbms32.mk extproc_with_context SHARED_LIBNAME=epdemo.so +# OBJS="epdemo1.o epdemo2.o" +# e.g. make -f demo_rdbms32.mk extproc_with_context +# SHARED_LIBNAME=extdemo2.so OBJS="extdemo2.o" +# e.g. or For EXTDEMO2 DEMO ONLY: make -f demo_rdbms32.mk demos +# +# 4. To link C++ demos: +# +# make -f demo_rdbms32.mk cppdemos +# +# Example for building OCI programs with libclntsh.so +# +# 1. A single OCI demo: +# +# make -f demo_rdbms32.mk build_clntshared EXE=demo OBJS="demo.o ..." +# e.g. make -f demo_rdbms32.mk build_clntshared EXE=oci02 OBJS=oci02.o +# +# Example for building OCI programs with no pthread dependency +# +# 1. A single OCI demo: +# +# make -f demo_rdbms32.mk build_nopthread EXE=demo OBJS="demo.o ..." +# e.g. make -f demo_rdbms32.mk build_nopthread EXE=oci02 OBJS=oci02.o +# +# +# +# NOTE: 1. ORACLE_HOME must be either: +# . set in the user's environment +# . passed in on the command line +# . defined in a modified version of this makefile +# +# 2. If the target platform support shared libraries (e.g. Solaris) +# look in the platform specific documentation for information +# about environment variables that need to be properly +# defined (e.g. LD_LIBRARY_PATH in Solaris). +# + +include $(ORACLE_HOME)/rdbms/lib/env_rdbms.mk + +# flag for linking with non-deferred option (default is deferred mode) +NONDEFER=false + +DEMO_DIR=$(ORACLE_HOME)/rdbms/demo +DEMO_MAKEFILE = $(DEMO_DIR)/demo_rdbms.mk +DEMO32_MAKEFILE = $(DEMO_DIR)/demo_rdbms32.mk + +DEMOS = cdemo1 cdemo2 cdemo3 cdemo4 cdemo5 cdemo81 cdemo82 \ + cdemobj cdemolb cdemodsc cdemocor cdemolb2 cdemolbs \ + cdemodr1 cdemodr2 cdemodr3 cdemodsa obndra \ + cdemoext cdemothr cdemofil cdemofor \ + oci02 oci03 oci04 oci05 oci06 oci07 oci08 oci09 oci10 \ + oci11 oci12 oci13 oci14 oci15 oci16 oci17 oci18 oci19 oci20 \ + oci21 oci22 oci23 oci24 oci25 readpipe cdemosyev \ + ociaqdemo00 ociaqdemo01 ociaqdemo02 cdemoucb nchdemo1 \ + ociaqarraydeq ociaqarrayenq strmmon + +DEMOS_DP = cdemdpco cdemdpin cdemdpit cdemdplp cdemdpno cdemdpro cdemdpss + +CPPDEMOS = cdemo6 +# OCCI Demos +OCCIDEMOS = occiblob occiclob occicoll occidesc occidml occipool occiproc \ + occistre occiaqlis occiscp occixa occiuni1 occimb1 occilbar +OCCIOTTDEMOS = occiobj occiinh occipobj occiaqop +OCCIOTTUSR = hr +OCCIOTTPWD = hr +OCCI_UNICODE_OPT = none +# OTT Markers Support +OCCIOTTDEMOSWITHMARKER = mdemo1 +OTTUSR = scott +OTTPWD = tiger +CPDEMOS = cdemocp cdemocpproxy cdemosp cdemostc + +.SUFFIXES: .o .cob .for .c .pc .cc .cpp + +demos: $(DEMOS) extdemo2 extdemo4 extdemo5 extdemo6 + +demos_dp: $(DEMOS_DP) + +generate_sharedlib: + $(SILENT)$(ECHO) "Building client shared library ..." + $(SILENT)$(ECHO) "Calling script $$ORACLE_HOME/bin/genclntsh ..." + $(GENCLNTSH32) + $(SILENT)$(ECHO) "The library is $$ORACLE_HOME/lib/libclntsh.so... DONE" + +BUILD=build +$(DEMOS): + $(MAKE) -f $(DEMO32_MAKEFILE) $(BUILD) EXE=$@ OBJS=$@.o + +$(DEMOS_DP): cdemodp.c cdemodp0.h cdemodp.h + $(MAKE) -f $(DEMO32_MAKEFILE) build_dp EXE=$@ OBJS=$@.o + +cppdemos: $(CPPDEMOS) + +$(CPPDEMOS): + $(MAKE) -f $(DEMO32_MAKEFILE) buildcpp EXE=$@ OBJS=$@.o + +buildcpp: $(OBJS) + $(MAKECPLPLDEMO32) + +occidemos: $(OCCIDEMOS) $(OCCIOTTDEMOS) $(OCCIOTTDEMOSWITHMARKER) + +$(OCCIDEMOS): + $(MAKE) -f $(DEMO32_MAKEFILE) buildocci EXE=$@ OBJS=$@.o + +$(OCCIOTTDEMOS): + $(MAKE) -f $(DEMO32_MAKEFILE) occiott OCCIOTTFILE=$@ + $(MAKE) -f $(DEMO32_MAKEFILE) buildocci EXE=$@ OBJS="$@.o $@o.o $@m.o" + +# OTT Markers Support +$(OCCIOTTDEMOSWITHMARKER): + $(MAKE) -f $(DEMO32_MAKEFILE) ott_mrkr OTTFILE=$@ + $(MAKE) -f $(DEMO32_MAKEFILE) buildocci EXE=$@ OBJS="$@.o $@o.o $@m.o" + + +buildocci: $(OBJS) + $(MAKEOCCISHAREDDEMO32) + +buildocci_static: $(OBJS) + $(MAKEOCCISTATICDEMO32) + +occiott: + $(ORACLE_HOME)/bin/ott \ + userid=$(OCCIOTTUSR)/$(OCCIOTTPWD) \ + intype=$(OCCIOTTFILE).typ \ + outtype=$(OCCIOTTFILE)out.type \ + code=cpp \ + hfile=$(OCCIOTTFILE).h \ + cppfile=$(OCCIOTTFILE)o.cpp \ + attraccess=private \ + unicode=$(OCCI_UNICODE_OPT) + +# OTT Markers Suppport +ott_mrkr: + $(ORACLE_HOME)/bin/ott \ + userid=$(OTTUSR)/$(OTTPWD) \ + intype=$(OTTFILE).typ \ + outtype=$(OTTFILE)out.type \ + code=cpp \ + hfile=$(OTTFILE).h \ + cppfile=$(OTTFILE)o.cpp \ + use_marker=true + +cpdemos: $(CPDEMOS) +$(CPDEMOS): + $(MAKE) -f $(DEMO32_MAKEFILE) buildcp EXE=$@ OBJS=$@.o +buildcp: $(OBJS) + $(MAKECPSHAREDDEMO32) +buildcp_static: $(OBJS) + $(MAKECPSTATICDEMO32) + +# Pro*C rules +# SQL Precompiler macros + +pc1: + $(PCC2C) + +.pc.c: + $(MAKE) -f $(DEMO32_MAKEFILE) PCCSRC=$* I_SYM=include= pc1 + +.pc.o: + $(MAKE) -f $(DEMO32_MAKEFILE) PCCSRC=$* I_SYM=include= pc1 + $(PCCC2O32) + +.cc.o: + $(CCC2O32) + +.cpp.o: + $(CCC2O32) + +build: $(LIBCLNTSH) $(OBJS) + $(BUILDEXE32) + +extdemo2: + $(MAKE) -f $(DEMO32_MAKEFILE) extproc_with_context SHARED_LIBNAME=extdemo2.so OBJS="extdemo2.o" + +extdemo4: + $(MAKE) -f $(DEMO32_MAKEFILE) extproc_with_context SHARED_LIBNAME=extdemo4.so OBJS="extdemo4.o" + +extdemo5: + $(MAKE) -f $(DEMO32_MAKEFILE) extproc_with_context SHARED_LIBNAME=extdemo5.so OBJS="extdemo5.o" + +extdemo6: + $(MAKE) -f $(DEMO32_MAKEFILE) extproc_with_context SHARED_LIBNAME=extdemo6.so OBJS="extdemo6.o" + +.c.o: + $(C2O32) + +build_dp: $(LIBCLNTSH) $(OBJS) cdemodp.o + $(DPTARGET32) + +build_static: $(OBJS) + $(O2STATIC32) + +# These 3 should be supplied by platform specific files +#LLIBCLNTSH_NPT=$(LDLIBFLAG)$(LIBCLNTSHNAME)_nopthread +#LIBCLNTSH_NPT=$(LIBHOME32)$(LIB_PREFIX)$(LIBCLNTSHNAME)_nopthread.$(SO_EXT) +#BUILDEXE32_NPT=$(CC) $(LDFLAGS32) -o $(EXE) $(OBJS) $(LLIBCLNTSH_NPT) $(MATHLIB) + +build_clntshared : + $(MAKECLNTSHAREDDEMO32) + +# You can build OCI programs with no pthread dependency using +# the following target. +build_nopthread: $(LIBCLNTSH_NPT) $(OBJS) + $(MAKENPTDEMO32) + +# extproc_no_context and extproc_with_context are the current names of these +# targets. The old names, extproc_nocallback and extproc_callback are +# preserved for backward compatibility. + +extproc_no_context extproc_nocallback: $(OBJS) + $(BUILDLIB32_NO_CONTEXT) + +extproc_with_context extproc_callback: $(OBJS) $(LIBCLNTSH) + $(BUILDLIB32_WITH_CONTEXT) + +clean: + $(RM) -f $(DEMOS) $(CPDEMOS) extdemo2 extdemo4 extdemo5 extdemo6 *.o *.so + $(RM) -f $(OCCIDEMOS) $(OCCIOTTDEMOS) $(OCCIOTTDEMOSWITHMARKER) occi*m.cpp occi*o.cpp \ + occi*.type occiobj*.h occiinh*.h occipobj*.h + $(RM) -f $(DEMOS_DP) diff --git a/demo_rdbms64.mk b/demo_rdbms64.mk new file mode 100644 index 0000000..8b6b2b2 --- /dev/null +++ b/demo_rdbms64.mk @@ -0,0 +1,327 @@ +# This makefile is similar to demo_rdbms.mk, but this one builds +# 64-bit client executables. (It uses demo_rdbms.mk to build any +# shared-libraries that are loaded into the database server, e.g. for +# external procedure call.) +# +# Example for building demo OCI programs: +# +# 1. All OCI demos (including extdemo2, extdemo4 and extdemo5): +# +# make -f demo_rdbms64.mk demos +# +# 2. A single OCI demo: +# +# make -f demo_rdbms64.mk build EXE=demo OBJS="demo.o ..." +# e.g. make -f demo_rdbms64.mk build EXE=oci02 OBJS=oci02.o +# +# 3. A single OCI demo with static libraries: +# +# make -f demo_rdbms64.mk build_static EXE=demo OBJS="demo.o ..." +# e.g. make -f demo_rdbms64.mk build_static EXE=oci02 OBJS=oci02.o +# +# 4. To re-generate shared library: +# +# make -f demo_rdbms64.mk generate_sharedlib +# +# 5. All OCCI demos +# +# make -f demo_rdbms64.mk occidemos +# +# 6. A single OCCI demo: +# +# make -f demo_rdbms64.mk +# e.g. make -f demo_rdbms64.mk occidml +# OR +# make -f demo_rdbms64.mk buildocci EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms64.mk buildocci EXE=occidml OBJS=occidml.o +# +# 7. A single OCCI demo with static libraries: +# +# make -f demo_rdbms64.mk buildocci_static EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms64.mk buildocci_static EXE=occiblob OBJS=occiblob.o +# +# 8. All OCI Connection Pooling, Session Pooling and Statement Cache demos +# +# make -f demo_rdbms64.mk cpdemos +# +# 9. A single OCI Connection Pooling demo: +# +# make -f demo_rdbms64.mk +# e.g. make -f demo_rdbms64.mk cdemocp +# OR +# make -f demo_rdbms64.mk buildcp EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms64.mk buildcp EXE=cdemocp OBJS=cdemocp.o +# +# 10. A single OCI Connection Pooling demo with static libraries: +# +# make -f demo_rdbms64.mk buildcp_static EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms64.mk buildcp_static EXE=cdemocp OBJS=cdemocp.o +# +# 11. A single OCI Session Pooling demo: +# +# make -f demo_rdbms64.mk +# e.g. make -f demo_rdbms64.mk cdemosp +# OR +# make -f demo_rdbms64.mk buildcp EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms64.mk buildcp EXE=cdemosp OBJS=cdemosp.o +# +# 12. A single OCI Session Pooling demo with static libraries: +# +# make -f demo_rdbms64.mk buildcp_static EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms64.mk buildcp_static EXE=cdemosp OBJS=cdemosp.o +# +# +# 13. A single OCI Statement Cache demo: +# +# make -f demo_rdbms64.mk +# e.g. make -f demo_rdbms64.mk cdemostc +# OR +# make -f demo_rdbms64.mk buildcp EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms64.mk buildcp EXE=cdemostc OBJS=cdemostc.o +# +# 14. A single OCI Statement Cache demo with static libraries: +# +# make -f demo_rdbms64.mk buildcp_static EXE=demoname OBJS="demoname.o ..." +# e.g. make -f demo_rdbms64.mk buildcp_static EXE=cdemostc OBJS=cdemostc.o +# +# +# Example for building demo DIRECT PATH API programs: +# +# 1. All DIRECT PATH API demos: +# +# make -f demo_rdbms64.mk demos_dp +# +# 2. A single DIRECT PATH API demo: +# +# make -f demo_rdbms64.mk build_dp EXE=demo OBJS="demo.o ..." +# e.g. make -f demo_rdbms64.mk build_dp EXE=cdemdplp OBJS=cdemdplp.o +# +# +# Example for building external procedures demo programs: +# +# 1. All external procedure demos: +# +# 2. A single external procedure demo whose 3GL routines do not use the +# "with context" argument: +# +# make -f demo_rdbms64.mk extproc_no_context SHARED_LIBNAME=libname +# OBJS="demo.o ..." +# e.g. make -f demo_rdbms64.mk extproc_no_context SHARED_LIBNAME=epdemo.so +# OBJS="epdemo1.o epdemo2.o" +# +# 3. A single external procedure demo where one or more 3GL routines use the +# "with context" argument: +# +# make -f demo_rdbms64.mk extproc_with_context SHARED_LIBNAME=libname +# OBJS="demo.o ..." +# e.g. make -f demo_rdbms64.mk extproc_with_context SHARED_LIBNAME=epdemo.so +# OBJS="epdemo1.o epdemo2.o" +# e.g. make -f demo_rdbms64.mk extproc_with_context +# SHARED_LIBNAME=extdemo2.so OBJS="extdemo2.o" +# e.g. or For EXTDEMO2 DEMO ONLY: make -f demo_rdbms64.mk demos +# +# 4. To link C++ demos: +# +# make -f demo_rdbms64.mk cppdemos +# +# 1. A single OCI demo: +# +# make -f demo_rdbms64.mk build_clntshared EXE=demo OBJS="demo.o ..." +# e.g. make -f demo_rdbms64.mk build_clntshared EXE=oci02 OBJS=oci02.o +# +# Example for building OCI programs with no pthread dependency +# +# 1. A single OCI demo: +# +# make -f demo_rdbms64.mk build_nopthread EXE=demo OBJS="demo.o ..." +# e.g. make -f demo_rdbms64.mk build_nopthread EXE=oci02 OBJS=oci02.o +# +# NOTE: 1. ORACLE_HOME must be either: +# . set in the user's environment +# . passed in on the command line +# . defined in a modified version of this makefile +# +# 2. If the target platform support shared libraries (e.g. Solaris) +# look in the platform specific documentation for information +# about environment variables that need to be properly +# defined (e.g. LD_LIBRARY_PATH in Solaris). +# + +include $(ORACLE_HOME)/rdbms/lib/env_rdbms.mk + +# flag for linking with non-deferred option (default is deferred mode) +NONDEFER=false + +DEMO_DIR=$(ORACLE_HOME)/rdbms/demo +DEMO_MAKEFILE = $(DEMO_DIR)/demo_rdbms.mk +DEMO64_MAKEFILE = $(DEMO_DIR)/demo_rdbms64.mk + +DEMOS = cdemo1 cdemo2 cdemo3 cdemo4 cdemo5 cdemo81 cdemo82 \ + cdemobj cdemolb cdemodsc cdemocor cdemolb2 cdemolbs \ + cdemodr1 cdemodr2 cdemodr3 cdemodsa obndra \ + cdemoext cdemothr cdemofil cdemofor \ + oci02 oci03 oci04 oci05 oci06 oci07 oci08 oci09 oci10 \ + oci11 oci12 oci13 oci14 oci15 oci16 oci17 oci18 oci19 oci20 \ + oci21 oci22 oci23 oci24 oci25 readpipe cdemosyev \ + ociaqdemo00 ociaqdemo01 ociaqdemo02 cdemoucb nchdemo1 \ + ociaqarraydeq ociaqarrayenq strmmon + +DEMOS_DP = cdemdpco cdemdpin cdemdpit cdemdplp cdemdpno cdemdpro cdemdpss + +CPPDEMOS = cdemo6 +# OCCI Demos +OCCIDEMOS = occiblob occiclob occicoll occidesc occidml occipool occiproc \ + occistre occiaqlis occiscp occixa occiuni1 occimb1 occilbar +OCCIOTTDEMOS = occiobj occiinh occipobj occiaqop +OCCIOTTUSR = hr +OCCIOTTPWD = hr +OCCI_UNICODE_OPT = none +# OTT Markers Support +OCCIOTTDEMOSWITHMARKER = mdemo1 +OTTUSR = scott +OTTPWD = tiger +CPDEMOS = cdemocp cdemocpproxy cdemosp cdemostc + +.SUFFIXES: .o .cob .for .c .pc .cc .cpp + +demos: $(DEMOS) extdemo2 extdemo4 extdemo5 extdemo6 + +demos_dp: $(DEMOS_DP) + +generate_sharedlib: + $(SILENT)$(ECHO) "Building client shared library ..." + $(SILENT)$(ECHO) "Calling script $$ORACLE_HOME/bin/genclntsh ..." + $(GENCLNTSH64) + $(SILENT)$(ECHO) "The library is $$ORACLE_HOME/lib/libclntsh.so... DONE" + +BUILD=build +$(DEMOS): + $(MAKE) -f $(DEMO64_MAKEFILE) $(BUILD) EXE=$@ OBJS=$@.o + +$(DEMOS_DP): cdemodp.c cdemodp0.h cdemodp.h + $(MAKE) -f $(DEMO64_MAKEFILE) build_dp EXE=$@ OBJS=$@.o + +cppdemos: $(CPPDEMOS) + +$(CPPDEMOS): + $(MAKE) -f $(DEMO64_MAKEFILE) buildcpp EXE=$@ OBJS=$@.o + +buildcpp: $(OBJS) + $(MAKECPLPLDEMO64) + +occidemos: $(OCCIDEMOS) $(OCCIOTTDEMOS) $(OCCIOTTDEMOSWITHMARKER) + +$(OCCIDEMOS): + $(MAKE) -f $(DEMO64_MAKEFILE) buildocci EXE=$@ OBJS=$@.o + +$(OCCIOTTDEMOS): + $(MAKE) -f $(DEMO64_MAKEFILE) occiott OCCIOTTFILE=$@ + $(MAKE) -f $(DEMO64_MAKEFILE) buildocci EXE=$@ OBJS="$@.o $@o.o $@m.o" + +# OTT Markers Support +$(OCCIOTTDEMOSWITHMARKER): + $(MAKE) -f $(DEMO64_MAKEFILE) ott_mrkr OTTFILE=$@ + $(MAKE) -f $(DEMO64_MAKEFILE) buildocci EXE=$@ OBJS="$@.o $@o.o $@m.o" + +buildocci: $(OBJS) + $(MAKEOCCISHAREDDEMO64) + +buildocci_static: $(OBJS) + $(MAKEOCCISTATICDEMO64) + +occiott: + $(ORACLE_HOME)/bin/ott \ + userid=$(OCCIOTTUSR)/$(OCCIOTTPWD) \ + intype=$(OCCIOTTFILE).typ \ + outtype=$(OCCIOTTFILE)out.type \ + code=cpp \ + hfile=$(OCCIOTTFILE).h \ + cppfile=$(OCCIOTTFILE)o.cpp \ + attraccess=private \ + unicode=$(OCCI_UNICODE_OPT) + +# OTT Markers Suppport +ott_mrkr: + $(ORACLE_HOME)/bin/ott \ + userid=$(OTTUSR)/$(OTTPWD) \ + intype=$(OTTFILE).typ \ + outtype=$(OTTFILE)out.type \ + code=cpp \ + hfile=$(OTTFILE).h \ + cppfile=$(OTTFILE)o.cpp \ + use_marker=true + +cpdemos: $(CPDEMOS) +$(CPDEMOS): + $(MAKE) -f $(DEMO64_MAKEFILE) buildcp EXE=$@ OBJS=$@.o +buildcp: $(OBJS) + $(MAKECPSHAREDDEMO64) +buildcp_static: $(OBJS) + $(MAKECPSTATICDEMO64) + +# Pro*C rules +# SQL Precompiler macros + +pc1: + $(PCC2C) + +.pc.c: + $(MAKE) -f $(DEMO64_MAKEFILE) PCCSRC=$* I_SYM=include= pc1 + +.pc.o: + $(MAKE) -f $(DEMO64_MAKEFILE) PCCSRC=$* I_SYM=include= pc1 + $(PCCC2O64) + +.cc.o: + $(CCC2O64) + +.cpp.o: + $(CCC2O64) + +build: $(LIBCLNTSH) $(OBJS) + $(BUILDEXE64) + +extdemo2: + $(MAKE) -f $(DEMO64_MAKEFILE) extproc_with_context SHARED_LIBNAME=extdemo2.so OBJS="extdemo2.o" + +extdemo4: + $(MAKE) -f $(DEMO64_MAKEFILE) extproc_with_context SHARED_LIBNAME=extdemo4.so OBJS="extdemo4.o" + +extdemo5: + $(MAKE) -f $(DEMO64_MAKEFILE) extproc_with_context SHARED_LIBNAME=extdemo5.so OBJS="extdemo5.o" + +extdemo6: + $(MAKE) -f $(DEMO64_MAKEFILE) extproc_with_context SHARED_LIBNAME=extdemo6.so OBJS="extdemo6.o" + +.c.o: + $(C2O64) + +build_dp: $(LIBCLNTSH) $(OBJS) cdemodp.o + $(DPTARGET64) + +build_static: $(OBJS) + $(O2STATIC64) + +build_clntshared : + $(MAKECLNTSHAREDDEMO64) + +# You can build OCI programs with no pthread dependency using +# the following target. +build_nopthread: $(LIBCLNTSH_NPT) $(OBJS) + $(MAKENPTDEMO64) + +# extproc_no_context and extproc_with_context are the current names of these +# targets. The old names, extproc_nocallback and extproc_callback are +# preserved for backward compatibility. + +extproc_no_context extproc_nocallback: $(OBJS) + $(BUILDLIB64_NO_CONTEXT) + +extproc_with_context extproc_callback: $(OBJS) $(LIBCLNTSH) + $(BUILDLIB64_WITH_CONTEXT) + +clean: + $(RM) -f $(DEMOS) $(CPDEMOS) extdemo2 extdemo4 extdemo5 extdemo6 *.o *.so + $(RM) -f $(OCCIDEMOS) $(OCCIOTTDEMOS) $(OCCIOTTDEMOSWITHMARKER) occi*m.cpp occi*o.cpp \ + occi*.type occiobj*.h occiinh*.h occipobj*.h + $(RM) -f $(DEMOS_DP) diff --git a/dmabdemo.java b/dmabdemo.java new file mode 100644 index 0000000..b90ea30 --- /dev/null +++ b/dmabdemo.java @@ -0,0 +1,1125 @@ +import java.math.BigDecimal; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.Statement; + +import java.text.DecimalFormat; +import java.text.MessageFormat; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.MiningAlgorithm; +import javax.datamining.MiningFunction; +import javax.datamining.NamedObject; +import javax.datamining.base.AlgorithmSettings; +import javax.datamining.base.Model; +import javax.datamining.base.Task; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.ModelSignature; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.data.SignatureAttribute; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.rule.CompoundPredicate; +import javax.datamining.rule.Rule; +import javax.datamining.rule.SimplePredicate; +import javax.datamining.supervised.classification.ClassificationApplySettings; +import javax.datamining.supervised.classification.ClassificationApplySettingsFactory; +import javax.datamining.supervised.classification.ClassificationModel; +import javax.datamining.supervised.classification.ClassificationSettings; +import javax.datamining.supervised.classification.ClassificationSettingsFactory; +import javax.datamining.supervised.classification.ClassificationTestMetricOption; +import javax.datamining.supervised.classification.ClassificationTestMetrics; +import javax.datamining.supervised.classification.ClassificationTestMetricsTask; +import javax.datamining.supervised.classification.ClassificationTestMetricsTaskFactory; +import javax.datamining.supervised.classification.ClassificationTestTaskFactory; +import javax.datamining.supervised.classification.ConfusionMatrix; +import javax.datamining.supervised.classification.Lift; +import javax.datamining.supervised.classification.ReceiverOperatingCharacterics; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; +import javax.datamining.task.apply.DataSetApplyTask; +import javax.datamining.task.apply.DataSetApplyTaskFactory; + +import oracle.dmt.jdm.algorithm.abn.OraABNModelType; +import oracle.dmt.jdm.algorithm.abn.OraABNSettings; +import oracle.dmt.jdm.algorithm.abn.OraABNSettingsFactory; +import oracle.dmt.jdm.base.OraModel; +import oracle.dmt.jdm.base.OraTask; +import oracle.dmt.jdm.modeldetail.abn.OraABNModelDetail; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.rule.OraSimplePredicate; +import oracle.dmt.jdm.supervised.classification.OraLift; +import oracle.dmt.jdm.task.OraBuildTask; +import oracle.dmt.jdm.task.OraTransformationTask; +import oracle.dmt.jdm.task.OraTransformationTaskFactory; +import oracle.dmt.jdm.transform.OraExpressionTransform; +import oracle.dmt.jdm.transform.OraTransformationFactory; +import oracle.dmt.jdm.transform.OraTransformationSequence; +import oracle.dmt.jdm.transform.binning.OraBinningTransform; +import oracle.dmt.jdm.transform.binning.OraCategoricalBinningType; +import oracle.dmt.jdm.transform.binning.OraNumericalBinningType; + + +// Copyright (c) 2004, 2006, Oracle. All rights reserved. +// File: dmabdemo.java +//J2SE imports + + +// Java Data Mining (JDM) standard imports +// Oracle Java Data Mining (JDM) implemented api imports + +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to solve a classification problem using Adaptive Bayes Network(ABN) algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* How to predict whether a customer responds or not to the new affinity card +* program using a classifier based on ABN algorithm? +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the previous affinity card +* programs. Data exploration and preparing the data is a common step before +* doing data mining. Here in this demo, the following views are created in the user +* schema using CUSTOMERS, COUNTRIES and SUPPLIMENTARY_DEMOGRAPHICS tables. +* +* MINING_DATA_BUILD_V: +* This view collects the previous customers' demographic, purchasing, and affinity +* card response details for building the model. +* +* MINING_DATA_TEST_V: +* This view collects the previous customers' demographic, purchasing, and affinity +* card response details for testing the model. +* +* MINING_DATA_APPLY_V: +* This view collects the prospective customers' demographic and purchasing +* details for predicting response to the new affinity card program. +* +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Prepare Data: +* For ABN, binning transformation is used to reduce the cardinality of +* higher cardinality attributes. The prepareData() method in this demo program +* illustrates the preparation of the build data and how we can embed these +* transformations into the model. Model apply and test operations +* automatically apply the embedded transformations. +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a classification model using the ABN algorithm. +* Test Model: +* Classification model performance can be evaluated by computing test +* metrics like accuracy, confusion matrix, lift and ROC. The testModel() or +* computeTestMetrics() method illustrates how to perform the test operation to +* compute various metrics. +* Apply Model: +* Predicting the target attribute values is the prime function of +* classification models. The applyModel() method illustrates how to +* predict the customer response for affinity card program. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines to execute this demo program. +*/ +public class + +dmabdemo + extends Object +{ + // Connection related data members + private static javax.datamining.resource.Connection m_dmeConn; + private static javax.datamining.resource.ConnectionFactory m_dmeConnFactory; + // Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static ClassificationSettingsFactory m_clasFactory; + private static OraABNSettingsFactory m_abnFactory; + private static BuildTaskFactory m_buildFactory; + private static DataSetApplyTaskFactory m_dsApplyFactory; + private static ClassificationTestTaskFactory m_testFactory; + private static ClassificationApplySettingsFactory m_applySettingsFactory; + private static ClassificationTestMetricsTaskFactory m_testMetricsTaskFactory; + private static OraTransformationFactory m_xformFactory; + private static OraTransformationTaskFactory m_xformTaskFactory; + // Global constants + private static DecimalFormat m_df = new DecimalFormat("##.####"); + private static String TAB = " "; + private static String CR = "\n"; + private static String CR_TAB = "\n "; + private static String HORZ_LINE = "----"; + private static String UNDERLINE = + "*************************************"; + private static String RULES_ABN_HEADER = + "* Rules *"; + // Global data members + private static OraBinningTransform m_buildDataXform; + + public static void main(String[] args) + { + try + { + if (args.length != 3) + { + System.out.println("Usage: java dmabdemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + // 1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@" + uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Prepare data + prepareData(); + // 5. Build model - Please see dmnbdemo.java to see how to build a model + // with supplied prior probability. + buildModel(); + // 6. Test model - To compute accuracy and confusion matrix, lift result + // and ROC for the model from an apply output data. + // Please see dnnbdemo.java to see how to test the model + // with a test input data and cost matrix. + computeTestMetrics(); + // 7. Apply model + applyModel(); + //8. Start execution of the transformation task that trigger execution of + // its dependent task(s), here after completion of the transformation task, + // build task executes; after build task test and apply tasks are executed. + // Note that this whole process is executed in the server + m_dmeConn.execute("abnXFormTask_jdm"); + //9. Monitor the task executions of current and its dependent tasks + // and display task output results + monitorTaskExecutionProcess(); + } + catch (Exception anyExp) + { + anyExp.printStackTrace(System.out); + } + finally + { + try + { + // 8. Logout from the Data Mining Engine + m_dmeConn.close(); + } + catch (Exception anyExp1) + { + } // Ignore + } + } + + /** + * Initialize all object factories used in the demo program. + */ + public static void initFactories() + throws JDMException + { + m_pdsFactory = + (PhysicalDataSetFactory) m_dmeConn.getFactory("javax.datamining.data.PhysicalDataSet"); + m_paFactory = + (PhysicalAttributeFactory) m_dmeConn.getFactory("javax.datamining.data.PhysicalAttribute"); + m_clasFactory = + (ClassificationSettingsFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.ClassificationSettings"); + m_abnFactory = + (OraABNSettingsFactory) m_dmeConn.getFactory("oracle.dmt.jdm.algorithm.abn.OraABNSettings"); + m_buildFactory = + (BuildTaskFactory) m_dmeConn.getFactory("javax.datamining.task.BuildTask"); + m_dsApplyFactory = + (DataSetApplyTaskFactory) m_dmeConn.getFactory("javax.datamining.task.apply.DataSetApplyTask"); + m_testFactory = + (ClassificationTestTaskFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.ClassificationTestTask"); + m_applySettingsFactory = + (ClassificationApplySettingsFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.ClassificationApplySettings"); + m_testMetricsTaskFactory = + (ClassificationTestMetricsTaskFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.ClassificationTestMetricsTask"); + m_xformFactory = + (OraTransformationFactory) m_dmeConn.getFactory("oracle.dmt.jdm.transform.OraTransformation"); + m_xformTaskFactory = + (OraTransformationTaskFactory) m_dmeConn.getFactory("oracle.dmt.jdm.task.OraTransformationTask"); + } + + /** + * This method illustrates preparation of the data for build, test, and apply + * operations by using binning transformation. + * + * Here numerical attributes AGE and YRS_RESIDENCE are prepared using + * quantile binning. Categorical attributes COUNTRY_NAME and OCCUPATION + * are prepared using top-n binning. For more details about binning, + * refer to Oracle Data Mining Concepts Guide. + * + * The case id, target attribute, and any attribute with <= 2 distinct values + * should be excluded from the binning process. However, + * we may exclude additional attributes from the binning process to + * demonstrate how to exclude additional attributes from the binning process. + * + * The following table illustrates customer attributes available for building + * the mining model and data characteristics and type of binning used + * for each attribute and number of bins used. + * + * COLUMN_NAME DATA_TYPE DISTINCT EXCLUDED BIN TYPE BIN # + * ------------------ --------- -------- -------- ----------- ----- + * CUST_ID NUMBER 1500 YES + * CUST_GENDER CHAR 2 YES + * AGE NUMBER 66 NO QUANTILE 5 + * CUST_MARITAL_STATUS VARCHAR2 7 YES + * COUNTRY_NAME VARCHAR2 19 NO TOP-N 7 + * CUST_INCOME_LEVEL VARCHAR2 12 YES + * EDUCATION VARCHAR2 16 YES + * OCCUPATION VARCHAR2 15 NO TOP-N 7 + * HOUSEHOLD_SIZE VARCHAR2 6 YES + * YRS_RESIDENCE NUMBER 15 NO QUANTILE 5 + * AFFINITY_CARD NUMBER 2 YES + * BULK_PACK_DISKETTES NUMBER 2 YES + * FLAT_PANEL_MONITOR NUMBER 2 YES + * HOME_THEATER_PACKAGE NUMBER 2 YES + * BOOKKEEPING_APPLICATION NUMBER 2 YES + * PRINTER_SUPPLIES NUMBER 1 YES + * Y_BOX_GAMES NUMBER 2 YES + * OS_DOC_SET_KANJI NUMBER 2 YES + * + * Build data binnning transformation produces numerical and categorical + * bin boundary tables. These tables must be specified for test and apply data + * to bin the data consistent with the build data. + * Following binned tables are created after the execution of this method. + * + * Unprepared Data ---> Prepared(Binned) Data + * --------------------- --------------------------- + * MINING_DATA_BUILD_V ABN_BINNED_DATA_BUILD_JDM + * MINING_DATA_TEST_V ABN_BINNED_DATA_TEST_JDM + * MINING_DATA_APPLY_V ABN_BINNED_DATA_APPLY_JDM + */ + public static void prepareData() + throws JDMException + { + + boolean isOutputAsView = false; + String inputDataURI = null; + String outputDataURI = null; + String categoricalBinTable = null; + String numericalBinTable = null; + OraTransformationTask xformTask = null; + // 1. Prepare build data + isOutputAsView = true; + inputDataURI = "MINING_DATA_BUILD_V"; + outputDataURI = "ABN_PREP_DATA_BUILD_JDM"; + m_buildDataXform = m_xformFactory.createBinningTransform(); + String[] excludeColumnList = + { "CUST_ID", "CUST_GENDER", "CUST_MARITAL_STATUS", "CUST_INCOME_LEVEL", + "EDUCATION", "HOUSEHOLD_SIZE", "AFFINITY_CARD", + "BULK_PACK_DISKETTES", "FLAT_PANEL_MONITOR", "HOME_THEATER_PACKAGE", + "BOOKKEEPING_APPLICATION", "PRINTER_SUPPLIES", "Y_BOX_GAMES", + "OS_DOC_SET_KANJI" }; + m_buildDataXform.setExcludeColumnList(excludeColumnList); + // Categorical binning definition + m_buildDataXform.setNumberOfBinsForCategorical(7); + m_buildDataXform.setCategoricalBinningType(OraCategoricalBinningType.top_n); + // Numerical binning definition + m_buildDataXform.setNumberOfBinsForNumerical(5); + m_buildDataXform.setNumericalBinningType(OraNumericalBinningType.quantile); + //2. Create Transformation sequence + List xformList = + new ArrayList(1); //There is only one xform in this example, so capacity specified as 1 + xformList.add(m_buildDataXform); + OraTransformationSequence xformSeq = + m_xformFactory.createTransformationSequence(inputDataURI, xformList, + outputDataURI); + m_dmeConn.saveObject("abnBuildDataXformSeq_jdm", xformSeq, true); + //3. Create and execute transformation task + xformTask = + m_xformTaskFactory.create("abnBuildDataXformSeq_jdm", false); + saveTask(xformTask, "abnXFormTask_jdm", null); + } + + /** + * This method illustrates how to build a mining model using the + * ABN_BINNED_DATA_BUILD_JDM dataset and classification settings + * with ABN algorithm. + * + * By default, the ABN algorithm uses model type as multi feature. Multi feature + * doesn't produce model details. Here single feature is used to demonstrate + * retrieval of model details. + */ + public static void buildModel() + throws JDMException + { + + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = + m_pdsFactory.create("MINING_DATA_BUILD_V", false); + PhysicalAttribute pa = + m_paFactory.create("CUST_ID", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + buildData.addAttribute(pa); + m_dmeConn.saveObject("abnBuildData_jdm", buildData, true); + // 2. Create & save Classification Settings + // Create ABN algorithm settings + OraABNSettings abnAlgo = m_abnFactory.create(); + abnAlgo.setModelType(OraABNModelType.singleFeature); + // Create ClassificationSettings + ClassificationSettings buildSettings = m_clasFactory.create(); + buildSettings.setAlgorithmSettings(abnAlgo); + buildSettings.setTargetAttributeName("AFFINITY_CARD"); + m_dmeConn.saveObject("abnBuildSettings_jdm", buildSettings, true); + // 3. Create, save & execute Build Task + BuildTask buildTask = //Build data specification + //Mining function settings name + //Mining model name + m_buildFactory.create("abnBuildData_jdm", "abnBuildSettings_jdm", + "abnModel_jdm"); + buildTask.setDescription("abnBuildTask_jdm"); + ((OraBuildTask) buildTask).setTransformationSequenceName("abnBuildDataXformSeq_jdm"); + saveTask(buildTask, "abnBuildTask_jdm", "abnXFormTask_jdm"); + } + + /** + * This method illustrates how to compute test metrics using + * an apply output table that has actual and predicted target values. Here the + * apply operation is done on ABN_BINNED_DATA_TEST_JDM dataset, which creates + * an apply output table with actual and predicted target values. Using + * ClassificationTestMetricsTask test metrics are computed. This produces + * the same test metrics results as ClassificationTestTask. + */ + public static void computeTestMetrics() + throws JDMException + { + // 1. Do the apply on test data to create an apply output table + // Create & save PhysicalDataSpecification + PhysicalDataSet applyData = + m_pdsFactory.create("MINING_DATA_TEST_V", false); + PhysicalAttribute pa = + m_paFactory.create("CUST_ID", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + applyData.addAttribute(pa); + m_dmeConn.saveObject("abnTestApplyData_jdm", applyData, true); + // 2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + HashMap srcDestMap = new HashMap(); + srcDestMap.put("AFFINITY_CARD", "AFFINITY_CARD"); + clasAS.setSourceDestinationMap(srcDestMap); + m_dmeConn.saveObject("abnTestApplySettings_jdm", clasAS, true); + // 3. Create, store & execute apply Task + DataSetApplyTask applyTask = + m_dsApplyFactory.create("abnTestApplyData_jdm", "abnModel_jdm", + "abnTestApplySettings_jdm", + "ABN_TEST_APPLY_OUTPUT_JDM"); + saveTask(applyTask, "abnTestApplyTask_jdm", "abnBuildTask_jdm"); + // 4. Create & save PhysicalDataSpecification + PhysicalDataSet applyOutputData = + m_pdsFactory.create("ABN_TEST_APPLY_OUTPUT_JDM", false); + applyOutputData.addAttribute(pa); + m_dmeConn.saveObject("abnTestApplyOutput_jdm", applyOutputData, true); + // 5. Create a ClassificationTestMetricsTask + ClassificationTestMetricsTask testMetricsTask = + // apply output data used as input + // actual target column + // predicted target column + // test metrics result name + m_testMetricsTaskFactory.create("abnTestApplyOutput_jdm", + "AFFINITY_CARD", "PREDICTION", + "abnComputeTestMetrics_jdm"); // enable confusion matrix computation + testMetricsTask.computeMetric(ClassificationTestMetricOption.confusionMatrix, + true); // enable lift computation + testMetricsTask.computeMetric(ClassificationTestMetricOption.lift, + true); // enable ROC computation + testMetricsTask.computeMetric(ClassificationTestMetricOption.receiverOperatingCharacteristics, + true); + testMetricsTask.setPositiveTargetValue(new Integer(1)); + testMetricsTask.setNumberOfLiftQuantiles(10); + testMetricsTask.setPredictionRankingAttrName("PROBABILITY"); + // Save task and specify the parent task name + saveTask(testMetricsTask, "abnTestMetricsTask_jdm", + "abnTestApplyTask_jdm"); + } + + /** + * This method illustrates how to apply the mining model on the + * ABN_BINNED_DATA_APPLY_JDM dataset to predict customer + * response. After completion of the task, the apply output table with the + * predicted results is created at the user-specified location. + */ + public static void applyModel() + throws JDMException + { + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = + m_pdsFactory.create("MINING_DATA_APPLY_V", false); + PhysicalAttribute pa = + m_paFactory.create("CUST_ID", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + applyData.addAttribute(pa); + m_dmeConn.saveObject("abnApplyData_jdm", applyData, true); + // 2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + m_dmeConn.saveObject("abnApplySettings_jdm", clasAS, true); + // 3. Create, store & execute apply Task + DataSetApplyTask applyTask = + m_dsApplyFactory.create("abnApplyData_jdm", "abnModel_jdm", + "abnApplySettings_jdm", + "ABN_APPLY_OUTPUT_JDM"); + saveTask(applyTask, "abnApplyTask_jdm", "abnBuildTask_jdm"); + } + + /** + * This method saves the given task with the specified task name and task + * dependency (parent task) in the DME. + * + * @param taskObj task object + * @param taskName name of the task + * @param parentTaskName name of the parent task + * + * @return boolean returns true when the task is successful + * @exception JDMException if task execution failed + */ + public static void saveTask(Task taskObj, String taskName, + String parentTaskName) + throws JDMException + { + if (parentTaskName != null) + ((OraTask) taskObj).addDependency(parentTaskName); //Since OJDM 11.1 + ((OraTask) taskObj).overwriteOutput(true); //Since OJDM 11.1 + m_dmeConn.saveObject(taskName, taskObj, true); + } + + /** + * This method monitor task execution initiated by the first task + * in the sequence of dependent tasks. In addition, this method displays + * task output results (if any). + * @throws JDMException + */ + public static void monitorTaskExecutionProcess() + throws JDMException + { + //Data trasformation task + //1. Wait for the completion of the task + System.out.println("---------------------------------------------------"); + System.out.println("--- Prepare Data ---"); + System.out.println("---------------------------------------------------"); + System.out.print("Waiting for the completion of abnXFormTask_jdm. "); + ExecutionStatus xformTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("abnXFormTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(xformTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + //BuildTask + System.out.println("---------------------------------------------------"); + System.out.println("--- Build Model ---"); + System.out.println("---------------------------------------------------"); + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of abnBuildTask_jdm. "); + ExecutionStatus buildTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("abnBuildTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(buildTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + // 3. Restore the model from the data mining server + ClassificationModel model = + (ClassificationModel) m_dmeConn.retrieveObject("abnModel_jdm", + NamedObject.model); + // 4. Explore the details of the restored model + // Display model build settings + ClassificationSettings retrievedBuildSettings = + (ClassificationSettings) model.getBuildSettings(); + if (retrievedBuildSettings == null) + System.out.println("Failure to restore build settings."); + else + displayBuildSettings(retrievedBuildSettings, + "abnBuildSettings_jdm"); + // Display model details + OraABNModelDetail abnModelDetails = + (OraABNModelDetail) model.getModelDetail(); + displayABNModelDetails(abnModelDetails); + + // Display model transformations that are embedded in this example + OraExpressionTransform exprXforms = + ((OraModel) model).getModelTransformations(); + displayModelTransforms(exprXforms); + + System.out.println("---------------------------------------------------"); + System.out.println("--- Test Model - using apply output table ---"); + System.out.println("---------------------------------------------------"); + + //If model build is successful, then do testData ApplyTask + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of abnTestApplyTask_jdm. "); + ExecutionStatus testApplyTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("abnTestApplyTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(testApplyTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + //If testdata apply is successful, then wait for its child test metrics tasks + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of abnTestMetricsTask_jdm. "); + ExecutionStatus testTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("abnTestMetricsTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(testTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + // Restore & display test metrics + ClassificationTestMetrics testMetrics = + (ClassificationTestMetrics) m_dmeConn.retrieveObject("abnComputeTestMetrics_jdm", + NamedObject.testMetrics); + // Display classification test metrics + displayTestMetricDetails(testMetrics); + } + else + { + System.out.println("It is at state:" + + testTaskCompletionStatus.getState().name() + + ((testTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + testTaskCompletionStatus.getDescription())); + } + + } + else + { + System.out.println("It is at state:" + + testApplyTaskCompletionStatus.getState().name() + + ((testApplyTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + testApplyTaskCompletionStatus.getDescription())); + } + //ApplyTask(s) + //Waiting for apply task to complete + System.out.println("---------------------------------------------------"); + System.out.println("--- Apply Model ---"); + System.out.println("---------------------------------------------------"); + + ExecutionStatus applyTaskStatus = + m_dmeConn.getLastExecutionHandle("abnApplyTask_jdm").waitForCompletion(Integer.MAX_VALUE); + if (ExecutionState.success.equals(applyTaskStatus.getState())) + { + // Display apply result -- Note that APPLY results do not need to be + // reverse transformed, as done in the case of model details. This is + // because class values of a classification target were not (required to + // be) binned or normalized. + displayTable("ABN_APPLY_OUTPUT_JDM", "where ROWNUM < 11", + "order by CUST_ID"); + } + else + { + System.out.println("abnApplyTask_jdm is at state:" + + applyTaskStatus.getState().name() + + ((applyTaskStatus.getDescription() == null)? + "": + "State Description:" + applyTaskStatus.getDescription())); + } + } + else + { + System.out.println("It is at state:" + + buildTaskCompletionStatus.getState().name() + + ((buildTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + buildTaskCompletionStatus.getDescription())); + } + } + else + { + System.out.println("It is at state:" + + xformTaskCompletionStatus.getState().name() + + ((xformTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + xformTaskCompletionStatus.getDescription())); + } + } + + private static void displayBuildSettings(ClassificationSettings clasSettings, + String buildSettingsName) + { + System.out.println("BuildSettings Details from the " + + buildSettingsName + " table:"); + displayTable(buildSettingsName, "", "order by SETTING_NAME"); + System.out.println("BuildSettings Details from the " + + buildSettingsName + + " model build settings object:"); + String objName = clasSettings.getName(); + if (objName != null) + System.out.println("Name = " + objName); + String objDescription = clasSettings.getDescription(); + if (objDescription != null) + System.out.println("Description = " + objDescription); + java.util.Date creationDate = clasSettings.getCreationDate(); + String creator = clasSettings.getCreatorInfo(); + String targetAttrName = clasSettings.getTargetAttributeName(); + System.out.println("Target attribute name = " + targetAttrName); + AlgorithmSettings algoSettings = clasSettings.getAlgorithmSettings(); + if (algoSettings == null) + System.out.println("Failure: clasSettings.getAlgorithmSettings() returns null"); + MiningAlgorithm algo = algoSettings.getMiningAlgorithm(); + if (algo == null) + System.out.println("Failure: algoSettings.getMiningAlgorithm() returns null"); + System.out.println("Algorithm Name: " + algo.name()); + MiningFunction function = clasSettings.getMiningFunction(); + if (function == null) + System.out.println("Failure: clasSettings.getMiningFunction() returns null"); + System.out.println("Function Name: " + function.name()); + try + { + Map map = clasSettings.getPriorProbabilitiesMap(targetAttrName); + if (map != null) + System.out.println("Priors Map: " + map.toString()); + } + catch (Exception jdmExp) + { + System.out.println("Failure: clasSettings.getPriorProbabilitiesMap(targetAttrName)throws exception"); + jdmExp.printStackTrace(); + } + } + + /** + * This method displayes ABN model signature. + */ + public static void displayModelSignature(Model model) + throws JDMException + { + String modelName = model.getName(); + System.out.println("Model Name: " + modelName); + ModelSignature modelSignature = model.getSignature(); + System.out.println("ModelSignature Deatils: ( Attribute Name, Attribute Type )"); + MessageFormat mfSign = + new MessageFormat(" ( {0}, {1} )"); + String[] vals = new String[3]; + Collection sortedSet = modelSignature.getAttributes(); + Iterator attrIterator = sortedSet.iterator(); + while (attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute) attrIterator.next(); + vals[0] = attr.getName(); + vals[1] = attr.getDataType().name(); + System.out.println(mfSign.format(vals)); + } + } + + /** + * This method displayes ABN model details. + */ + public static void displayABNModelDetails(OraABNModelDetail abnModelDetails) + throws JDMException + { + System.out.println("ABN model details:"); + // Display all model rules + Collection vRules = abnModelDetails.getRules(); + if (vRules != null && vRules.isEmpty() == false) + { + Rule[] rules = (Rule[]) vRules.toArray(new Rule[vRules.size()]); + System.out.println(CR + CR + UNDERLINE); + System.out.println(RULES_ABN_HEADER); + System.out.println(UNDERLINE); + + for (int rl = 0; rl < rules.length; rl++) + { + printRuleDetails(rules[rl], 0); // printRuleDetails + } + } + System.out.println(CR + UNDERLINE + CR); + } + + /** + * This embedded transformations + */ + public static void displayModelTransforms(OraExpressionTransform exprXforms) + throws JDMException + { + System.out.println("ABN model transforms:"); + //Get per attribute name and expression element map object + Map exprMap = exprXforms.getAttributeExpressionMap(); + + OraExpressionTransform.OraExpressionElement exprElement = + (OraExpressionTransform.OraExpressionElement) exprMap.get("AGE"); + System.out.println("Attribute Name: AGE"); + System.out.println("Expression: " + exprElement.getExpression()); + System.out.println("Inverse Expression: " + exprElement.getInverseExpression()); + + exprElement = + (OraExpressionTransform.OraExpressionElement) exprMap.get("YRS_RESIDENCE"); + System.out.println("Attribute Name: YRS_RESIDENCE"); + System.out.println("Expression: " + exprElement.getExpression()); + System.out.println("Inverse Expression: " + exprElement.getInverseExpression()); + } + + + /** + * Prints rule details + */ + public static void printRuleDetails(Rule rule, int indent) + { + System.out.println(CR_TAB + getIndentation(indent, "Rule Details:") + + CR_TAB + TAB + + getIndentation(indent, "Support: " + m_df.format(rule.getSupport())) + + CR_TAB + TAB + + getIndentation(indent, "Confidence: " + + m_df.format(rule.getConfidence()))); + CompoundPredicate antecedent = + (CompoundPredicate) rule.getAntecedent(); + System.out.println(CR_TAB + TAB + + getIndentation(indent, ("Antecedent: "))); + printAntecedent(antecedent, indent); + CompoundPredicate consequent = + (CompoundPredicate) rule.getConsequent(); + System.out.println(CR_TAB + TAB + + getIndentation(indent, ("Consequent: "))); + printConsequent(consequent, indent); + } + + /** + * Prints antecedent + */ + public static void printAntecedent(CompoundPredicate predicate, + int indent) + { + try + { + SimplePredicate[] sps = + (SimplePredicate[]) predicate.getPredicates(); + if (sps == null) + return; + // Combine predicates by attribute name + Hashtable htNamePredicateMap = new Hashtable(); + for (int i = 0; i < sps.length; i++) + { + StringBuffer simplePredicate = printSimplePredicate(sps[i]); + String attrName = sps[i].getAttributeName(); + StringBuffer attrTotalPredicate = + (StringBuffer) htNamePredicateMap.get(attrName); + if (attrTotalPredicate == null) + htNamePredicateMap.put(attrName, simplePredicate); + else + { + attrTotalPredicate.append(" AND " + simplePredicate); + } + } + Enumeration en = htNamePredicateMap.keys(); + while (en.hasMoreElements()) + { + String name = (String) en.nextElement(); + StringBuffer sb = (StringBuffer) htNamePredicateMap.get(name); + System.out.println(getIndentation(indent, + (TAB + TAB + TAB + sb.toString()))); + } + } + catch (Exception e) + { + System.out.println("Error printing Antecedant"); + } + } + + /** + * Prints consequent + */ + public static void printConsequent(CompoundPredicate predicate, + int indent) + { + try + { + SimplePredicate[] sps = + (SimplePredicate[]) predicate.getPredicates(); + if (sps == null) + return; + for (int i = 0; i < sps.length; i++) + { + StringBuffer simplePredicate = printSimplePredicate(sps[i]); + if (i < sps.length - 1) + simplePredicate.append(" AND "); + System.out.println(getIndentation(indent, + TAB + TAB + TAB + simplePredicate.toString())); + } + } + catch (Exception e) + { + System.out.println("Error printing Consequent"); + } + } + + /** + * Prints simple predicate + */ + public static StringBuffer printSimplePredicate(SimplePredicate predicate) + throws JDMException + { + StringBuffer sb = new StringBuffer(); + if (predicate.isNumericalValue()) + { + //((OraSimplePredicate)predicate).getComparisonOperatorValue() + " " + + sb.append(predicate.getAttributeName() + " " + + ((OraSimplePredicate) predicate).getComparisonOperator().name() + + " " + predicate.getNumericalValue()); + } + else + { + //((OraSimplePredicate)predicate).getComparisonOperatorValue() + " " + sb = + new StringBuffer(predicate.getAttributeName() + " " + ((OraSimplePredicate) predicate).getComparisonOperator().name() + + " "); + Object[] inValues = predicate.getCategoryValues(); + if (inValues != null) + { + for (int i = 0; i < inValues.length; i++) + { + sb.append(inValues[i]); + if (i != inValues.length - 1) + sb.append(","); + } + } + } + return sb; + } + + /** + * Display classification test metrics object + */ + public static void displayTestMetricDetails(ClassificationTestMetrics testMetrics) + throws JDMException + { + // Retrieve Oracle ABN model test metrics deatils extensions + // Test Metrics Name + System.out.println("Test Metrics Name = " + testMetrics.getName()); + // Model Name + System.out.println("Model Name = " + testMetrics.getModelName()); + // Test Data Name + System.out.println("Test Data Name = " + + testMetrics.getTestDataName()); + // Accuracy + System.out.println("Accuracy = " + + m_df.format(testMetrics.getAccuracy().doubleValue())); + // Confusion Matrix + ConfusionMatrix confusionMatrix = testMetrics.getConfusionMatrix(); + Collection categories = confusionMatrix.getCategories(); + Iterator xIterator = categories.iterator(); + System.out.println("Confusion Matrix: Accuracy = " + + m_df.format(confusionMatrix.getAccuracy())); + System.out.println("Confusion Matrix: Error = " + + m_df.format(confusionMatrix.getError())); + System.out.println("Confusion Matrix:( Actual, Prection, Value )"); + MessageFormat mf = + new MessageFormat(" ( {0}, {1}, {2} )"); + String[] vals = new String[3]; + while (xIterator.hasNext()) + { + Object actual = xIterator.next(); + vals[0] = actual.toString(); + Iterator yIterator = categories.iterator(); + while (yIterator.hasNext()) + { + Object predicted = yIterator.next(); + vals[1] = predicted.toString(); + long number = + confusionMatrix.getNumberOfPredictions(actual, predicted); + vals[2] = Long.toString(number); + System.out.println(mf.format(vals)); + } + } + // Lift + Lift lift = testMetrics.getLift(); + System.out.println("Lift Details:"); + System.out.println("Lift: Target Attribute Name = " + + lift.getTargetAttributeName()); + System.out.println("Lift: Positive Target Value = " + + lift.getPositiveTargetValue()); + System.out.println("Lift: Total Cases = " + lift.getTotalCases()); + System.out.println("Lift: Total Positive Cases = " + + lift.getTotalPositiveCases()); + int numberOfQuantiles = lift.getNumberOfQuantiles(); + System.out.println("Lift: Number Of Quantiles = " + numberOfQuantiles); + System.out.println("Lift: ( QUANTILE_NUMBER, TOTAL_CASES, QUANTILE_PERCENT_SIZE, POSITIVE_CASES, NEGATIVE_CASES, PROBABILITY_THRESHOLD, LIFT, CUMULATIVE_LIFT, GAIN, CUMULATIVE_GAIN, TARGET_DENSITY, CUMULATIVE_TARGET_DENSITY)"); + MessageFormat mfLift = + new MessageFormat(" ( {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10} )"); + double[] totalCasesPerQuantile = ((OraLift)lift).getCases();//Total cases per quantile + double[] quantilePercentageSize = ((OraLift)lift).getPercentageSize();//Quantile pecentage size + double[] positiveCasesPerQuantile = ((OraLift)lift).getNumberOfPositiveCases();//Positive target cases per quantile + double[] negativeCasesPerQuantile = ((OraLift)lift).getNumberOfNegativeCases();//Negative target cases per quantile + double[] probabilityOrCostThresholdPerQuantile = ((OraLift)lift).getProbabilityOrCostThreshold();//Probability or cost threshold per quantile + double[] liftPerQuantile = ((OraLift)lift).getLift();//Lift values for all quantiles + double[] targetDensityPerQuantile = ((OraLift)lift).getTargetDensity();//Target densities per quantile + + double[] cumulativeLift = ((OraLift)lift).getCumulativeLift(); + double[] cumulativeGain = ((OraLift)lift).getCumulativeGain(); + double[] cumulativeTargetDensity = ((OraLift)lift).getCumulativeTargetDensity(); + + + + String[] messageParams = new String[11]; + + for (int iQuantile = 0; iQuantile < numberOfQuantiles; iQuantile++) + { + //Assign message parameters + messageParams[0] = Integer.toString(iQuantile+1); //QUANTILE_NUMBER + messageParams[1] = m_df.format(totalCasesPerQuantile[iQuantile]); //TOTAL_CASES + messageParams[2] = m_df.format(quantilePercentageSize[iQuantile]);//QUANTILE_PERCENT_SIZE + messageParams[3] = m_df.format(positiveCasesPerQuantile[iQuantile]); //POSITIVE_CASES + messageParams[4] = m_df.format(negativeCasesPerQuantile[iQuantile]); //NEGATIVE_CASES + messageParams[5] = m_df.format(probabilityOrCostThresholdPerQuantile[iQuantile]); //PROBABILITY_THRESHOLD + messageParams[6] = m_df.format(liftPerQuantile[iQuantile]); //LIFT + messageParams[7] = m_df.format(cumulativeLift[iQuantile]); //CUMULATIVE_LIFT + messageParams[8] = m_df.format(cumulativeGain[iQuantile]); //CUMULATIVE_GAIN + messageParams[9] = m_df.format(targetDensityPerQuantile[iQuantile]); //TARGET_DENSITY + messageParams[10] = m_df.format(cumulativeTargetDensity[iQuantile]); //CUMULATIVE_TARGET_DENSITY + System.out.println(mfLift.format(messageParams)); + } + // ROC + ReceiverOperatingCharacterics roc = testMetrics.getROC(); + System.out.println("ROC Details:"); + System.out.println("ROC: Area Under Curve = " + + m_df.format(roc.getAreaUnderCurve())); + int nROCThresh = roc.getNumberOfThresholdCandidates(); + System.out.println("ROC: Number Of Threshold Candidates = " + + nROCThresh); + System.out.println("ROC: ( INDEX, PROBABILITY, TRUE_POSITIVES, FALSE_NEGATIVES, FALSE_POSITIVES, TRUE_NEGATIVES, TRUE_POSITIVE_FRACTION, FALSE_POSITIVE_FRACTION )"); + MessageFormat mfROC = + new MessageFormat(" ( {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7} )"); + String[] rocVals = new String[8]; + for (int iROC = 1; iROC <= nROCThresh; iROC++) + { + rocVals[0] = Integer.toString(iROC); //INDEX + rocVals[1] = + m_df.format(roc.getProbabilityThreshold(iROC)); //PROBABILITY + rocVals[2] = + Long.toString(roc.getPositives(iROC, true)); //TRUE_POSITIVES + rocVals[3] = + Long.toString(roc.getNegatives(iROC, false)); //FALSE_NEGATIVES + rocVals[4] = + Long.toString(roc.getPositives(iROC, false)); //FALSE_POSITIVES + rocVals[5] = + Long.toString(roc.getNegatives(iROC, true)); //TRUE_NEGATIVES + rocVals[6] = + m_df.format(roc.getHitRate(iROC)); //TRUE_POSITIVE_FRACTION + rocVals[7] = + m_df.format(roc.getFalseAlarmRate(iROC)); //FALSE_POSITIVE_FRACTION + System.out.println(mfROC.format(rocVals)); + } + } + + private static String getIndentation(int indent, String sText) + { + StringBuffer sbIndent = new StringBuffer(TAB); + for (int in = 0; in < indent; in++) + sbIndent.append(TAB); + StringBuffer outPut = new StringBuffer(sbIndent.toString()); + outPut.append(sText); + return outPut.toString(); + } + + private static void displayTable(String tableName, String whereCause, + String orderByColumn) + { + StringBuffer emptyCol = new StringBuffer(" "); + java.sql.Connection dbConn = + ((OraConnection) m_dmeConn).getDatabaseConnection(); + PreparedStatement pStmt = null; + ResultSet rs = null; + try + { + pStmt = + dbConn.prepareStatement("SELECT * FROM " + tableName + " " + whereCause + + " " + orderByColumn); + rs = pStmt.executeQuery(); + ResultSetMetaData rsMeta = rs.getMetaData(); + int colCount = rsMeta.getColumnCount(); + StringBuffer header = new StringBuffer(); + System.out.println("Table : " + tableName); + // Build table header + for (int iCol = 1; iCol <= colCount; iCol++) + { + String colName = rsMeta.getColumnName(iCol); + header.append(emptyCol.replace(0, colName.length(), colName)); + emptyCol = new StringBuffer(" "); + } + System.out.println(header.toString()); + // Write table data + while (rs.next()) + { + StringBuffer rowContent = new StringBuffer(); + for (int iCol = 1; iCol <= colCount; iCol++) + { + int sqlType = rsMeta.getColumnType(iCol); + Object obj = rs.getObject(iCol); + String colContent = null; + + if (obj instanceof java.lang.Number) + { + try + { + BigDecimal bd = (BigDecimal) obj; + if (bd.scale() > 5) + { + colContent = m_df.format(obj); + } + else + { + colContent = bd.toString(); + } + } + catch (Exception anyExp) + { + colContent = m_df.format(obj); + } + } + else + { + if (obj == null) + colContent = "NULL"; + else + colContent = obj.toString(); + } + rowContent.append(" " + + emptyCol.replace(0, colContent.length(), colContent)); + emptyCol = new StringBuffer(" "); + } + System.out.println(rowContent.toString()); + } + } + catch (Exception anySqlExp) + { + anySqlExp.printStackTrace(); + } // Ignore + } + + private static void clean() + { + java.sql.Connection dbConn = + ((OraConnection) m_dmeConn).getDatabaseConnection(); + Statement stmt = null; + // Drop the model + try + { + m_dmeConn.removeObject("abnModel_jdm", NamedObject.model); + } + catch (JDMException jdmExp) + { + } + } +} diff --git a/dmabdemo.sql b/dmabdemo.sql new file mode 100644 index 0000000..310be10 --- /dev/null +++ b/dmabdemo.sql @@ -0,0 +1,712 @@ +Rem +Rem $Header: dmabdemo.sql 15-jun-2007.18:15:24 ramkrish Exp $ +Rem +Rem dmabdemo.sql +Rem +Rem Copyright (c) 2003, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmabdemo.sql - Sample program for DBMS_DATA_MINING package. +Rem +Rem DESCRIPTION +Rem This script creates a classification model +Rem using the ABN algorithm and data in the +Rem SH (Sales History) schema in the RDBMS. +Rem +Rem This sample demonstrates the backward compatibility of +Rem procedures for computing test metrics, apply, and ranked apply. +Rem Other samples demonstrate the use of the new SQL functions +Rem for data mining in Oracle10gR2. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ramkrish 06/14/07 - remove commit after settings +Rem ramkrish 10/25/07 - replace deprecated get_model calls with catalog +Rem queries +Rem ktaylor 07/11/05 - minor editing of comments +Rem jcjeon 01/17/05 - add column format +Rem ramkrish 12/20/04 - add ORDER BY in missing values cursor +Rem jyarmus 11/01/04 - modify binning, ADD settings examples AS comments +Rem ramkrish 10/01/04 - add data analysis and comments/cleanup +Rem ramkrish 10/02/03 - Creation + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET linesize 100 +SET echo ON + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM +----------------------------------------------------------------------- +-- Given demographic data about a set of customers, predict the +-- customer response to an affinity card program using a classifier +-- based on ABN algorithm. + +----------------------------------------------------------------------- +-- SET UP AND ANALYZE THE DATA +----------------------------------------------------------------------- + +-- The data for this sample is composed from base tables in SH Schema +-- (See Sample Schema Documentation) and presented through these views: +-- mining_data_build_v (build data) +-- mining_data_test_v (test data) +-- mining_data_apply_v (apply data) +-- (See dmsh.sql for view definitions). + +----------- +-- ANALYSIS +----------- +-- For classification using ABN, perform the following on mining data. +-- +-- 1. Missing Value Treatment for Predictors +-- +-- See dmsvcdem.sql for a definition of missing values, and the +-- steps to be taken for missing value imputation. +-- +-- ABN/NB treats NULL values for attributes as missing at random. +-- +-- 2. Outlier Treatment for Predictors for Build data +-- +-- See dmsvcdem.sql for a discussion on outlier treatment. +-- +-- ABN/NB (and Bayesian algorithms in general) require that high cardinality +-- data be binned. Studies have shown that equi-width binning into 10 bins +-- of data with no outliers provides good model performance. So if equiwidth +-- binning is considered, then outliers in the data have to be handled. +-- Not doing this would affect the bin boundaries such that data values +-- would tend to concentrate on too few bins. However .... +-- +-- 3. Binning high cardinality data +-- You can skip step 2 if the data is binned using quantile binning +-- (10 bins, for starters). ODM recommends quantile binning for NB +-- and ABN. +-- +-- eliminate old tables +BEGIN + EXECUTE IMMEDIATE 'DROP TABLE mining_data_build_hist'; +EXCEPTION WHEN OTHERS THEN + NULL; +END; +/ + +-- Gather histogram and cardinality for attributes as preparation for binning +-- +-- create table for column histogram +set echo off +CREATE GLOBAL TEMPORARY TABLE mining_data_build_hist ( + cname VARCHAR2(30), cnval NUMBER, csval VARCHAR2(30), vcnt NUMBER); + +DECLARE + cname VARCHAR2(30); + ctype VARCHAR2(30); + vstmt VARCHAR2(4000); + ccnt NUMBER; + CURSOR c1 IS + SELECT column_name,data_type + FROM all_tab_columns + WHERE table_name='MINING_DATA_BUILD_V' + ORDER BY column_name; +BEGIN + OPEN c1; + LOOP + FETCH c1 INTO cname,ctype; + EXIT WHEN c1%NOTFOUND; + + -- find cardinality + vstmt := 'SELECT COUNT(DISTINCT ' || cname || ') FROM mining_data_build_v'; + EXECUTE IMMEDIATE vstmt INTO ccnt; + DBMS_OUTPUT.PUT_LINE('Column: ' || cname || ', Card: ' || ccnt); + + -- find column histogram (skip case id) and store it in a temp table + IF (cname != 'CUST_ID') THEN + IF (ctype = 'NUMBER') THEN -- num column histogram + vstmt := + 'INSERT INTO mining_data_build_hist (cname, cnval, vcnt) ' || + 'SELECT ' || '''' || cname || '''' || ',' || cname || ',count(*) ' || + 'FROM mining_data_build_v GROUP BY ' || cname; + ELSIF (ctype = 'VARCHAR2') THEN -- str column histogram + vstmt := + 'INSERT INTO mining_data_build_hist (cname, csval, vcnt) ' || + 'SELECT ' || '''' || cname || '''' || ',' || cname || ',count(*) ' || + 'FROM mining_data_build_v GROUP BY ' || cname; + END IF; + EXECUTE IMMEDIATE vstmt; + END IF; + END LOOP; +END; +/ +set echo on + +-- Inspect COLUMN HISTOGRAMS +-- +column cname format a25; +column cval format a45; +SELECT cname, NVL(TO_CHAR(cnval), csval) cval, vcnt + FROM mining_data_build_hist +ORDER BY 1,2,3; + +-- . The target attribute is AFFINITY_CARD. CUST_ID is the case identifier. +-- The rest of the attributes are predictors. +-- . OCCUPATION has 15 distinct values, we decide to quantile bin it +-- into 7+1 bins. +-- . AGE has 66 distinct values in the range 17-80; we decide to quantile +-- bin it into 5+1 bins. +-- . All other attributes are categorical with binary values, so they +-- are not binned. + +----------------------------------------------------------------------- +-- BUILD THE MODEL +----------------------------------------------------------------------- + +-- Cleanup build data preparation objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE abn_sh_sample_num'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE abn_sh_sample_cat'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW abn_sh_sample_build_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW abn_sh_sample_build_cat'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +-- Cleanup old model with same name for repeat runs +BEGIN DBMS_DATA_MINING.DROP_MODEL('ABN_SH_Clas_sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-------------------------------- +-- PREPARE BUILD (TRAINING) DATA +-- +-- 1. Missing Value treatment for all Predictors +-- Skipped - see dmnbdemo.sql +-- +-- 2. Outlier Treatment +-- Skipped - due to choice of quantile binning +-- +-- 3. Binning +-- +BEGIN + -- Bin categorical attributes: OCCUPATION + DBMS_DATA_MINING_TRANSFORM.CREATE_BIN_CAT ( + bin_table_name => 'abn_sh_sample_cat'); + + DBMS_DATA_MINING_TRANSFORM.INSERT_BIN_CAT_FREQ ( + bin_table_name => 'abn_sh_sample_cat', + data_table_name => 'mining_data_build_v', + bin_num => 7, + exclude_list => DBMS_DATA_MINING_TRANSFORM.COLUMN_LIST ( + 'cust_gender', + 'cust_marital_status', + 'cust_income_level', + 'education', + 'household_size') + ); + + -- Bin numerical attributes: AGE + DBMS_DATA_MINING_TRANSFORM.CREATE_BIN_NUM ( + bin_table_name => 'abn_sh_sample_num'); + + DBMS_DATA_MINING_TRANSFORM.INSERT_BIN_NUM_QTILE ( + bin_table_name => 'abn_sh_sample_num', + data_table_name => 'mining_data_build_v', + bin_num => 5, + exclude_list => DBMS_DATA_MINING_TRANSFORM.COLUMN_LIST ( + 'affinity_card', + 'bookkeeping_application', + 'bulk_pack_diskettes', + 'cust_id', + 'flat_panel_monitor', + 'home_theater_package', + 'os_doc_set_kanji', + 'printer_supplies', + 'y_box_games') + ); + + -- Create the transformed view + -- Execute the first transformation (categorical binning) + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_CAT ( + bin_table_name => 'abn_sh_sample_cat', + data_table_name => 'mining_data_build_v', + xform_view_name => 'abn_sh_sample_build_cat'); + + -- Provide the result (abn_sh_sample_build_cat) + -- to the next transformation (numerical binning) + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_NUM ( + bin_table_name => 'abn_sh_sample_num', + data_table_name => 'abn_sh_sample_build_cat', + xform_view_name => 'abn_sh_sample_build_prepared'); +END; +/ + +-- BUILD DATA PREPARATION OBJECTS: +-- ------------------------------ +-- 1. Categorical Bin Table: abn_sh_sample_cat +-- 2. Numerical Bin Table: abn_sh_sample_num +-- 3. Input (view) to CREATE_MODEL: abn_sh_sample_build_prepared + +------------------- +-- SPECIFY SETTINGS +-- +-- Cleanup old settings table for repeat runs +-- +BEGIN EXECUTE IMMEDIATE 'DROP TABLE abn_sh_sample_settings'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- CREATE AND POPULATE A PRIORS TABLE +-- +-- See dmnbdemo.sql - Classification using NB algorithm - for an example. + +-- NB is the default classifier. Override the default to ABN. +-- The default ABN model type is multi_feature. Override this +-- to single feature ABN (to demonstrate model details, since +-- get_model_details_abn() provides details only of single +-- feature ABN models. See Concepts Guide for distinction between +-- these models). +-- +-- CREATE AND POPULATE A SETTINGS TABLE +-- +set echo off +CREATE TABLE abn_sh_sample_settings ( + setting_name VARCHAR2(30), + setting_value VARCHAR2(30)); +set echo on + +BEGIN + -- Populate settings table + INSERT INTO abn_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.algo_name,dbms_data_mining.algo_adaptive_bayes_network); + INSERT INTO abn_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.abns_model_type,dbms_data_mining.abns_single_feature); + + -- Examples of other possible overrides are: + -- (dbms_data_mining.abns_max_build_minutes,10); + -- (dbms_data_mining.abns_max_nb_predictors,19); + -- (dbms_data_mining.abns_max_predictors,34); + -- (dbms_data_mining.abns_model_type, dbms_data_mining.abns_multi_feature); + -- (dbms_data_mining.abns_model_type, dbms_data_mining.abns_naive_bayes); +END; +/ + +--------------------- +-- CREATE A NEW MODEL +-- +-- Build a new ABN model +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'ABN_SH_Clas_sample', + mining_function => dbms_data_mining.classification, + data_table_name => 'abn_sh_sample_build_prepared', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + settings_table_name => 'abn_sh_sample_settings'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30 +column setting_value format a30 +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'ABN_SH_CLAS_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +column attribute_name format a40 +column attribute_type format a20 +SELECT attribute_name, attribute_type + FROM user_mining_model_attributes + WHERE model_name = 'ABN_SH_CLAS_SAMPLE' +ORDER BY attribute_name; + +------------------------ +-- DISPLAY MODEL DETAILS +-- +-- If the build data is prepared (as in this example), then the model +-- contains values of prepared data. The query shown below +-- reverse-transforms the model contents to be as close to the original +-- values as possible, based on the build data preparation objects. +-- Reporting the exact original value is impossible since the input +-- build data has already undergone some transformations (binning/ +-- normalization etc.) +-- +-- The SQL query presented below does the following. +-- 1. Use the bin boundary tables to create labels +-- 2. Replace attribute values with labels +-- 3. For numeric bins, the labels are "[/(lower_boundary,upper_boundary]/)" +-- 4. For categorical bins, label matches the value it represents +-- Note that this method of categorical label representation +-- will only work for cases where one value corresponds to one bin. +-- Target was not binned, hence we don't unbin the target. +-- +-- You can replace the model name in the query with your own, +-- and also adapt the query to accomodate other transforms. +-- +SET heading OFF +WITH +mod_dtls AS ( +SELECT * + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_ABN('abn_sh_clas_sample')) +), +bin_labels AS ( +SELECT col, bin, (DECODE(bin,'1','[','(') || lv || ',' || val || ']') label + FROM (SELECT col, + bin, + LAST_VALUE(val) OVER ( + PARTITION BY col ORDER BY val + ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) lv, + val + FROM abn_sh_sample_num) +UNION ALL +SELECT col, bin, val label + FROM abn_sh_sample_cat +), +mod_ante AS ( +SELECT R.rule_id, A.attribute_name Aa, A.conditional_operator Ac, + NVL(L.label, NVL(A.attribute_str_value,A.attribute_num_value)) + antecedent, + A.attribute_support antecedent_support, + A.attribute_confidence antecedent_confidence + FROM mod_dtls R, + TABLE(R.antecedent) A, + bin_labels L + WHERE A.attribute_name = L.col (+) AND + (NVL(A.attribute_str_value,A.attribute_num_value) = L.bin(+)) +), +mod_cons AS ( +SELECT R.rule_id, C.attribute_name Ca, C.conditional_operator Cc, + NVL(L.label, NVL(C.attribute_str_value,C.attribute_num_value)) + consequent, + C.attribute_support consequent_support, + C.attribute_confidence consequent_confidence + FROM mod_dtls R, + TABLE(R.consequent) C, + bin_labels L + WHERE C.attribute_name = L.col (+) AND + (NVL(C.attribute_str_value,C.attribute_num_value) = L.bin(+)) +), +model_details AS ( +SELECT R.rule_support, R.rule_id, + ante.Aa, ante.Ac, ante.antecedent, ante.antecedent_support, + ROUND(ante.antecedent_confidence,4) antecedent_confidence, + cons.Ca, cons.Cc, cons.consequent, cons.consequent_support, + ROUND(cons.consequent_confidence, 4) consequent_confidence + FROM mod_dtls R, + mod_ante ante, + mod_cons cons + WHERE R.rule_id = ante.rule_id AND ante.rule_id = cons.rule_id +ORDER BY R.rule_support DESC, + consequent_confidence DESC, cons.Ca, cons.consequent, + antecedent_confidence DESC, ante.Aa, ante.antecedent +) +SELECT 'Rule Support: ' || ROUND(rule_support, 4), +-- ' Rule Id: ' || rule_id , + ' Antecedent attribute: ' || Aa || ' ' || Ac || ' ' || antecedent, + ' Consequent attribute: ' || Ca || ' ' || Cc || ' ' || consequent, + ' Antecedent support: ' || antecedent_support, + ' Antecedent confidence: ' || antecedent_confidence, + ' Consequent support: ' || consequent_support, + ' Consequent confidence: ' || consequent_confidence + FROM model_details + WHERE ROWNUM < 21; + +----------------------------------------------------------------------- +-- TEST THE MODEL +----------------------------------------------------------------------- + +-- Cleanup test data preparation objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP VIEW abn_sh_sample_test_targets'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW abn_sh_sample_test_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW abn_sh_sample_test_cat'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-------------------- +-- PREPARE TEST DATA +-- +-- If the data for model creation has been prepared, then the data used +-- for testing the model must be prepared to the same scale in order to +-- obtain meaningful results. +-- +-- 1. Missing value treatment - see dmsvcdem.sql for example of what +-- needs to be done with Test and Apply data input. +-- +-- 2. Outlier treatment and +-- 3. Binning +-- Quantile binning handles both the outlier treatment and binning in this case. +-- Transform the test data mining_test_v, using the transformation tables +-- generated during the Build data preparation, to generate a view representing +-- prepared test data. +-- +-- If this model is tested in a different schema or instance, the +-- data preparation objects generated in the CREATE step must also +-- be made available in the target schema/instance. So you must export +-- those objects (i.e. the num and cat bin tables and views) along with +-- the model to the target user schema. +-- +BEGIN + -- Execute the first transform effected on training data + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_CAT ( + bin_table_name => 'abn_sh_sample_cat', + data_table_name => 'mining_data_test_v', + xform_view_name => 'abn_sh_sample_test_cat'); + + -- Provide the result to the next transform effected on training data + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_NUM ( + bin_table_name => 'abn_sh_sample_num', + data_table_name => 'abn_sh_sample_test_cat', + xform_view_name => 'abn_sh_sample_test_prepared'); +END; +/ + +-- Cleanup test result objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE abn_sh_sample_test_apply'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE abn_sh_sample_confusion_matrix'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE abn_sh_sample_lift'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE abn_sh_sample_roc'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +--------------------------------- +-- SPECIFY COST MATRIX (OPTIONAL) +-- +-- (See dmsvcdem.sql - SVM Classification - for example) +-- + +------------------------------------ +-- COMPUTE METRICS TO TEST THE MODEL +-- +-- The COMPUTE interfaces that provide the test results require two +-- data inputs: +-- 1. A table or view of targets - i.e. one that provides only the +-- case identifier and target columns of your test data. +-- 2. The table with the results of an APPLY operation on test data. +-- + +-- CREATE TEST TARGETS VIEW +-- +CREATE VIEW abn_sh_sample_test_targets AS +SELECT cust_id, affinity_card + FROM abn_sh_sample_test_prepared; + +-- APPLY MODEL ON TEST DATA +-- +BEGIN + DBMS_DATA_MINING.APPLY( + model_name => 'ABN_SH_Clas_sample', + data_table_name => 'abn_sh_sample_test_prepared', + case_id_column_name => 'cust_id', + result_table_name => 'abn_sh_sample_test_apply'); +END; +/ + +-- COMPUTE TEST METRICS +-- +DECLARE + v_accuracy NUMBER; + v_area_under_curve NUMBER; +BEGIN + DBMS_DATA_MINING.COMPUTE_CONFUSION_MATRIX ( + accuracy => v_accuracy, + apply_result_table_name => 'abn_sh_sample_test_apply', + target_table_name => 'abn_sh_sample_test_targets', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + confusion_matrix_table_name => 'abn_sh_sample_confusion_matrix', + score_column_name => 'PREDICTION', + score_criterion_column_name => 'PROBABILITY'); + DBMS_OUTPUT.PUT_LINE('**** MODEL ACCURACY ****: ' || ROUND(v_accuracy, 4)); + + DBMS_DATA_MINING.COMPUTE_LIFT ( + apply_result_table_name => 'abn_sh_sample_test_apply', + target_table_name => 'abn_sh_sample_test_targets', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + lift_table_name => 'abn_sh_sample_lift', + positive_target_value => '1', + num_quantiles => '10'); + + DBMS_DATA_MINING.COMPUTE_ROC ( + roc_area_under_curve => v_area_under_curve, + apply_result_table_name => 'abn_sh_sample_test_apply', + target_table_name => 'abn_sh_sample_test_targets', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + roc_table_name => 'abn_sh_sample_roc', + positive_target_value => '1', + score_column_name => 'PREDICTION', + score_criterion_column_name => 'PROBABILITY'); + DBMS_OUTPUT.PUT_LINE('**** AREA UNDER ROC CURVE ****: ' || v_area_under_curve ); +END; +/ + +-- TEST RESULT OBJECTS: +-- ------------------- +-- 1. Confusion matrix Table: abn_sh_sample_confusion_matrix +-- 2. Lift Table: abn_sh_sample_lift +-- 3. ROC Table: abn_sh_sample_roc +-- + +-- +-- DISPLAY CONFUSION MATRIX +-- +-- NOTE: Cells with count 0 are not represented in the table +-- +SET heading ON +column predicted format a20; +SELECT actual_target_value actual, + to_char(predicted_target_value) predicted, + value as count + FROM abn_sh_sample_confusion_matrix +ORDER BY actual_target_value,predicted_target_value; + +-- DISPLAY LIFT RESULTS +-- +-- Uncomment the lines below to generate .csv for Lift charting using Excel +-- SET lines 32767 +-- SET pages 0 +-- SET colsep "," +-- SET feedback off +-- SET trimspool on +-- SPOOL dmabdemo.csv +SELECT quantile_number qtl, + lift_cumulative lcume, + percentage_records_cumulative prcume, + targets_cumulative tcume, + target_density_cumulative tdcume +-- Other info in Lift results +-- quantile_total_count, +-- target_density_cumulative, +-- non_targets_cumulative, +-- lift_quantile, +-- target_density + FROM abn_sh_sample_lift +ORDER BY quantile_number; +-- SPOOL OFF + +-- DISPLAY ROC - TOP 10 PROBABILITIES +-- +SELECT probability prob, + true_positives tp, + false_negatives fn, + false_positives fp, + true_negatives tn, + true_positive_fraction tpf, + false_positive_fraction fpf + FROM (SELECT * FROM abn_sh_sample_roc ORDER BY probability) + WHERE ROWNUM < 11; + +----------------------------------------------------------------------- +-- APPLY THE MODEL +----------------------------------------------------------------------- + +-- Cleanup scoring data preparation objects for repeat runs +-- +BEGIN EXECUTE IMMEDIATE 'DROP VIEW abn_sh_sample_apply_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW abn_sh_sample_apply_cat'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +----------------------- +-- PREPARE SCORING DATA +-- +-- If the data for model creation has been prepared, then the data to be +-- scored using the model must be prepared to the same scale in order to +-- obtain meaningful results. +-- +-- 1. Missing value treatment - see dmsvcdem.sql for example of what +-- needs to be done with Test and Apply data input. +-- +-- 2. Outlier treatment and +-- 3. Binning +-- Quantile binning handles both the outlier treatment and binning in this case. +-- Transform the test data mining_test_v, using the transformation tables +-- generated during the Build data preparation, to generate a view representing +-- prepared test data. +-- +-- If this model is applied in a different schema or instance, the +-- data preparation objects generated in the CREATE step must also +-- be made available in the target schema/instance. So you must export +-- those objects (i.e. the num and cat bin tables and views) along with +-- the model to the target user schema. +-- +BEGIN + -- Execute the first transform effected on training data + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_CAT ( + bin_table_name => 'abn_sh_sample_cat', + data_table_name => 'mining_data_apply_v', + xform_view_name => 'abn_sh_sample_apply_cat'); + + -- Provide the result to the next transform effected on training data + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_NUM ( + bin_table_name => 'abn_sh_sample_num', + data_table_name => 'abn_sh_sample_apply_cat', + xform_view_name => 'abn_sh_sample_apply_prepared'); +END; +/ + +-- Cleanup scoring result objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE abn_sh_sample_apply_result'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +------------------ +-- APPLY THE MODEL +-- +BEGIN + DBMS_DATA_MINING.APPLY( + model_name => 'ABN_SH_Clas_sample', + data_table_name => 'abn_sh_sample_apply_prepared', + case_id_column_name => 'cust_id', + result_table_name => 'abn_sh_sample_apply_result'); +END; +/ + +-- APPLY RESULT OBJECTS: abn_sh_sample_apply_result + +------------------------ +-- DISPLAY APPLY RESULTS +-- +-- 1. The results table contains a prediction set - i.e. ALL the predictions +-- for a given case id, with their corresponding probability values. +-- 2. In this example, note that APPLY results do not need to be reverse +-- transformed, as done in the case of model details. This is because +-- class values of a classification target were not (required to be) +-- binned or normalized. +-- 3. Only the first 10 rows of the table are displayed here. +-- +column prediction format a20 +column probability format 9.999999 +SELECT cust_id, TO_CHAR(prediction) AS prediction, probability + FROM (SELECT cust_id, prediction, ROUND(probability,4) probability + FROM abn_sh_sample_apply_result + ORDER BY cust_id, prediction, probability) + WHERE ROWNUM < 11 +ORDER BY cust_id; + +----------------------------------------------------------- +-- GENERATE RANKED APPLY RESULTS (OPTIONALLY BASED ON COST) +-- +-- See dmsvmcdem.sql - SVM Classification - for example +-- diff --git a/dmaidemo.java b/dmaidemo.java new file mode 100644 index 0000000..74ad523 --- /dev/null +++ b/dmaidemo.java @@ -0,0 +1,297 @@ +// Copyright (c) 2004, 2006, Oracle. All rights reserved. +// File: dmaidemo.java + +import java.text.DecimalFormat; +import java.text.MessageFormat; + +import java.util.Collection; +import java.util.Iterator; + +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.NamedObject; +import javax.datamining.SortOrder; +import javax.datamining.attributeimportance.AttributeImportanceModel; +import javax.datamining.attributeimportance.AttributeImportanceSettings; +import javax.datamining.attributeimportance.AttributeImportanceSettingsFactory; +import javax.datamining.base.Task; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.ModelSignature; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.resource.Connection; +import javax.datamining.resource.ConnectionFactory; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; + +import oracle.dmt.jdm.base.OraBuildSettings; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.task.OraTransformationTaskFactory; +import oracle.dmt.jdm.transform.binning.OraBinningTransformFactory; + +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to build an Attribute Importance (AI) model by using the Minimum Description +* Length (MDL) algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* Given a target attribute affinity_card, find the importance of independent +* attributes. +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* See the corresponding section in dmabdemo.java - Classification using ABN. +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build an Attribute Importance model by using Minimum +* Description Length (MDL) algorithm with auto data preparation. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +public class dmaidemo + extends Object +{ + // Connection related data members + private static Connection m_dmeConn; + private static ConnectionFactory m_dmeConnFactory; + // Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static AttributeImportanceSettingsFactory m_aiFactory; + private static BuildTaskFactory m_buildFactory; + private static OraBinningTransformFactory m_binningXformFactory; + private static OraTransformationTaskFactory m_xformTaskFactory; + // Provide schema name that has the data tables/views + private static String m_buildDataName = "MINING_DATA_BUILD_V"; + private static String m_idColName = "CUST_ID"; + private static String m_pdsName = "aiBuildData_jdm"; + private static String m_settingsName = "aiSettings_jdm"; + private static String m_modelName = "aiModel_jdm"; + private static String m_taskName = "aiBuildTask_jdm"; + private static String m_targetName = "AFFINITY_CARD"; + // Global constants + private static DecimalFormat m_df = new DecimalFormat("##.####"); + + public static void main(String[] args) + { + try + { + if ((args.length != 0) & (args.length != 3)) + { + System.out.println("Usage: java dmaidemo "); + System.out.println(" or: java dmaidemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + // 1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@" + uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Build a model + buildModel(); + } + catch (Exception anyExp) + { + anyExp.printStackTrace(System.out); + } + finally + { + try + { + //6. Logout from the Data Mining Engine + m_dmeConn.close(); + } + catch (Exception anyExp1) + { + } //Ignore + } + } + + public static void initFactories() + throws JDMException + { + m_pdsFactory = + (PhysicalDataSetFactory) m_dmeConn.getFactory("javax.datamining.data.PhysicalDataSet"); + m_paFactory = + (PhysicalAttributeFactory) m_dmeConn.getFactory("javax.datamining.data.PhysicalAttribute"); + m_aiFactory = + (AttributeImportanceSettingsFactory) m_dmeConn.getFactory("javax.datamining.attributeimportance.AttributeImportanceSettings"); + m_buildFactory = + (BuildTaskFactory) m_dmeConn.getFactory("javax.datamining.task.BuildTask"); + m_binningXformFactory = + (OraBinningTransformFactory) m_dmeConn.getFactory("oracle.dmt.jdm.transform.binning.OraBinningTransform"); + m_xformTaskFactory = + (OraTransformationTaskFactory) m_dmeConn.getFactory("oracle.dmt.jdm.task.OraTransformationTask"); + } + + /** + * This method illustrates how to build attribute importance mining model + * using MINING_BUILD_DATA_V dataset and mining function settings. + */ + public static void buildModel() + throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Build Model ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = + m_pdsFactory.create(m_buildDataName, false); + PhysicalAttribute pa = + m_paFactory.create(m_idColName, AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + buildData.addAttribute(pa); + m_dmeConn.saveObject(m_pdsName, buildData, false); + // 2. Create & save Mining Function Settings + // Create AttributeImportanceSettings + AttributeImportanceSettings buildSettings = m_aiFactory.create(); + buildSettings.setTargetAttributeName(m_targetName); + ((OraBuildSettings) buildSettings).useAutomatedDataPreparations(true); + m_dmeConn.saveObject(m_settingsName, buildSettings, true); + // 3. Create, save & execute Build Task + BuildTask buildTask = // Build data specification + // Mining function settings name + // Mining model name + m_buildFactory.create(m_pdsName, m_settingsName, m_modelName); + buildTask.setDescription(m_taskName); + executeTask(buildTask, m_taskName); + // 4. Restore the model from the DME and explore the details of the model + AttributeImportanceModel model = + (AttributeImportanceModel) m_dmeConn.retrieveObject(m_modelName, + NamedObject.model); + // Display model details + displayAIModelDetails(model); + } + + /** + * This method stores the given task with the specified name in the DMS + * (Data Mining Server), + * and submits the task for asynchronous execution in the DMS. After + * completing the task successfully it returns true. If there is a task + * failure, then it prints the error description and returns false. + * + * @param taskObj task object + * @param taskName name of the task + * + * @return boolean returns true when the task is successful + */ + public static boolean executeTask(Task taskObj, String taskName) + throws JDMException + { + boolean isTaskSuccess = false; + m_dmeConn.saveObject(taskName, taskObj, true); + ExecutionHandle execHandle = m_dmeConn.execute(taskName); + System.out.print(taskName + " is started, please wait. "); + //Wait for completion of the task + ExecutionStatus status = + execHandle.waitForCompletion(Integer.MAX_VALUE); + //Check the status of the task after completion + isTaskSuccess = status.getState().equals(ExecutionState.success); + if (isTaskSuccess) + { + //Task completed successfully + System.out.println(taskName + " is successful."); + } + else + { //Task failed + System.out.println(taskName + " is failed.\nFailure Description: " + + status.getDescription()); + } + return isTaskSuccess; + } + + /** + * This method displayes AI model details. + * */ + public static void displayAIModelDetails(AttributeImportanceModel model) + throws JDMException + { + String modelName = model.getName(); + System.out.println("Model Name: " + modelName); + // 1. Get spurious info from the model + System.out.println("Attribute Count:" + model.getAttributeCount()); + System.out.println("Max Rank:" + model.getMaxRank()); + // 2. List of attribute names ranked by their importance value. + // NOTE: The attributes that show negative importance values are not + // important attributes, similar to attributes with importance value of 0. + // From MDL principles, the negative importance value indicates that the + // given attribute simply adds to the size of the model - in this case, the + // list of attributes most relevant to the target - without adding any + // additional knowledge. + System.out.println("All attributes in descending order of their importance:"); + Collection attrColl = model.getAttributesByRank(SortOrder.descending); + displayAttributes(attrColl, model.getSignature()); + // 3. Get attributes by range (first top 5) + System.out.println("Top 5 attributes:"); + attrColl = model.getAttributesByRank(1, 5); + displayAttributes(attrColl, model.getSignature()); + // 4. Get attributes by percentage (bottom 20%) + System.out.println("Top 20% attributes:"); + attrColl = model.getAttributesByPercentage(20.0, SortOrder.descending); + displayAttributes(attrColl, model.getSignature()); + // 5. Get attributes by percentage (bottom 20%) + System.out.println("Bottom 20% attributes:"); + attrColl = model.getAttributesByPercentage(20.0, SortOrder.ascending); + displayAttributes(attrColl, model.getSignature()); + } + + private static void displayAttributes(Collection attrColl, + ModelSignature signature) + { + System.out.println("( Attribute Name, Importance, Rank )"); + MessageFormat mfSign = new MessageFormat("( {0}, {1}, {2} )"); + String[] vals = new String[3]; + Iterator attrI = attrColl.iterator(); + while (attrI.hasNext()) + { + try + { + vals[0] = (String) attrI.next(); + vals[1] = + m_df.format(signature.getAttribute(vals[0]).getImportanceValue()) + + ""; + vals[2] = + m_df.format(signature.getAttribute(vals[0]).getRank()) + ""; + } + catch (Exception e) + { + } + System.out.println(mfSign.format(vals)); + } + } + + private static void clean() + { + // Drop the model + try + { + m_dmeConn.removeObject(m_modelName, NamedObject.model); + } + catch (JDMException jdmExp) + { + } + } +} diff --git a/dmaidemo.sql b/dmaidemo.sql new file mode 100644 index 0000000..3e966ce --- /dev/null +++ b/dmaidemo.sql @@ -0,0 +1,184 @@ +Rem +Rem $Header: dmaidemo.sql 11-jul-2005.12:07:01 ktaylor Exp $ +Rem +Rem dmabdemo.sql +Rem +Rem Copyright (c) 2003, 2005, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmaidemo.sql - Sample program for the DBMS_DATA_MINING package. +Rem +Rem DESCRIPTION +Rem This script creates an attribute importance model +Rem using the MDL algorithm +Rem and data in the SH (Sales History) schema in the RDBMS. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ktaylor 07/11/05 - minor edits to comments +Rem jcjeon 01/18/05 - add column format +Rem ramkrish 10/26/04 - add data analysis and comments/cleanup +Rem ramkrish 10/02/03 - Creation + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET echo ON + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM +----------------------------------------------------------------------- +-- Given a target attribute affinity_card, find the importance of +-- independent attributes. + +----------------------------------------------------------------------- +-- SET UP AND ANALYZE THE DATA +----------------------------------------------------------------------- + +-- See the corresponding section in dmabdemo.sql - Classification +-- using ABN. The analysis and preparation steps are very similar. + +----------------------------------------------------------------------- +-- BUILD THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old build data preparation objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE ai_sh_sample_num'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE ai_sh_sample_cat'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW ai_sh_sample_build_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW ai_sh_sample_build_cat'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-------------------------------- +-- PREPARE BUILD (TRAINING) DATA +-- +-- 1. Missing Value treatment for all Predictors +-- Skipped - see dmsvcdem.sql +-- +-- 2. Outlier Treatment +-- See notes in dmabdemo.sql and dmsvcdem.sql on outlier +-- treatment with equi-width binning. +-- Skipped - see dmsvcdem.sql for example. +-- +-- 3. Binning +-- +BEGIN + -- Bin categorical attributes: OCCUPATION + DBMS_DATA_MINING_TRANSFORM.CREATE_BIN_CAT ( + bin_table_name => 'ai_sh_sample_cat'); + + DBMS_DATA_MINING_TRANSFORM.INSERT_BIN_CAT_FREQ ( + bin_table_name => 'ai_sh_sample_cat', + data_table_name => 'mining_data_build_v', + bin_num => 7, + exclude_list => DBMS_DATA_MINING_TRANSFORM.COLUMN_LIST ( + 'cust_gender', + 'cust_marital_status', + 'country_name', + 'cust_income_level', + 'education', + 'household_size') + ); + + -- Bin numerical attributes: AGE + DBMS_DATA_MINING_TRANSFORM.CREATE_BIN_NUM ( + bin_table_name => 'ai_sh_sample_num'); + + DBMS_DATA_MINING_TRANSFORM.INSERT_BIN_NUM_QTILE ( + bin_table_name => 'ai_sh_sample_num', + data_table_name => 'mining_data_build_v', + bin_num => 5, + exclude_list => DBMS_DATA_MINING_TRANSFORM.COLUMN_LIST ( + 'affinity_card', + 'bookkeeping_application', + 'bulk_pack_diskettes', + 'cust_id', + 'flat_panel_monitor', + 'home_theater_package', + 'os_doc_set_kanji', + 'printer_supplies', + 'y_box_games', + 'yrs_residence') + ); + + -- Create the transformed view + -- Execute the first transformation (categorical binning) + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_CAT ( + bin_table_name => 'ai_sh_sample_cat', + data_table_name => 'mining_data_build_v', + xform_view_name => 'ai_sh_sample_build_cat'); + + -- Provide the result (ai_sh_sample_build_cat) + -- to the next transformation (numerical binning) + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_NUM ( + bin_table_name => 'ai_sh_sample_num', + data_table_name => 'ai_sh_sample_build_cat', + xform_view_name => 'ai_sh_sample_build_prepared'); +END; +/ +-- BUILD DATA PREPARATION OBJECTS: +-- ------------------------------ +-- 1. Categorical Bin Table: ai_sh_sample_cat +-- 2. Numerical Bin Table: ai_sh_sample_num +-- 3. Input (view) to CREATE_MODEL: ai_sh_sample_build_prepared + +------------------- +-- SPECIFY SETTINGS +-- +-- There are no explicit settings for attribute importance. +-- +--------------------- +-- CREATE A NEW MODEL +-- +-- Cleanup old model with the same name for repeat runs +BEGIN DBMS_DATA_MINING.DROP_MODEL('AI_SH_sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- Build a new AI model +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'AI_SH_sample', + mining_function => DBMS_DATA_MINING.ATTRIBUTE_IMPORTANCE, + data_table_name => 'ai_sh_sample_build_prepared', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +-- Skip. This routine is not applicable for this function. + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +-- Skip. This routine is not applicable for this function. + +------------------------ +-- DISPLAY MODEL DETAILS +-- +-- list of attribute names ranked by their importance value. +-- +-- NOTE: The attributes that show negative importance values +-- are not important attributes, similar to attributes +-- with importance value of 0. From MDL principles, the +-- negative importance value indicates that the given +-- attribute simply adds to the size of the model - +-- in this case, the list of attributes most relevant +-- to the target - without adding any additional knowledge. +-- +column attribute_name format a40 +SELECT attribute_name, importance_value, rank + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_AI('AI_SH_sample')) +ORDER BY RANK; diff --git a/dmapplydemo.java b/dmapplydemo.java new file mode 100644 index 0000000..a12a5f6 --- /dev/null +++ b/dmapplydemo.java @@ -0,0 +1,743 @@ +// Copyright (c) 2004, 2006, Oracle. All rights reserved. +// File: dmapplydemo.java + +import java.math.BigDecimal; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.Statement; + +import java.text.DecimalFormat; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.NamedObject; +import javax.datamining.algorithm.naivebayes.NaiveBayesSettings; +import javax.datamining.algorithm.naivebayes.NaiveBayesSettingsFactory; +import javax.datamining.base.Task; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.CategoryProperty; +import javax.datamining.data.CategorySet; +import javax.datamining.data.CategorySetFactory; +import javax.datamining.data.ModelSignature; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataRecord; +import javax.datamining.data.PhysicalDataRecordFactory; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.supervised.classification.ClassificationApplyContent; +import javax.datamining.supervised.classification.ClassificationApplySettings; +import javax.datamining.supervised.classification.ClassificationApplySettingsFactory; +import javax.datamining.supervised.classification.ClassificationModel; +import javax.datamining.supervised.classification.ClassificationSettings; +import javax.datamining.supervised.classification.ClassificationSettingsFactory; +import javax.datamining.supervised.classification.ClassificationTestMetricsTaskFactory; +import javax.datamining.supervised.classification.ClassificationTestTaskFactory; +import javax.datamining.supervised.classification.CostMatrix; +import javax.datamining.supervised.classification.CostMatrixFactory; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; +import javax.datamining.task.apply.DataSetApplyTask; +import javax.datamining.task.apply.DataSetApplyTaskFactory; + +import javax.datamining.task.apply.RecordApplyTask; + +import javax.datamining.task.apply.RecordApplyTaskFactory; + +import oracle.dmt.jdm.base.OraBuildSettings; +import oracle.dmt.jdm.base.OraTask; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; + + + +/** +* This sample program describes how to use the ODM Java API to build, test, +* and apply a classification model using the NaiveBayes(NB) algorithm. +* This program uses the "AP_BINNED_DATA_BUILD_JDM" prepared dataset for building +* a model to predict which customer would respond to a promotion campaign +* ("affinity_card"). It then tests the model by computing model accuracy, +* confusion matrix, and lift results using "AP_BINNED_DATA_TEST_JDM" prepared +* dataset. After testing the model, it applies the built model on the +* "AP_BINNED_DATA_APPLY_JDM" prepared dataset to predict which customers would +* respond to a promotion campaign. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +public class dmapplydemo + extends Object +{ + + //Connection related data members + private static javax.datamining.resource.Connection m_dmeConn = null; + private static javax.datamining.resource.ConnectionFactory m_dmeConnFactory = + null; + //Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory = null; + private static PhysicalAttributeFactory m_paFactory = null; + private static ClassificationSettingsFactory m_clasFactory = null; + private static NaiveBayesSettingsFactory m_nbFactory = null; + private static BuildTaskFactory m_buildFactory = null; + private static DataSetApplyTaskFactory m_dsApplyFactory = null; + private static ClassificationTestTaskFactory m_testFactory = null; + private static ClassificationApplySettingsFactory m_applySettingsFactory = null; + private static CostMatrixFactory m_costMatrixFactory = null; + private static CategorySetFactory m_catSetFactory = null; + private static ClassificationTestMetricsTaskFactory m_testMetricsTaskFactory = null; + private static RecordApplyTaskFactory m_recApplyFactory = null; + private static PhysicalDataRecordFactory m_pdrFactory = null; + private static ModelSignature m_modelSignature = null; + + public static void main(String[] args) + { + try + { + if ((args.length != 0) & (args.length != 3)) + { + System.out.println("Usage: java dmapplydemo "); + System.out.println(" or: java dmapplydemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + // 1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@" + uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Build a model + buildModel(); + // 5. Create & save cost matrix + createCostMatrix(); + // 6. Run apply operations using + // various types of apply settings supported + defaultApply(); + + sourceDestinationMapApply(); + + mapByRankApply(); + + mapByCategoryApply(); + + mapTopPredictionApply(); + + //7. Start execution of the build task that trigger execution of + // its dependent apply tasks. + m_dmeConn.execute("apBuildTask_jdm"); + //8. Monitor the execution of the tasks in the server + monitorTaskExecutionProcess(); + } + catch (Exception anyExp) + { + anyExp.printStackTrace(System.out); + } + finally + { + try + { + //6. Logout from the Data Mining Engine + m_dmeConn.close(); + } + catch (Exception anyExp1) + { + } //Ignore + } + } + + public static void initFactories() + throws JDMException + { + m_pdsFactory = + (PhysicalDataSetFactory) m_dmeConn.getFactory("javax.datamining.data.PhysicalDataSet"); + m_paFactory = + (PhysicalAttributeFactory) m_dmeConn.getFactory("javax.datamining.data.PhysicalAttribute"); + m_pdrFactory = (PhysicalDataRecordFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalDataRecord"); + m_clasFactory = + (ClassificationSettingsFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.ClassificationSettings"); + m_nbFactory = + (NaiveBayesSettingsFactory) m_dmeConn.getFactory("javax.datamining.algorithm.naivebayes.NaiveBayesSettings"); + m_buildFactory = + (BuildTaskFactory) m_dmeConn.getFactory("javax.datamining.task.BuildTask"); + m_dsApplyFactory = + (DataSetApplyTaskFactory) m_dmeConn.getFactory("javax.datamining.task.apply.DataSetApplyTask"); + m_recApplyFactory = (RecordApplyTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.apply.RecordApplyTask"); + m_testFactory = + (ClassificationTestTaskFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.ClassificationTestTask"); + m_applySettingsFactory = + (ClassificationApplySettingsFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.ClassificationApplySettings"); + m_costMatrixFactory = + (CostMatrixFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.CostMatrix"); + m_catSetFactory = + (CategorySetFactory) m_dmeConn.getFactory("javax.datamining.data.CategorySet"); + m_testMetricsTaskFactory = + (ClassificationTestMetricsTaskFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.ClassificationTestMetricsTask"); + } + + /** + * This method builds a mining model. The build operation requires the training + * dataset location details and the mining function setting. + * In this example, we will build a classification model using the prepared + * build dataset "AP_BINNED_DATA_BUILD_JDM" in the user schema, with the + * NaiveBayes algorithm. This model can be used to predict which customer + * would respond to a promotion campaign. After completing the build task, the + * model named "apModel_jdm" will be created in the DMS. + */ + public static void buildModel() + throws JDMException + { + //1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = + m_pdsFactory.create("MINING_DATA_BUILD_V", false); + PhysicalAttribute pa = + m_paFactory.create("cust_id", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + buildData.addAttribute(pa); + m_dmeConn.saveObject("apBuildData_jdm", buildData, true); + //2. Create & save Mining Function Settings + //Create NB algorithm settings + NaiveBayesSettings nbAlgo = m_nbFactory.create(); + nbAlgo.setPairwiseThreshold(0.01f); + nbAlgo.setSingletonThreshold(0.01f); + //Create ClassificationSettings + ClassificationSettings buildSettings = m_clasFactory.create(); + buildSettings.setAlgorithmSettings(nbAlgo); + buildSettings.setTargetAttributeName("affinity_card"); + ((OraBuildSettings) buildSettings).useAutomatedDataPreparations(true); + //Set target prior probabilities + Map priorMap = new HashMap(); + priorMap.put(new Double(0), new Double(0.7)); + priorMap.put(new Double(1), new Double(0.3)); + buildSettings.setPriorProbabilitiesMap("affinity_card", priorMap); + m_dmeConn.saveObject("apBuildSettings_jdm", buildSettings, true); + //3. Create, save & execute Build Task + BuildTask buildTask = //Build data specification + //Mining function settings name + //Mining model name + m_buildFactory.create("apBuildData_jdm", "apBuildSettings_jdm", + "apModel_jdm"); + buildTask.setDescription("apBuildTask_jdm"); + saveTask(buildTask, "apBuildTask_jdm", null); + } + + /** + * This method applies a mining model to a dataset. The apply dataset location + * details, input model, and the output table location details are required + * for this operation. + * In this example, we apply the "apModel_jdm" to the + * "AP_BINNED_DATA_APPLY_JDM" prepared dataset to predict which customers + * receive an "affinity_card". After completing the apply task, an apply + * output table "ap_def_apply_output_jdm" will be created in the DMS. + */ + public static void defaultApply() + throws JDMException + { + //1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = + m_pdsFactory.create("MINING_DATA_APPLY_V", false); + PhysicalAttribute pa = + m_paFactory.create("cust_id", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + applyData.addAttribute(pa); + m_dmeConn.saveObject("ap_def_ApplyData_jdm", applyData, true); + //2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + m_dmeConn.saveObject("ap_def_ApplySettings_jdm", clasAS, true); + + //3. Create, store & execute apply Task + DataSetApplyTask applyTask = + m_dsApplyFactory.create("ap_def_ApplyData_jdm", "apModel_jdm", + "ap_def_ApplySettings_jdm", + "ap_def_apply_output_jdm"); + saveTask(applyTask, "ap_def_ApplyTask_jdm", "apBuildTask_jdm"); + } + + /** + * This method applies a mining model to a dataset. The apply dataset location + * details, input model and the output table location details are required + * for this operation. + * In this example, we apply the "apModel_jdm" to the + * "AP_BINNED_DATA_APPLY_JDM" prepared dataset to predict which customers + * receive an "affinity_card". After completing the apply task, an apply + * output table "ap_src_apply_output_jdm" will be created in the DMS. + */ + public static void sourceDestinationMapApply() + throws JDMException + { + //1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = + m_pdsFactory.create("MINING_DATA_APPLY_V", false); + PhysicalAttribute pa = + m_paFactory.create("cust_id", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + applyData.addAttribute(pa); + m_dmeConn.saveObject("ap_src_ApplyData_jdm", applyData, true); + //2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + //2.1 Create a Map of attributes to be included in the output dataset + Map srcDestMap = new HashMap(); + srcDestMap.put("AGE", "AGE_IN_YRS"); + srcDestMap.put("CUST_INCOME_LEVEL", "CUST_INCOME_LEVEL_IN_$"); + srcDestMap.put("OCCUPATION", "OCCUPATION_AS"); + clasAS.setSourceDestinationMap(srcDestMap); + m_dmeConn.saveObject("ap_src_ApplySettings_jdm", clasAS, true); + //3. Create, store & execute apply Task + DataSetApplyTask applyTask = + m_dsApplyFactory.create("ap_src_ApplyData_jdm", "apModel_jdm", + "ap_src_ApplySettings_jdm", + "ap_src_apply_output_jdm"); + saveTask(applyTask, "ap_src_ApplyTask_jdm", "apBuildTask_jdm"); + } + + /** + * This method applies a mining model to a dataset. The apply dataset location + * details, input model, and the output table location details are required + * for this operation. + * In this example, we apply the "apModel_jdm" to the + * "AP_BINNED_DATA_APPLY_JDM" prepared dataset to predict which customers + * receive an "affinity_card". After completing the apply task, an apply + * output table "ap_apply_output" will be created in the DMS. + */ + public static void mapByRankApply() + throws JDMException + { + //1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = + m_pdsFactory.create("MINING_DATA_APPLY_V", false); + PhysicalAttribute pa = + m_paFactory.create("cust_id", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + applyData.addAttribute(pa); + m_dmeConn.saveObject("ap_rk_ApplyData_jdm", applyData, true); + //2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + String[] predCategories = new String[] + { "Top_1_Category" }; + clasAS.mapByRank(ClassificationApplyContent.predictedCategory, + predCategories, true); + m_dmeConn.saveObject("ap_rk_ApplySettings_jdm", clasAS, true); + + //3. Create, store & execute apply Task + DataSetApplyTask applyTask = + m_dsApplyFactory.create("ap_rk_ApplyData_jdm", "apModel_jdm", + "ap_rk_ApplySettings_jdm", + "ap_rk_apply_output_jdm"); + saveTask(applyTask, "ap_rk_ApplyTask_jdm", "apBuildTask_jdm"); + } + + /** + * This method applies a mining model to a dataset. The apply dataset location + * details, input model, and the output table location details are required + * for this operation. + * In this example, we apply the "apModel_jdm" to the + * "AP_BINNED_DATA_APPLY_JDM" prepared dataset to predict which customers + * receive an "affinity_card". After completing the apply task, an apply + * output table "ap_cls_apply_output_jdm" will be created in the DMS. + */ + public static void mapByCategoryApply() + throws JDMException + { + //1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = + m_pdsFactory.create("MINING_DATA_APPLY_V", false); + PhysicalAttribute pa = + m_paFactory.create("cust_id", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + applyData.addAttribute(pa); + m_dmeConn.saveObject("ap_cls_ApplyData_jdm", applyData, true); + //2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + clasAS.mapByCategory(ClassificationApplyContent.probability, + new Integer(0), "NotResponds"); + clasAS.mapByCategory(ClassificationApplyContent.probability, + new Integer(1), "Responds"); + m_dmeConn.saveObject("ap_cls_ApplySettings_jdm", clasAS, true); + //3. Create, store & execute apply Task + DataSetApplyTask applyTask = + m_dsApplyFactory.create("ap_cls_ApplyData_jdm", "apModel_jdm", + "ap_cls_ApplySettings_jdm", + "ap_cls_apply_output_jdm"); + saveTask(applyTask, "ap_cls_ApplyTask_jdm", "apBuildTask_jdm"); + + } + + /** + * This method applies a mining model to a dataset. The apply dataset location + * details, input model, and the output table location details are required + * for this operation. + * In this example, we apply the "apModel_jdm" to the + * "AP_BINNED_DATA_APPLY_JDM" prepared dataset to predict which customers + * receive an "affinity_card". After completing the apply task, an apply + * output table "ap_top_apply_output_jdm" will be created in the DMS. + */ + public static void mapTopPredictionApply() + throws JDMException + { + //1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = + m_pdsFactory.create("MINING_DATA_APPLY_V", false); + PhysicalAttribute pa = + m_paFactory.create("cust_id", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + applyData.addAttribute(pa); + m_dmeConn.saveObject("ap_top_ApplyData_jdm", applyData, true); + //2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + clasAS.mapTopPrediction(ClassificationApplyContent.predictedCategory, + "Responds"); + clasAS.mapTopPrediction(ClassificationApplyContent.probability, + "Probability"); + m_dmeConn.saveObject("ap_top_ApplySettings_jdm", clasAS, true); + //3. Create, store & execute apply Task + DataSetApplyTask applyTask = + m_dsApplyFactory.create("ap_top_ApplyData_jdm", "apModel_jdm", + "ap_top_ApplySettings_jdm", + "ap_top_apply_output_jdm"); + saveTask(applyTask, "ap_top_ApplyTask_jdm", "apBuildTask_jdm"); + + } + + /** + * This method applies a mining model to a single record. + */ + public static void recordApply(ModelSignature modelSignature) throws JDMException + { + //1. Create a PhysicalDataRecord that contains an model signature attributes + PhysicalDataRecord applyInputRecord = m_pdrFactory.create(modelSignature); + //2. Specify attribute record values + applyInputRecord.setValue("AGE", "62"); + applyInputRecord.setValue("BOOKKEEPING_APPLICATION", new Integer(1)); + applyInputRecord.setValue("CUST_GENDER","F"); + applyInputRecord.setValue("CUST_MARITAL_STATUS","Widowed"); + applyInputRecord.setValue("EDUCATION","< Bach."); + applyInputRecord.setValue("HOME_THEATER_PACKAGE", new Integer(1)); + applyInputRecord.setValue("HOUSEHOLD_SIZE", new Integer(2)); + applyInputRecord.setValue("OCCUPATION","Exec."); + applyInputRecord.setValue("YRS_RESIDENCE",new Integer(3)); + applyInputRecord.setValue("Y_BOX_GAMES",new Integer(0)); + //3. Create and save ClassificationApplySettings object + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + clasAS.mapTopPrediction(ClassificationApplyContent.predictedCategory, "Responds"); + clasAS.mapTopPrediction(ClassificationApplyContent.probability, "Probability"); + m_dmeConn.saveObject( "ap_rec_ApplySettings_jdm", clasAS, true); + //4. Create and execute RecordApplyTask + RecordApplyTask applyTask = m_recApplyFactory.create(applyInputRecord, + "apModel_jdm", "ap_rec_ApplySettings_jdm"); + ExecutionStatus recExecStatus = m_dmeConn.execute(applyTask, null); + //5. Check the status of the task after completion + boolean isTaskSuccess = recExecStatus.getState().equals(ExecutionState.success); + if( isTaskSuccess ) { + //Task completed successfully + System.out.println("RecordApplyTask is successful."); + } else {//Task failed + System.out.println("RecordApplyTask is failed.\nFailure Description: " + + recExecStatus.getDescription() ); + } + //6. Display prediction for this record + PhysicalDataRecord applyOutputRecord = applyTask.getOutputRecord(); + Number customerResponds = (Number)applyOutputRecord.getValue("RESPONDS"); + String respondsStr = (customerResponds.intValue() == 0)?"do not responds":"responds"; + Number customerRespondsProbability = (Number)applyOutputRecord.getValue("PROBABILITY"); + System.out.println("This customer " + respondsStr + " to the affinity card promotion with probability " + customerRespondsProbability.toString()); + } + + /** + * This method saves the given task with the specified task name and task + * dependency (parent task) in the DME. + * + * @param taskObj task object + * @param taskName name of the task + * @param parentTaskName name of the parent task + * + * @return boolean returns true when the task is successful + * @exception JDMException if task execution failed + */ + public static void saveTask(Task taskObj, String taskName, + String parentTaskName) + throws JDMException + { + if (parentTaskName != null) + ((OraTask) taskObj).addDependency(parentTaskName); //Since OJDM 11.1 + ((OraTask) taskObj).overwriteOutput(true); //Since OJDM 11.1 + m_dmeConn.saveObject(taskName, taskObj, true); + } + + + //create and save cost matrix + + private static void createCostMatrix() + throws JDMException + { + //create categorySet + CategorySet catSet = + m_catSetFactory.create(AttributeDataType.integerType); + //Add category values + catSet.addCategory(new Integer(0), CategoryProperty.valid); + catSet.addCategory(new Integer(1), CategoryProperty.valid); + //create cost matrix + CostMatrix costMatrix = m_costMatrixFactory.create(catSet); + costMatrix.setCellValue(new Integer(0), new Integer(0), 0); + costMatrix.setCellValue(new Integer(1), new Integer(1), 0); + costMatrix.setCellValue(new Integer(0), new Integer(1), 2); + costMatrix.setCellValue(new Integer(1), new Integer(0), 4); + //save cost matrix + m_dmeConn.saveObject("apCostMatrix", costMatrix, true); + } + + /** + * This method monitor task execution initiated by the first task + * in the sequence of dependent tasks. In addition, this method displays + * task output results (if any). + * @throws JDMException + */ + public static void monitorTaskExecutionProcess() + throws JDMException + { + //1. Monitor BuildTask + //Wait for the completion of the task + System.out.print("Waiting for the completion of apBuildTask_jdm. "); + ExecutionStatus buildTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("apBuildTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //If successful + if (ExecutionState.success.equals(buildTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + ClassificationModel model = + (ClassificationModel)m_dmeConn.retrieveObject( + "apModel_jdm", NamedObject.model); + m_modelSignature = model.getSignature(); + recordApply(m_modelSignature); + //2. Monitor default settings applyTask + //Wait for the completion of the task + { + System.out.print("Waiting for the completion of ap_def_ApplyTask_jdm. "); + ExecutionStatus defaultApplySettingsTaskStatus = + m_dmeConn.getLastExecutionHandle("ap_def_ApplyTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //If successful + if (ExecutionState.success.equals(defaultApplySettingsTaskStatus.getState())) + { + System.out.println("It is successful. "); + displayApplyResults("ap_def_apply_output_jdm", + "cust_id, prediction"); + } + else + { + System.out.println("It is at state:" + + defaultApplySettingsTaskStatus.getState().name() + + ((defaultApplySettingsTaskStatus.getDescription() == + null)? "": + "State Description:" + defaultApplySettingsTaskStatus.getDescription())); + } + } + + //3. Monitor source destination settings applyTask + //Wait for the completion of the task + { + System.out.print("Waiting for the completion of ap_src_ApplyTask_jdm. "); + ExecutionStatus sourceDestinationMappingApplyTaskStatus = + m_dmeConn.getLastExecutionHandle("ap_src_ApplyTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //If successful + if (ExecutionState.success.equals(sourceDestinationMappingApplyTaskStatus.getState())) + { + System.out.println("It is successful. "); + displayApplyResults("ap_src_apply_output_jdm", + "cust_id, prediction"); + } + else + { + System.out.println("It is at state:" + + sourceDestinationMappingApplyTaskStatus.getState().name() + + ((sourceDestinationMappingApplyTaskStatus.getDescription() == + null)? "": + "State Description:" + sourceDestinationMappingApplyTaskStatus.getDescription())); + } + } + + //4. Monitor rank applyTask + //Wait for the completion of the task + { + System.out.print("Waiting for the completion of ap_rk_ApplyTask_jdm. "); + ExecutionStatus rankApplyTaskStatus = + m_dmeConn.getLastExecutionHandle("ap_rk_ApplyTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //If successful + if (ExecutionState.success.equals(rankApplyTaskStatus.getState())) + { + System.out.println("It is successful. "); + displayApplyResults("ap_rk_apply_output_jdm", + "cust_id, prediction"); + } + else + { + System.out.println("It is at state:" + + rankApplyTaskStatus.getState().name() + + ((rankApplyTaskStatus.getDescription() == + null)? "": + "State Description:" + rankApplyTaskStatus.getDescription())); + } + } + + //5. Monitor rank applyTask + //Wait for the completion of the task + { + System.out.print("Waiting for the completion of ap_cls_ApplyTask_jdm. "); + ExecutionStatus classApplyTaskStatus = + m_dmeConn.getLastExecutionHandle("ap_cls_ApplyTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //If successful + if (ExecutionState.success.equals(classApplyTaskStatus.getState())) + { + System.out.println("It is successful. "); + displayApplyResults("ap_cls_apply_output_jdm", + "cust_id, notresponds, responds"); + } + else + { + System.out.println("It is at state:" + + classApplyTaskStatus.getState().name() + + ((classApplyTaskStatus.getDescription() == + null)? "": + "State Description:" + classApplyTaskStatus.getDescription())); + } + } + + //6. Monitor top-prediction applyTask + //Wait for the completion of the task + { + System.out.print("Waiting for the completion of ap_top_ApplyTask_jdm. "); + ExecutionStatus topPredApplyTaskStatus = + m_dmeConn.getLastExecutionHandle("ap_top_ApplyTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //If successful + if (ExecutionState.success.equals(topPredApplyTaskStatus.getState())) + { + System.out.println("It is successful. "); + displayApplyResults("ap_top_apply_output_jdm", + "cust_id, prediction"); + } + else + { + System.out.println("It is at state:" + + topPredApplyTaskStatus.getState().name() + + ((topPredApplyTaskStatus.getDescription() == + null)? "": + "State Description:" + topPredApplyTaskStatus.getDescription())); + } + } + } + else + { + System.out.println("It is at state:" + + buildTaskCompletionStatus.getState().name() + + ((buildTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + buildTaskCompletionStatus.getDescription())); + } + } + + public static void displayApplyResults(String applyTableName, + String orderBy) + { + StringBuffer emptyCol = new StringBuffer(" "); + + java.sql.Connection dbConn = + ((OraConnection) m_dmeConn).getDatabaseConnection(); + PreparedStatement pStmt = null; + ResultSet rs = null; + try + { + pStmt = + dbConn.prepareStatement("SELECT * FROM " + applyTableName + " WHERE ROWNUM<10 ORDER BY " + + orderBy); + rs = pStmt.executeQuery(); + ResultSetMetaData rsMeta = rs.getMetaData(); + int colCount = rsMeta.getColumnCount(); + StringBuffer header = new StringBuffer(); + System.out.println("Table : " + applyTableName); + //Build table header + for (int iCol = 1; iCol <= colCount; iCol++) + { + String colName = rsMeta.getColumnName(iCol); + header.append(emptyCol.replace(0, colName.length(), colName)); + emptyCol = new StringBuffer(" "); + } + System.out.println(header.toString()); + //Write table data + while (rs.next()) + { + StringBuffer rowContent = new StringBuffer(); + for (int iCol = 1; iCol <= colCount; iCol++) + { + int sqlType = rsMeta.getColumnType(iCol); + Object obj = rs.getObject(iCol); + String colContent = null; + DecimalFormat df = new DecimalFormat("00000000.##E0"); + if (obj instanceof java.lang.Number) + { + try + { + BigDecimal bd = (BigDecimal) obj; + if (bd.scale() > 5) + { + colContent = df.format(obj); + } + else + { + colContent = bd.toString(); + } + } + catch (Exception anyExp) + { + colContent = df.format(obj); + } + } + else + { + colContent = obj.toString(); + } + + rowContent.append(emptyCol.replace(0, colContent.length(), + colContent)); + emptyCol = new StringBuffer(" "); + } + System.out.println(rowContent.toString()); + } + } + catch (Exception anySqlExp) + { + anySqlExp.printStackTrace(); + } //Ignore + } + + private static void clean() + { + //Drop the model + try + { + m_dmeConn.removeObject("apModel_jdm", NamedObject.model); + } + catch (Exception jdmExp) + { + } + + + } +} diff --git a/dmardemo.java b/dmardemo.java new file mode 100644 index 0000000..5a8dc32 --- /dev/null +++ b/dmardemo.java @@ -0,0 +1,793 @@ +// Copyright (c) 2004, 2006, Oracle. All rights reserved. +// File: dmardemo.java +import java.math.BigDecimal; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; + +import java.sql.SQLException; + +import java.sql.Statement; + +import java.text.DecimalFormat; + +import java.util.Collection; + +import java.util.Iterator; + +import java.util.TreeSet; + +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.MiningAlgorithm; +import javax.datamining.MiningFunction; +import javax.datamining.NamedObject; +import javax.datamining.SortOrder; +import javax.datamining.association.AssociationModel; +import javax.datamining.association.AssociationSettings; +import javax.datamining.association.AssociationSettingsFactory; +import javax.datamining.association.Itemset; +import javax.datamining.association.RuleProperty; +import javax.datamining.association.RulesFilterFactory; +import javax.datamining.base.AlgorithmSettings; +import javax.datamining.base.Task; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.resource.Connection; +import javax.datamining.resource.ConnectionFactory; +import javax.datamining.resource.ConnectionSpec; + +import javax.datamining.task.BuildTask; + +import javax.datamining.task.BuildTaskFactory; + +import oracle.dmt.jdm.association.OraAssociationRule; +import oracle.dmt.jdm.association.OraItemset; +import oracle.dmt.jdm.association.OraRulesFilter; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; + +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to build an Association model by using Apriori (AR) algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* Find the associations between items bought by customers. +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from a small subset of sales transactions +* from base tables in the Sales History (SH) Schema. The SH schema is an Oracle Database +* Sample Schema that has customer demographics, purchasing, and +* response details for the previous affinity card programs. Data +* exploration and preparing the data is a common step before doing data mining. +* Here in this demo, the following views are created in the user schema using +* SALES and PRODUCT tables. +* +* SALES_TRANS_CUST_V: +* This view collects the previous customers' purchasing details for building the +* model. This view will contain purchasing details for customers who have a +* cust_id between 100001 AND 104500. +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Prepare Data: +* 1. Common item removal: common items are candidates for removal during model +* build, because if a majority of customers have bought those items, the +* resulting rules do not have much value. Since the dataset is small, we will +* skip common item removal. +* +* 2. Data format transformation: market basket or sales datasets are +* transactional in nature, and form dimension tables in a typical DW. We +* present such transactional data to the API using an Object View that +* contains a nested table column holding a collection of items that correspond +* to a given case id. +* +* 3. Binning transformation: it is used to reduce the cardinality of higher +* cardinality attributes. The prepareData() method in this demo program +* illustrates the preparation of the build data. We skip binning +* transformation in this demo. See dmabdemo.java for an example of quantile +* binning. +* +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build an Association model by using the Apriori algorithm. +* +* Test Model: +* Association rules do not have a predefined test metric. Two indirect +* measures of modeling success are: +* +* 1. Number of Rules generated: The optimal number of rules is application +* dependent. In general, an overwhelming number of rules is undesirable for +* user interpretation. More rules take longer to compute, and also consume +* storage and CPU cycles. You should avoid too many rules by increasing the +* value for support. +* +* 2. Relevance of rules: This can be determined only by +* user inspection of rules, since it is application dependent. Ideally, we +* want to find rules with high confidence and with non-obvious patterns. The +* value for confidence is an indicator of the strength of the rule - so you +* could set the confidence value high in conjunction with support and see if +* you get high quality rules. +* +* 3. Frequent itemsets provide an insight into co-occurrence of items. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +// Generic Java api imports +// Java Data Mining (JDM) standard api imports +// Oracle Java Data Mining (JDM) implemented api imports +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to build an Association model by using Apriori (AR) algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* Find the associations between items bought by customers. +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from a small subset of sales transactions +* from base tables in the Sales History (SH) Schema. The SH schema is an Oracle Database +* Sample Schema that has customer demographics, purchasing, and +* response details for the previous affinity card programs. Data +* exploration and preparing the data is a common step before doing data mining. +* Here in this demo, the following views are created in the user schema using +* SALES and PRODUCT tables. +* +* SALES_TRANS_CUST_V: +* This view collects the previous customers' purchasing details for building the +* model. This view will contain purchasing details for customers who have a +* cust_id between 100001 AND 104500. +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Create input view: +* In this demo we illustrate creation of a nested table based view, that +* has sales transaction data as a nested structure for each customer. This +* view is used as input for AR model build. +* +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build an Association model by using the Apriori algorithm. +* +* Test Model: +* Association rules do not have a predefined test metric. Two indirect +* measures of modeling success are: +* +* 1. Number of Rules generated: The optimal number of rules is application +* dependent. In general, an overwhelming number of rules is undesirable for +* user interpretation. More rules take longer to compute, and also consume +* storage and CPU cycles. You should avoid too many rules by increasing the +* value for support. +* +* 2. Relevance of rules: This can be determined only by +* user inspection of rules, since it is application dependent. Ideally, we +* want to find rules with high confidence and with non-obvious patterns. The +* value for confidence is an indicator of the strength of the rule - so you +* could set the confidence value high in conjunction with support and see if +* you get high quality rules. +* +* 3. Frequent itemsets provide an insight into co-occurrence of items. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +public class + +dmardemo + extends Object +{ + //Connection related data members + private static Connection m_dmeConn; + private static ConnectionFactory m_dmeConnFactory; + //Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static AssociationSettingsFactory m_assoFactory; + private static RulesFilterFactory m_filterFactory; + private static BuildTaskFactory m_buildFactory; + private static String m_pdsName = "arBuildData_jdm"; + private static String m_settingsName = "arSettings_jdm"; + private static String m_modelName = "arModel_jdm"; + private static String m_taskName = "arBuildTask_jdm"; + // Global constants + private static DecimalFormat m_df = new DecimalFormat("##.####"); + // Default settings + private static int m_maxRuleLength = 20; + private static double m_minSupport = 0.1; + private static double m_minConfidence = 0.1; + + public static void main(String[] args) + { + try + { + if ((args.length != 0) & (args.length != 3)) + { + System.out.println("Usage: java dmardemo "); + System.out.println(" or: java dmardemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + // 1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@" + uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Create input view + createInputView(); + // 5. Build a model + buildModel(); + } + catch (Exception anyExp) + { + anyExp.printStackTrace(System.out); + } + finally + { + try + { + //6. Logout from the Data Mining Engine + m_dmeConn.close(); + } + catch (Exception anyExp1) + { + } //Ignore + } + } + + public static void initFactories() + throws JDMException + { + m_pdsFactory = + (PhysicalDataSetFactory) m_dmeConn.getFactory("javax.datamining.data.PhysicalDataSet"); + m_paFactory = + (PhysicalAttributeFactory) m_dmeConn.getFactory("javax.datamining.data.PhysicalAttribute"); + m_assoFactory = + (AssociationSettingsFactory) m_dmeConn.getFactory("javax.datamining.association.AssociationSettings"); + m_buildFactory = + (BuildTaskFactory) m_dmeConn.getFactory("javax.datamining.task.BuildTask"); + m_filterFactory = + (RulesFilterFactory) m_dmeConn.getFactory("javax.datamining.association.RulesFilter"); + } + + /** + * This method illustrates preparation of the data for build operations by + * using Common item removal, Data format transformation, and binning + * transformations. + * + * Transformations: + * 1. Common item removal: Skipped since the dataset is small. + * + * 2. Column format transformation: Converted a table column into a nested + * table column format, so each record contains a nested table column + * holding a collection of items that correspond to a given customer id. + * + * The following table illustrates customer attributes available for building + * the mining model and data characteristics. + * + * COLUMN_NAME DATA_TYPE DISTINCT NUMBER OF ROWS + * ------------------ --------- -------- -------------- + * CUST_ID NUMBER 940 2804 + * PROD_NAME VARCHAR2(50) 14 2804 + * HAS_IT NUMBER 1 2804 + * + * Unprepared Data ---> Prepared(nested table column) Data + * -------------------- ---------------------------------- + * SALES_TRANS_CUST_V SALES_TRANS_CUST_AR_V + */ + public static void createInputView() + throws JDMException + { + System.out.println("--- Create AR model build input view 'SALES_TRANS_CUST_V' ---"); + boolean isOutputAsView = false; + String inputDataURI = null; + String outputDataURI = null; + + // 1. Create the database view in a transactional format + // that joins customers sales transactions table SH.SALES + // with the products table SH.PRODUCTS that contains + // the product name. In this example 4500 customers transactions + // are taken as input. + isOutputAsView = true; + inputDataURI = "SH.SALES a, SH.PRODUCTS b"; + outputDataURI = "SALES_TRANS_CUST_V"; + String createView = + "CREATE VIEW SALES_TRANS_CUST_V AS " + " SELECT cust_id, prod_name, 1 has_it " + + " FROM (SELECT a.cust_id, b.prod_name " + + " FROM SH.SALES a, SH.PRODUCTS b " + + " WHERE a.prod_id = b.prod_id AND " + + " a.cust_id between 100001 AND 104500) " + + " GROUP BY cust_id, prod_name "; + + // Execute the sql statement + java.sql.Connection dbConn = + ((OraConnection) m_dmeConn).getDatabaseConnection(); + PreparedStatement pStmt = null; + try + { + pStmt = dbConn.prepareStatement(createView); + pStmt.executeQuery(); + } + catch (Exception anySqlExp) + { + anySqlExp.printStackTrace(); // Ignore + } + finally + { + try + { + pStmt.close(); + } + catch (Exception ex) + { + } + ; // Ignore + } + + // 2. Convert the transactional view created in the previous step + // "SALES_TRANS_CUST_V" to a nested table based view that + // represents the transactions by a customer is stored as a + // nested table, in this new view there will be one record per + // customer in the main view and this record contains the + // products purchased as a nested view + isOutputAsView = true; + inputDataURI = "SALES_TRANS_CUST_V"; + outputDataURI = "SALES_TRANS_CUST_AR_V"; + String caseId = "CUST_ID"; + String originalColumn = "PROD_NAME"; + String newNestedColumn = "CUSTPRODS"; + String createNestedColumn = + "CREATE VIEW SALES_TRANS_CUST_AR_V AS " + "SELECT CUST_ID, " + + "CAST(COLLECT( " + + " DM_Nested_Numerical(SUBSTR(PROD_NAME, 1, 30), has_it) " + + " ) AS DM_Nested_Numericals) CUSTPRODS " + + "FROM SALES_TRANS_CUST_V " + "GROUP BY CUST_ID"; + + // Execute the sql statement + try + { + pStmt = dbConn.prepareStatement(createNestedColumn); + pStmt.executeQuery(); + } + catch (Exception anySqlExp) + { + anySqlExp.printStackTrace(); // Ignore + } + finally + { + try + { + pStmt.close(); + } + catch (Exception ex) + { + } + ; // Ignore + } + } + + /** + * This method illustrates how to build an association mining model + * using SALES_TRANS_CUST_AR_V dataset and mining function settings. + */ + public static void buildModel() + throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Build Model ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = + m_pdsFactory.create("SALES_TRANS_CUST_AR_V", false); + PhysicalAttribute pa = + m_paFactory.create("CUST_ID", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + buildData.addAttribute(pa); + m_dmeConn.saveObject(m_pdsName, buildData, false); + // 2. Create & save Mining Function Settings + // Create AssociationSettings + AssociationSettings buildSettings = m_assoFactory.create(); + // + // Association Rules in ODM works best on sparse data - i.e. data where + // the average number of attributes/items associated with a given case is + // a small percentage of the total number of possible attributes/items. + // This is true of most market basket datasets where an average customer + // purchases only a small subset of items from a fairly large inventory + // in the store. + // + // In this demo data set, we will compute density of data and + // average number of products purchased per customer, to determine + // the algorithm settings value. + // + // Compute the density of data + // COUNT(*) / COUNT(DISTINCT CUST_ID) * COUNT(DISTINCT PROD_NAME) + // 2804 / 940 * 14 --> 2.2 (22%) + // + // Compute the average number of products purchased per customer + // AVG (SELECT COUNT(PROD_NAME) + // FROM SALES_TRANS_CUST_AR_V + // GROUP BY CUST_ID) --> 2.98 (3 items) + // + // For sparse data, it is common to have a density below 1%, and AR + // typically performs well with sparse data. The above dataset, + // SALES_TRANS_CUST_AR_V, is moderately dense, 22%, (because of the + // aggregation), and we have to tune the AR parameters in accordance. + // + // Start with + // + m_minSupport = 10.0f; // 10% + m_minConfidence = 10.0f; // 10% + // Since the average number of products purchased per customer is 2.98, so + // we will set Max Rule Length (i.e. Items) = 3 + m_maxRuleLength = 3; + buildSettings.setMinSupport(m_minSupport); + buildSettings.setMinConfidence(m_minConfidence); + buildSettings.setMaxRuleLength(m_maxRuleLength); + m_dmeConn.saveObject(m_settingsName, buildSettings, true); + // 3. Create, save & execute Build Task + BuildTask buildTask = //Build data specification + //Mining function settings name + //Mining model name + m_buildFactory.create(m_pdsName, m_settingsName, m_modelName); + buildTask.setDescription(m_taskName); + executeTask(buildTask, m_taskName); + // 4. Restore the model from the data mining server + AssociationModel model = + (AssociationModel) m_dmeConn.retrieveObject(m_modelName, + NamedObject.model); + // 5. Explore the details of the restored model + // Display model build settings + AssociationSettings retrievedBuildSettings = + (AssociationSettings) model.getBuildSettings(); + if (buildSettings == null) + System.out.println("Failure to restore build settings."); + else + displayBuildSettings(retrievedBuildSettings, m_settingsName); + // Display the rules + displayAssociationRules(model); + } + + /** + * This method stores the given task with the specified name in the DMS + * and submits the task for asynchronous execution in the DMS. After + * completing the task successfully it returns true. If there is a task + * failure, then it prints error description and returns false. + * + * @param taskObj task object + * @param taskName name of the task + * + * @return boolean returns true when the task is successful + */ + public static boolean executeTask(Task taskObj, String taskName) + throws JDMException + { + boolean isTaskSuccess = false; + m_dmeConn.saveObject(taskName, taskObj, true); + ExecutionHandle execHandle = m_dmeConn.execute(taskName); + System.out.print(taskName + " is started, please wait. "); + //Wait for completion of the task + ExecutionStatus status = + execHandle.waitForCompletion(Integer.MAX_VALUE); + //Check the status of the task after completion + isTaskSuccess = status.getState().equals(ExecutionState.success); + if (isTaskSuccess) + { + //Task completed successfully + System.out.println(taskName + " is successful."); + } + else + { //Task failed + System.out.println(taskName + " is failed.\nFailure Description: " + + status.getDescription()); + } + return isTaskSuccess; + } + + private static void displayBuildSettings(AssociationSettings assocSettings, + String buildSettingsName) + { + System.out.println("BuildSettings Details from the " + + buildSettingsName + " table:"); + displayTable(buildSettingsName, "", "order by SETTING_NAME"); + System.out.println("BuildSettings Details from the " + + buildSettingsName + + " model build settings object:"); + String objName = assocSettings.getName(); + if (objName != null) + System.out.println("Name = " + objName); + String objDescription = assocSettings.getDescription(); + if (objDescription != null) + System.out.println("Description = " + objDescription); + java.util.Date creationDate = assocSettings.getCreationDate(); + String creator = assocSettings.getCreatorInfo(); + AlgorithmSettings algoSettings = assocSettings.getAlgorithmSettings(); + if (algoSettings == null) + System.out.println("Failure: assocSettings.getAlgorithmSettings() returns null"); + MiningAlgorithm algo = algoSettings.getMiningAlgorithm(); + if (algo != null) + System.out.println("Algorithm Name: " + algo.name()); + MiningFunction function = assocSettings.getMiningFunction(); + if (function == null) + System.out.println("Failure: assocSettings.getMiningFunction() returns null"); + System.out.println("Function Name: " + function.name()); + // List of association settings + int intValue = assocSettings.getMaxRuleLength(); + System.out.println("Max Number of Rules: " + intValue); + Double doubleValue = assocSettings.getMinConfidence(); + System.out.println("Min Confidence: " + + m_df.format(doubleValue.doubleValue())); + doubleValue = assocSettings.getMinSupport(); + System.out.println("Min Support: " + + m_df.format(doubleValue.doubleValue())); + } + + private static void displayTable(String tableName, String whereCause, + String orderByColumn) + { + StringBuffer emptyCol = new StringBuffer(" "); + java.sql.Connection dbConn = + ((OraConnection) m_dmeConn).getDatabaseConnection(); + PreparedStatement pStmt = null; + ResultSet rs = null; + try + { + pStmt = + dbConn.prepareStatement("SELECT * FROM " + tableName + " " + whereCause + + " " + orderByColumn); + rs = pStmt.executeQuery(); + ResultSetMetaData rsMeta = rs.getMetaData(); + int colCount = rsMeta.getColumnCount(); + StringBuffer header = new StringBuffer(); + System.out.println("Table : " + tableName); + // Build table header + for (int iCol = 1; iCol <= colCount; iCol++) + { + String colName = rsMeta.getColumnName(iCol); + header.append(emptyCol.replace(0, colName.length(), colName)); + emptyCol = new StringBuffer(" "); + } + System.out.println(header.toString()); + // Write table data + while (rs.next()) + { + StringBuffer rowContent = new StringBuffer(); + for (int iCol = 1; iCol <= colCount; iCol++) + { + int sqlType = rsMeta.getColumnType(iCol); + Object obj = rs.getObject(iCol); + String colContent = null; + + if (obj instanceof java.lang.Number) + { + try + { + BigDecimal bd = (BigDecimal) obj; + if (bd.scale() > 5) + { + colContent = m_df.format(obj); + } + else + { + colContent = bd.toString(); + } + } + catch (Exception anyExp) + { + colContent = m_df.format(obj); + } + } + else + { + if (obj == null) + colContent = "NULL"; + else + { + colContent = obj.toString(); + try + { + Double testDouble = new Double(colContent); + colContent = m_df.format(testDouble); + } + catch (Exception e) + { + } + } + } + rowContent.append(" " + + emptyCol.replace(0, colContent.length(), colContent)); + emptyCol = new StringBuffer(" "); + } + System.out.println(rowContent.toString()); + } + } + catch (Exception anySqlExp) + { + anySqlExp.printStackTrace(); + } // Ignore + finally + { + try + { + rs.close(); + pStmt.close(); + } + catch (Exception ex) + { + } + ; // Ignore + } + } + + /** + * Displays rules from association model. + */ + private static void displayAssociationRules(AssociationModel model) + throws JDMException + { + String modelName = model.getName(); + System.out.println("Model Name: " + modelName); + // DISPLAY TOP-10 FREQUENT ITEMSETS + // + System.out.println("================================"); + System.out.println("Display Top-10 frequent itemsets"); + System.out.println("================================"); + // 1. Retrieve item sets collection that is already sorted internally: + // Order by support desc, + // itemset_id asc, + // column_value asc, + // number_of_items asc + Collection itemSets = model.getItemsets(); + Iterator iItemSets = itemSets.iterator(); + // 2. Display the top 10 item sets + int count = 0; + while (iItemSets.hasNext()) + { + if (count > 10) + break; + else + count = count + 1; + + OraItemset itemSet = (OraItemset) iItemSets.next(); + Object[] items = itemSet.getItems(); + String itemList = ""; + for (int i = 0; i < items.length; i++) + itemList = items[i] + ","; + System.out.println(itemList + " (support=" + + m_df.format(itemSet.getSupport()) + + ", number of items=" + itemSet.getSize() + ")"); + } + + // DISPLAY TOP-10 ASSOCIATION RULES + // + System.out.println("================================"); + System.out.println("Display Top-10 association rules"); + System.out.println("================================"); + // 1. Set order by confidence DESC, support DESC + OraRulesFilter filter = (OraRulesFilter) m_filterFactory.create(); + filter.setOrderingCondition(new RuleProperty[] + { RuleProperty.confidence, RuleProperty.support }, new SortOrder[] + { SortOrder.descending, SortOrder.descending }); + // 2. Set to return the first 10 rules only + filter.setMaxNumberOfRules(10); + // 3. Retrieve rules + Collection rules = model.getRules(filter); + Iterator iRules = rules.iterator(); + while (iRules.hasNext()) + { + OraAssociationRule rule = (OraAssociationRule) iRules.next(); + Itemset antecedent = rule.getAntecedent(); + Object[] ante_items = antecedent.getItems(); + // sort the items in antecedent to produce deterministic order of items + TreeSet sortedSet = new TreeSet(); + for (int i = 0; i < ante_items.length; i++) + sortedSet.add(ante_items[i]); + Iterator sortedI = sortedSet.iterator(); + while (sortedI.hasNext()) + System.out.print(sortedI.next() + " "); + Itemset consequent = rule.getConsequent(); + Object[] cons_items = consequent.getItems(); + System.out.println("==> " + cons_items[0] + " (support=" + + m_df.format(rule.getSupport()) + ", confidence=" + + m_df.format(rule.getConfidence()) + ")"); + } + } + + public static void clean() + { + java.sql.Connection dbConn = + ((OraConnection) m_dmeConn).getDatabaseConnection(); + Statement stmt = null; + // Drop prepared views + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP VIEW SALES_TRANS_CUST_V"); + } + catch (SQLException anySqlExp) + { + } // Ignore + finally + { + try + { + stmt.close(); + } + catch (Exception anySqlExp) + { + } + } + // Drop prepared views + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP VIEW SALES_TRANS_CUST_AR_V"); + } + catch (SQLException anySqlExp) + { + } // Ignore + finally + { + try + { + stmt.close(); + } + catch (Exception anySqlExp) + { + } + } + //Drop the model + try + { + m_dmeConn.removeObject(m_modelName, NamedObject.model); + } + catch (JDMException jdmExp) + { + } + // drop the build settings + try + { + m_dmeConn.removeObject(m_settingsName, NamedObject.buildSettings); + } + catch (JDMException jdmExp) + { + } + // drop the PDS + try + { + m_dmeConn.removeObject(m_pdsName, NamedObject.physicalDataSet); + } + catch (JDMException jdmExp) + { + } + // drop the build task + try + { + m_dmeConn.removeObject(m_taskName, NamedObject.task); + } + catch (JDMException jdmExp) + { + } + } +} diff --git a/dmardemo.sql b/dmardemo.sql new file mode 100644 index 0000000..9b3792c --- /dev/null +++ b/dmardemo.sql @@ -0,0 +1,497 @@ +Rem +Rem $Header: dmardemo.sql 04-feb-2008.19:09:11 ramkrish Exp $ +Rem +Rem dmardemo.sql +Rem +Rem Copyright (c) 2003, 2008, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmardemo.sql - Sample program for the DBMS_DATA_MINING package. +Rem +Rem DESCRIPTION +Rem This script creates an association model +Rem using the Apriori algorithm +Rem and data in the SH (Sales History) schema in the RDBMS. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ramkrish 02/04/08 - Add Transactional Input samples +Rem ramkrish 06/14/07 - remove commit after settings +Rem ramkrish 10/25/07 - replace deprecated get_model calls with catalog +Rem queries +Rem dmukhin 12/13/06 - bug 5557333: AR scoping +Rem ktaylor 07/11/05 - minor edits to comments +Rem ramkrish 03/04/05 - 4222328: fix sales_trans queries for dupl custids +Rem jcjeon 01/18/05 - add column format +Rem ramkrish 09/16/04 - add data analysis and comments/cleanup +Rem ramkrish 07/30/04 - lrg 1726339 - comment out itemsetid +Rem hash-based group by no longer guarantees +Rem ordered itemset ids +Rem xbarr 06/25/04 - xbarr_dm_rdbms_migration +Rem mmcracke 12/11/03 - Remove RuleID from results display +Rem ramkrish 10/20/03 - ramkrish_txn109085 +Rem ramkrish 10/02/03 - Creation + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET linesize 140 +SET echo ON + +-- ODM API now accepts data both in relational (2D) form, and +-- transactional form for Association Rules (only). + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM USING RELATIONAL (i.e. 2D) INPUT +----------------------------------------------------------------------- +-- Find the associations between items bought by customers + +----------------------------------------------------------------------- +-- SET UP AND ANALYZE THE DATA +----------------------------------------------------------------------- + +-- Cleanup old dataset for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP VIEW sales_trans_cust'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW sales_trans_cust_ar'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +------- +-- DATA +------- +-- The data for this sample is composed from a small subset of +-- sales transactions in the SH schema - listing the (multiple) +-- items bought by a set of customers with ids in the range +-- 100001-104500. Note that this data is based on customer id, +-- not basket id (as in the case of true market basket data). +-- But in either case, it is useful to remove duplicate occurrences +-- (e.g. customer buys two cans of milk in the same visit, or buys +-- boxes of the same cereal in multiple, independent visits) +-- of items per customer or per basket, since what we care about +-- is just the presence/absence of a given item per customer/basket +-- id to compute the rules. Hence the DISTINCT in the view definition. +-- +-- Market basket or sales datasets are transactional in nature, +-- and form dimension tables in a typical data warehouse. +-- +-- ODM API now accepts data both in relational (2D) form, and +-- transactional form for Association Rules (only, not for other algorithms). +-- +-- We present such transactional data to the API using an Object View +-- that contains a nested table column holding a collection of items +-- that correspond to a given customer id. +-- +-- For clarity, these views are shown just before the model build statement. +-- +CREATE VIEW sales_trans_cust AS +SELECT DISTINCT cust_id, prod_name, 1 has_it +FROM (SELECT a.cust_id, b.prod_name + FROM sh.sales a, sh.products b + WHERE a.prod_id = b.prod_id AND + a.cust_id between 100001 AND 104500) +ORDER BY cust_id, prod_name; + +----------- +-- ANALYSIS +----------- +-- Association Rules in ODM works best on sparse data - i.e. data where +-- the average number of attributes/items associated with a given case is +-- a small percentage of the total number of possible attributes/items. +-- This is true of most market basket datasets where an average customer +-- purchases only a small subset of items from a fairly large inventory +-- in the store. +-- +-- This section provides a rough outline of the analysis to be performed +-- on data used for Association Rules model build. +-- +-- 1. Compute the cardinality of customer id and product (940, 11) +SELECT COUNT(DISTINCT cust_id) cc, COUNT(DISTINCT prod_name) cp + FROM sales_trans_cust; + +-- 2. Compute the density of data (27.08) +column density format a18 +SELECT TO_CHAR((100 * ct)/(cc * cp), 99.99) density + FROM (SELECT COUNT(DISTINCT cust_id) cc, + COUNT(DISTINCT prod_name) cp, + COUNT(*) ct + FROM sales_trans_cust); + +-- 3. Common items are candidates for removal during model build, because +-- if a majority of customers have bought those items, the resulting +-- rules do not have much value. Find out most common items. For example, +-- the query shown below determines that Mouse_Pad is most common (303). +-- +-- Since the dataset is small, we will skip common item removal. +-- +column prod_name format a40 +SELECT prod_name, count(prod_name) cnt + FROM sales_trans_cust +GROUP BY prod_name +ORDER BY cnt DESC, prod_name DESC; + +-- 4. Compute the average number of products purchased per customer (2.98) +-- 3 out of 11 corresponds to the density we computed earlier. +-- +column avg_num_prod format a16 +SELECT TO_CHAR(AVG(cp), 999.99) avg_num_prod + FROM (SELECT COUNT(prod_name) cp + FROM sales_trans_cust + GROUP BY cust_id); + +-- 5. For sparse data, it is common to have a density below 1%, and +-- AR typically performs well with sparse data. The above dataset +-- is moderately dense (because of the aggregation), and we have +-- to tune the AR parameters in accordance. Start with +-- +-- - Min Support = 0.1 +-- - Min Confidence = 0.1 +-- - Max Rule Length (i.e. Items) = 3 + +-- 6. Market basket or sales datasets are transactional in nature, +-- and form dimension tables in a typical DW. We present such +-- transactional data to the API using an Object View that contains +-- a nested table column holding a collection of items that +-- correspond to a given customer id. +-- +CREATE VIEW sales_trans_cust_ar AS +SELECT cust_id, + CAST(COLLECT(DM_Nested_Numerical( + prod_name, has_it)) + AS DM_Nested_Numericals) custprods + FROM sales_trans_cust +GROUP BY cust_id; + +----------------------------------------------------------------------- +-- BUILD THE MODEL +----------------------------------------------------------------------- + +-------------------------------- +-- PREPARE BUILD (TRAINING) DATA +-- +-- Data for AR modeling may need binning if it contains numerical +-- data, and categorical data with high cardinality. See dmabdemo.sql +-- for an example on quantile binning. + +------------------- +-- SPECIFY SETTINGS +-- +-- Cleanup old settings table for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE ar_sh_sample_settings'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- The default (and only) algorithm for association rules is +-- Apriori AR. However, we need a settings table because we +-- intend to override the default Min Support, Min Confidence, +-- Max items +-- +set echo off +CREATE TABLE ar_sh_sample_settings ( + setting_name VARCHAR2(30), + setting_value VARCHAR2(30)); +set echo on + +BEGIN + INSERT INTO ar_sh_sample_settings VALUES + (dbms_data_mining.asso_min_support,0.1); + INSERT INTO ar_sh_sample_settings VALUES + (dbms_data_mining.asso_min_confidence,0.1); + INSERT INTO ar_sh_sample_settings VALUES + (dbms_data_mining.asso_max_rule_length,3); + COMMIT; +END; +/ + +--------------------- +-- CREATE A NEW MODEL +-- +-- Cleanup old model with same name for repeat runs +BEGIN DBMS_DATA_MINING.DROP_MODEL('AR_SH_sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- Build a new AR model +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'AR_SH_sample', + mining_function => DBMS_DATA_MINING.ASSOCIATION, + data_table_name => 'sales_trans_cust_ar', + case_id_column_name => 'cust_id', + settings_table_name => 'ar_sh_sample_settings'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30 +column setting_value format a30 +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'AR_SH_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +-- NOT APPLICABLE +-- The model signature is applicable only for predictive models. +-- Association models are descriptive models that are summaries of data. + +----------------------------------------------------------------------- +-- TEST THE MODEL +----------------------------------------------------------------------- + +-- Association rules do not have a predefined test metric. +-- +-- Two indirect measures of modeling success are: +-- +-- 1. Number of Rules generated: The optimal number of rules is +-- application dependent. In general, an overwhelming number of +-- rules is undesirable for user interpretation. More rules take +-- longer to compute, and also consume storage and CPU cycles. +-- You avoid too many rules by increasing the value for support. +-- +-- 2. Relevance of rules +-- This can be determined only by user inspection of rules, since +-- it is application dependent. Ideally, we want to find rules with +-- high confidence and with non-obvious patterns. The value for +-- confidence is an indicator of the strength of the rule - so +-- you could set the confidence value high in conjunction with +-- support and see if you get high quality rules. +-- +-- 3. Frequent itemsets provide an insight into co-occurrence of items. + +----------------------------------------------------------------------- +-- DISPLAY MODEL CONTENT +----------------------------------------------------------------------- + +----------------------------------- +-- DISPLAY TOP-10 FREQUENT ITEMSETS +-- +break on itemset_id skip 1; +column item format a40 +SELECT item, support, number_of_items + FROM (SELECT I.attribute_subname AS item, + F.support, + F.number_of_items + FROM TABLE(DBMS_DATA_MINING.GET_FREQUENT_ITEMSETS( + 'AR_SH_sample', + 10)) F, + TABLE(F.items) I + ORDER BY number_of_items, support, item); + +----------------------------------- +-- DISPLAY TOP-10 ASSOCIATION RULES +-- ordered by confidence DESC, support DESC +-- +SET line 300 +column antecedent format a140 +column consequent format a140 +SELECT ROUND(rule_support,4) support, +-- rule_id, + ROUND(rule_confidence,4) confidence, + antecedent, + consequent + FROM TABLE(DBMS_DATA_MINING.GET_ASSOCIATION_RULES('AR_SH_sample', 10)) + ORDER BY confidence DESC, support DESC; + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM USING TRANSACTIONAL (tuple/triple) INPUT +----------------------------------------------------------------------- + +-- ODM API accepts data both in relational (2D) form, and +-- transactional form for Association Rules (only). +-- +-- The transactional input is a two column table of the form: +-- (case_id, item_id) +-- or a three column table of the form: +-- (item_id, transaction_id, transaction_value) +-- +-- case_id can be a string/categorical or Numerical +-- Item Id can be categorical or numerical +-- Item Value can be categorical or numerical +-- +-- Example of a two column transactional table is: +-- (case_id, item_id) +-- (1, 1) +-- (1, 4) +-- (2, 2) +-- or +-- (1, apple) +-- (1, pear) +-- (2, banana) +-- +-- Example of a three column transactional table is: +-- (case_id, item_id, item_val) +-- (1, apple, 2) +-- (1, apple, 4) +-- (2, banana, 1) +-- (2, banana, 2) +-- or +-- (1, wine, red) +-- (1, wine, white) +-- (2, cheese, swiss) +-- (2, cheese, provolone) +-- which allows you to treat different (item_id, val) pairings +-- against a given case-id essentially as different, unique items +-- in the itemset +-- + +BEGIN EXECUTE IMMEDIATE 'DROP VIEW sales_str_xnal'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW sales_xnal_cat_sval'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN DBMS_DATA_MINING.DROP_MODEL('AR_SH_Sample_str_xnal'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN DBMS_DATA_MINING.DROP_MODEL('AR_SH_Sample_xnal_sval'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +--------------------------------------------------------- +-- Add settings for Transaction Input - the presence +-- of an Item Id column specification indicates to the +-- API that the input is transactional +-- +BEGIN + INSERT INTO ar_sh_sample_settings VALUES + (dbms_data_mining.odms_item_id_column_name, 'ITEM_ID'); +END; +/ + +----------------------------------------- +-- Transactional input (case_id, item_id) +-- String Case-ID, Categorical Item_id +-- +CREATE VIEW sales_str_xnal AS +SELECT (TO_CHAR(cust_id) || '_String') AS cust_id, + prod_name AS item_id + FROM sales_trans_cust; + +---------------------------------------------- +-- Build AR model with transactional input +-- With String Case-ID, Categorical Item-Id +-- +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'AR_SH_Sample_str_xnal', + mining_function => DBMS_DATA_MINING.ASSOCIATION, + data_table_name => 'sales_str_xnal', + case_id_column_name => 'cust_id', + settings_table_name => 'ar_sh_sample_settings' + ); +END; +/ + +------------------------------------------------------------- +-- Display Top-10 Frequent Itemsets +-- Transactional input - String Case-Id, Categorical Item-Id +-- +break on itemset_id skip 1; +column item format a40 +SELECT item, support, number_of_items + FROM (SELECT I.attribute_subname AS item, + F.support, + F.number_of_items + FROM TABLE(DBMS_DATA_MINING.GET_FREQUENT_ITEMSETS( + 'AR_SH_Sample_str_xnal', + 10)) F, + TABLE(F.items) I + ORDER BY number_of_items, support, item); + +---------------------------------------------------------- +-- Display Top-10 Association Rules - Transactional input +-- Transactional input - String Case-Id, Categorical Item-Id +-- ordered by confidence DESC, support DESC +-- (Rule ID has been commented out because it is not a +-- repeatable ID - uncomment rule id in your run if needed) +-- +SET line 300 +column antecedent format a140 +column consequent format a140 +SELECT ROUND(rule_support,4) support, +-- rule_id, + ROUND(rule_confidence,4) confidence, + antecedent, + consequent + FROM TABLE(DBMS_DATA_MINING.GET_ASSOCIATION_RULES( + 'AR_SH_Sample_str_xnal', 10)) + ORDER BY confidence DESC, support DESC; + +--------------------------------------------------------- +-- Add settings for item Value +-- +BEGIN + INSERT INTO ar_sh_sample_settings VALUES + (dbms_data_mining.odms_item_value_column_name, 'ITEM_VAL'); + COMMIT; +END; +/ + +------------------------------------------------------------------ +-- Transactional input (case_id, item_id) with categorical item_id +-- Numeric Case_id, Categorical item_id, Categorical item_val +-- +CREATE VIEW sales_xnal_cat_sval AS +SELECT cust_id, + prod_name AS item_id, + prod_name AS item_val + FROM sales_trans_cust; + +---------------------------------------------- +-- Build AR model with transactional input +-- Numeric Case-Id, Categorical Item-Id, Categorical Item-val +-- +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'AR_SH_Sample_xnal_sval', + mining_function => DBMS_DATA_MINING.ASSOCIATION, + data_table_name => 'sales_xnal_cat_sval', + case_id_column_name => 'cust_id', + settings_table_name => 'ar_sh_sample_settings' + ); +END; +/ + +------------------------------------------------------------- +-- Display Top-10 Frequent Itemsets +-- Transactional input - Numeric Case-Id, Categorical Item-Id +-- +break on itemset_id skip 1; +column item format a40 +SELECT item, support, number_of_items + FROM (SELECT I.attribute_subname AS item, + F.support, + F.number_of_items + FROM TABLE(DBMS_DATA_MINING.GET_FREQUENT_ITEMSETS( + 'AR_SH_Sample_xnal_sval', + 10)) F, + TABLE(F.items) I + ORDER BY number_of_items, support, item); + +---------------------------------------------------------- +-- Display Top-10 Association Rules - Transactional input +-- Transactional input - +-- Numeric Case-Id, Categorical Item-Id, Categorical Item-val +-- ordered by confidence DESC, support DESC +-- (Rule ID has been commented out because it is not a +-- repeatable ID - uncomment rule id in your run if needed) +-- +SET line 300 +column antecedent format a140 +column consequent format a140 +SELECT ROUND(rule_support,4) support, +-- rule_id, + ROUND(rule_confidence,4) confidence, + antecedent, + consequent + FROM TABLE(DBMS_DATA_MINING.GET_ASSOCIATION_RULES( + 'AR_SH_Sample_xnal_sval', 10)) + ORDER BY confidence DESC, support DESC; diff --git a/dmdtdemo.sql b/dmdtdemo.sql new file mode 100644 index 0000000..00ee589 --- /dev/null +++ b/dmdtdemo.sql @@ -0,0 +1,334 @@ +Rem +Rem $Header: dmdtdemo.sql 25-oct-2007.11:35:28 ramkrish Exp $ +Rem +Rem dmdtdemo.sql +Rem +Rem Copyright (c) 2004, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmdtdemo.sql - Sample program for the DBMS_DATA_MINING package +Rem +Rem DESCRIPTION +Rem This script creates a classification model +Rem using the Decision Tree algorithm +Rem and data from the SH (Sales History) schema in the RDBMS. +Rem +Rem This program uses the PREDICTION_* functions for model scoring. +Rem +Rem NOTES +Rem +Rem MODIFIED (MM/DD/YY) +Rem ramkrish 06/14/07 - remove commit after settings +Rem ramkrish 10/25/07 - replace deprecated get_model calls with catalog +Rem queries +Rem jiawang 11/10/06 - Set pretty print +Rem ktaylor 07/11/05 - minor edits to comments +Rem ramkrish 01/28/05 - prediction column format fixes +Rem jcjeon 01/18/05 - add column format +Rem ramkrish 10/27/04 - add data analysis and comments/cleanup +Rem mjaganna 11/20/04 - remove the use of priors +Rem amozes 08/04/04 - singular dtree, plural prediction_details +Rem amozes 07/13/04 - amozes_bug-3756145 +Rem amozes 07/09/04 - Created +Rem + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET linesize 320 +SET echo ON +SET long 2000000000 + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM +----------------------------------------------------------------------- +-- Given demographic data about a set of customers, predict the +-- customer response to an affinity card program using a classifier +-- based on Decision Trees algorithm. + +----------------------------------------------------------------------- +-- SET UP AND ANALYZE THE DATA +----------------------------------------------------------------------- +-- The data for this sample is composed from base tables in SH Schema +-- (See Sample Schema Documentation) and presented through these views: +-- mining_data_build_v (build data) +-- mining_data_test_v (test data) +-- mining_data_apply_v (apply data) +-- (See dmsh.sql for view definitions). + +----------- +-- ANALYSIS +----------- +-- These are the factors to consider for data analysis in decision trees: +-- +-- 1. Missing Value Treatment for Predictors +-- +-- See dmsvcdem.sql for a definition of missing values, and the +-- steps to be taken for missing value imputation. +-- +-- Sparse data is not suitable for decision trees, but it will +-- accept sparse data nevertheless. +-- +-- Decision Tree implementation in ODM handles missing predictor +-- values (by penalizing predictors which have missing values) +-- and missing target values (by simply discarding records with +-- missing target values). +-- +-- 2. Outlier Treatment for Predictors for Build data +-- +-- See dmsvcdem.sql for a discussion on outlier treatment. +-- For decision trees, outlier treatment is not really necessary. +-- +-- 3. Binning high cardinality data +-- No data preparation for the types we accept is necessary - even +-- for high cardinality predictors. Preprocessing to reduce the +-- cardinality (e.g., binning) can improve the performance of the build, +-- but it could penalize the accuracy of the resulting model. +-- +----------------------------------------------------------------------- +-- BUILD THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old model with same name for repeat runs +BEGIN DBMS_DATA_MINING.DROP_MODEL('DT_SH_Clas_sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-------------------------------- +-- PREPARE BUILD (TRAINING) DATA +-- +-- The decision tree algorithm is very capable of handling data which +-- has not been specially prepared. For this example, no data preparation +-- will be performed. +-- + +------------------- +-- SPECIFY SETTINGS +-- +-- Cleanup old settings table objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE dt_sh_sample_settings'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE dt_sh_sample_cost'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-------------------------- +-- CREATE A SETTINGS TABLE +-- +-- The default classification algorithm is Naive Bayes. In order to override +-- this, create and populate a settings table to be used as input for +-- CREATE_MODEL. +-- +set echo off +CREATE TABLE dt_sh_sample_settings ( + setting_name VARCHAR2(30), + setting_value VARCHAR2(30)); +set echo on + +-- CREATE AND POPULATE A COST MATRIX TABLE +-- +-- A cost matrix is used to influence the weighting of misclassification +-- during model creation (and scoring). +-- See Oracle Data Mining Concepts Guide for more details. +-- +CREATE TABLE dt_sh_sample_cost ( + actual_target_value NUMBER, + predicted_target_value NUMBER, + cost NUMBER); +INSERT INTO dt_sh_sample_cost VALUES (0,0,0); +INSERT INTO dt_sh_sample_cost VALUES (0,1,1); +INSERT INTO dt_sh_sample_cost VALUES (1,0,8); +INSERT INTO dt_sh_sample_cost VALUES (1,1,0); + +BEGIN + -- Populate settings table + INSERT INTO dt_sh_sample_settings VALUES + (dbms_data_mining.algo_name, dbms_data_mining.algo_decision_tree); + INSERT INTO dt_sh_sample_settings VALUES + (dbms_data_mining.clas_cost_table_name, 'dt_sh_sample_cost'); + + -- Examples of other possible settings are: + --(dbms_data_mining.tree_impurity_metric, 'TREE_IMPURITY_ENTROPY') + --(dbms_data_mining.tree_term_max_depth, 5) + --(dbms_data_mining.tree_term_minrec_split, 5) + --(dbms_data_mining.tree_term_minpct_split, 2) + --(dbms_data_mining.tree_term_minrec_node, 5) + --(dbms_data_mining.tree_term_minpct_node, 0.05) +END; +/ + +--------------------- +-- CREATE A NEW MODEL +-- +-- Build a DT model +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'DT_SH_Clas_sample', + mining_function => dbms_data_mining.classification, + data_table_name => 'mining_data_build_v', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + settings_table_name => 'dt_sh_sample_settings'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30 +column setting_value format a30 +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'DT_SH_CLAS_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +column attribute_name format a40 +column attribute_type format a20 +SELECT attribute_name, attribute_type + FROM user_mining_model_attributes + WHERE model_name = 'DT_SH_CLAS_SAMPLE' +ORDER BY attribute_name; + +------------------------ +-- DISPLAY MODEL DETAILS +-- NOTE: The """ characters in this XML output are owing to +-- SQL*Plus behavior. Cut and paste this XML into a file, +-- and open the file in a browser to see correctly formatted XML. +-- +column dt_details format a320 +exec dbms_xdb_print.setPrintMode(dbms_xdb_print.PRINT_PRETTY, 2); +SELECT + dbms_data_mining.get_model_details_xml('DT_SH_Clas_sample') + AS DT_DETAILS +FROM dual; + +----------------------------------------------------------------------- +-- TEST THE MODEL +----------------------------------------------------------------------- + +-------------------- +-- PREPARE TEST DATA +-- +-- If the data for model creation has been prepared, then the data used +-- for testing the model must be prepared to the same scale in order to +-- obtain meaningful results. +-- In this case, no data preparation is necessary since model creation +-- was performed on the raw (unprepared) input. +-- + +------------------------------------ +-- COMPUTE METRICS TO TEST THE MODEL +-- +-- Other demo programs demonstrate how to use the PL/SQL API to +-- compute a number of metrics, including lift and ROC. This demo +-- only computes a confusion matrix and accuracy, but it does so +-- using the SQL data mining functions. +-- +-- In this example, we experiment with using the cost matrix +-- that was provided to the create routine. In this example, the +-- cost matrix reduces the problematic misclassifications, but also +-- negatively impacts the overall model accuracy. + +-- DISPLAY CONFUSION MATRIX WITHOUT APPLYING COST MATRIX +-- +SELECT affinity_card AS actual_target_value, + PREDICTION(DT_SH_Clas_sample USING *) AS predicted_target_value, + COUNT(*) AS value + FROM mining_data_test_v +GROUP BY affinity_card, PREDICTION(DT_SH_Clas_sample USING *) +ORDER BY 1,2; + +-- DISPLAY CONFUSION MATRIX APPLYING THE COST MATRIX +-- +SELECT affinity_card AS actual_target_value, + PREDICTION(DT_SH_Clas_sample COST MODEL USING *) + AS predicted_target_value, + COUNT(*) AS value + FROM mining_data_test_v +GROUP BY affinity_card, PREDICTION(DT_SH_Clas_sample COST MODEL USING *) +ORDER BY 1,2; + +-- DISPLAY ACCURACY WITHOUT APPLYING COST MATRIX +-- +SELECT ROUND(SUM(correct)/COUNT(*),4) AS accuracy + FROM (SELECT DECODE(affinity_card, + PREDICTION(DT_SH_Clas_sample USING *), 1, 0) AS correct + FROM mining_data_test_v); + +-- DISPLAY ACCURACY APPLYING THE COST MATRIX +-- +SELECT ROUND(SUM(correct)/COUNT(*),4) AS accuracy + FROM (SELECT DECODE(affinity_card, + PREDICTION(DT_SH_Clas_sample COST MODEL USING *), + 1, 0) AS correct + FROM mining_data_test_v); + +----------------------------------------------------------------------- +-- APPLY THE MODEL +----------------------------------------------------------------------- + +------------------ +-- BUSINESS CASE 1 +-- Find the 10 customers who live in Italy that are least expensive +-- to be convinced to use an affinity card. +-- +WITH +cust_italy AS ( +SELECT cust_id + FROM mining_data_apply_v + WHERE country_name = 'Italy' +ORDER BY PREDICTION_COST(DT_SH_Clas_sample, 1 COST MODEL USING *) ASC, 1 +) +SELECT cust_id + FROM cust_italy + WHERE rownum < 11; + +------------------ +-- BUSINESS CASE 2 +-- Find the average age of customers who are likely to use an +-- affinity card. +-- Include the build-time cost matrix in the prediction. +-- Only take into account CUST_MARITAL_STATUS, EDUCATION, and +-- HOUSEHOLD_SIZE as predictors. +-- Break out the results by gender. +-- +column cust_gender format a12 +SELECT cust_gender, COUNT(*) AS cnt, ROUND(AVG(age)) AS avg_age + FROM mining_data_apply_v + WHERE PREDICTION(dt_sh_clas_sample COST MODEL + USING cust_marital_status, education, household_size) = 1 +GROUP BY cust_gender +ORDER BY cust_gender; + +------------------ +-- BUSINESS CASE 3 +-- List ten customers (ordered by their id) along with likelihood and cost +-- to use or reject the affinity card (Note: while this example has a +-- binary target, such a query is useful in multi-class classification - +-- Low, Med, High for example). +-- +column prediction format 9; +SELECT T.cust_id, S.prediction, S.probability, S.cost + FROM (SELECT cust_id, + PREDICTION_SET(dt_sh_clas_sample COST MODEL USING *) pset + FROM mining_data_apply_v + WHERE cust_id < 100011) T, + TABLE(T.pset) S +ORDER BY cust_id, S.prediction; + +------------------ +-- BUSINESS CASE 4 +-- Find the segmentation (resulting tree node) for customers who +-- work in Tech support and are under 25. +-- +column education format a30; +column treenode format a40; +SELECT cust_id, education, + PREDICTION_DETAILS(dt_sh_clas_sample USING *) treenode + FROM mining_data_apply_v + WHERE occupation = 'TechSup' AND age < 25 +ORDER BY 1; diff --git a/dmdtxvlddemo.sql b/dmdtxvlddemo.sql new file mode 100644 index 0000000..66a2c7a --- /dev/null +++ b/dmdtxvlddemo.sql @@ -0,0 +1,246 @@ +Rem +Rem $Header: dmdtxvlddemo.sql 15-jun-2007.18:38:59 ramkrish Exp $ +Rem +Rem dmdtxvlddemo.sql +Rem +Rem Copyright (c) 2005, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmdtxvlddemo.sql - Sample program for the DBMS_DATA_MINING package. +Rem +Rem DESCRIPTION +Rem This script demonstrates the use of cross-validation for evaluating +Rem decision tree models when the amount of data available for training +Rem and testing is relatively small. Also demonstrates the desirability +Rem of using as much +Rem of the data as possible for building as well as testing models. +Rem +Rem Cross validation is a generic technique, and can be utilized for +Rem evaluating other algorithms as well with suitable modifications +Rem to settings. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ramkrish 06/14/07 - remove commit after settings +Rem ktaylor 07/11/05 - Minor edits to comments +Rem mjaganna 02/10/05 - mjaganna_xvalidate_demo +Rem mjaganna 01/28/05 - Created +Rem + +SET SERVEROUTPUT ON +SET ECHO OFF +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET long 2000000000 + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM +----------------------------------------------------------------------- +-- Given demographic data about a set of customers, compute the accuracy +-- of predictions for customer response to an affinity card program +-- using a classifier based on Decision Trees algorithm. +-- +-- This demo should be viewed as an extension of the scenario +-- described in dmdtdemo.sql. We perform 10 fold cross-validation +-- using the training data set alone. + +------------------- +-- SPECIFY SETTINGS +-- +-- Cleanup old settings table objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE dt_sh_sample_settings'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-------------------------- +-- CREATE A SETTINGS TABLE +-- +-- The default classification algorithm is Naive Bayes. In order to override +-- this, create and populate a settings table to be used as input for +-- CREATE_MODEL. +-- +CREATE TABLE dt_sh_sample_settings ( + setting_name VARCHAR2(30), + setting_value VARCHAR2(30)); + +DECLARE + nfolds NUMBER; + maxbucket NUMBER; -- max buckets for ORA_HASH() + iter NUMBER; -- loop itarator + tgtname VARCHAR2(30); -- target column name + tgtval NUMBER; -- class value (same type as target column) + case_id VARCHAR2(30); -- case_id column name + tabname VARCHAR2(30); -- training data + tabname_p VARCHAR2(30); -- "partitioned" training data + model_name VARCHAR2(30); -- model_name + sqltxt VARCHAR2(32767); + type dmdtcurtyp IS REF CURSOR; + tgtcur dmdtcurtyp; +BEGIN + nfolds := 10; -- number of folds (typically 10 fold) + maxbucket := nfolds-1; -- max buckets for ORA_HASH(); max of 9 means + -- 10 buckets in all 0..9 + + model_name := 'DT_SH_Clas_Xvld_tmp'; + tgtname := 'affinity_card'; + + --Training data, can be parametrized for general usage + tabname := 'mining_data_build_v'; + case_id := 'cust_id'; + + -- "partitioned" table + tabname_p := tabname || '_P'; + + -- Populate settings table + INSERT INTO dt_sh_sample_settings VALUES + (dbms_data_mining.algo_name, dbms_data_mining.algo_decision_tree); + + -- Examples of other possible settings are: + --(dbms_data_mining.tree_impurity_metric, 'TREE_IMPURITY_ENTROPY') + --(dbms_data_mining.tree_term_max_depth, 5) + --(dbms_data_mining.tree_term_minrec_split, 5) + --(dbms_data_mining.tree_term_minpct_split, 2) + --(dbms_data_mining.tree_term_minrec_node, 5) + --(dbms_data_mining.tree_term_minpct_node, 0.05) + BEGIN EXECUTE IMMEDIATE 'DROP TABLE dmdtxvld_c'; + EXCEPTION WHEN OTHERS THEN NULL; END; + + -- The column type of the actual and predicted should be the same as the + -- target column, in this case it happens to be NUMBER + EXECUTE IMMEDIATE + 'CREATE TABLE dmdtxvld_c (' || + 'iter NUMBER, actual NUMBER(10), predicted NUMBER(10), count NUMBER)'; + + -- Create "partitioned" table. A new table is created which tags the rows + -- with a partition number using column 'pn' + -- + -- Drop if already exists + BEGIN EXECUTE IMMEDIATE 'DROP TABLE '|| tabname_p; + EXCEPTION WHEN OTHERS THEN NULL; END; + + -- Instances of each class are partitioned nfolds ways + sqltxt := 'CREATE TABLE ' || tabname_p || ' AS '; + + -- Open tgtcur using tgtname,tabname; + OPEN tgtcur FOR 'SELECT DISTINCT(' || tgtname || ') FROM '|| tabname; + + -- Form SQL statement with as many UNION ALL's as distinct target values + FETCH tgtcur INTO tgtval; + sqltxt := sqltxt || + 'SELECT t1.*, MOD(ROWNUM,' || nfolds ||') pn ' || + 'FROM (SELECT t.*, ORA_HASH(rownum) randrow ' || + 'FROM ' || tabname || ' t ' || + 'WHERE ' || tgtname || ' = '''|| tgtval ||''' ORDER BY randrow) t1 '; + LOOP + FETCH tgtcur INTO tgtval; + EXIT WHEN tgtcur%NOTFOUND; + + sqltxt := sqltxt || + 'UNION ALL ' || + 'SELECT t1.*, MOD(ROWNUM,' || nfolds || ') pn ' || + 'FROM (SELECT t.*, ORA_HASH(rownum) randrow ' || + 'FROM ' || tabname || ' t ' || + 'WHERE ' || tgtname || ' = '''|| tgtval||''' ORDER BY randrow) t1 '; + END LOOP; + CLOSE tgtcur; + + -- execute the statement + EXECUTE IMMEDIATE sqltxt; + + -- Iterate nfolds times. Each time we use (nfolds-1)*R/nfolds rows for build + -- and the remaining R/nfolds rows for testing where R is the number of + -- training rows (instances) + -- + FOR iter IN 0..(nfolds-1) + LOOP + + -- Create the build view + -- All rows except those in current partition + EXECUTE IMMEDIATE + 'CREATE OR REPLACE VIEW xvld_tmp_bld_v AS ' || + 'SELECT * FROM ' || tabname_p || ' WHERE pn != '|| iter; + + -- We will test using rows in current partition + EXECUTE IMMEDIATE + 'CREATE OR REPLACE VIEW xvld_tmp_tst_v AS ' || + 'SELECT * FROM ' || tabname_p || ' WHERE pn = '|| iter; + + -- Build a model with this subset of data + BEGIN + -- Cleanup old model with same name for repeat runs + BEGIN DBMS_DATA_MINING.DROP_MODEL(model_name); + EXCEPTION WHEN OTHERS THEN NULL; END; + + -- Build a DT model + BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => model_name, + mining_function => dbms_data_mining.classification, + data_table_name => 'xvld_tmp_bld_v', + case_id_column_name => case_id, + target_column_name => tgtname, + settings_table_name => 'dt_sh_sample_settings'); + END; + + -- Apply the model, and compute confusion matrix + -- Confusion matrix is saved away in dmdtxvld_c table tagged by + -- iteration number iter + EXECUTE IMMEDIATE + 'INSERT INTO dmdtxvld_c ' || + 'SELECT ' || iter || ',' || tgtname || ' AS actual_target_value,' || + 'PREDICTION('|| model_name || ' USING *) ' || + 'AS predicted_target_value,' || + 'COUNT(*) AS value ' || + 'FROM xvld_tmp_tst_v ' || + 'GROUP BY ' || tgtname || ', PREDICTION('|| model_name|| ' USING *) ' || + 'ORDER BY 1,2'; + END; + END LOOP; + + -- Drop the model and partitioned table + -- remaining from the last iteration + BEGIN DBMS_DATA_MINING.DROP_MODEL(model_name); + EXCEPTION WHEN OTHERS THEN NULL; END; + + BEGIN EXECUTE IMMEDIATE 'DROP TABLE '|| TABNAME_P; + EXCEPTION WHEN OTHERS THEN NULL; END; + + BEGIN EXECUTE IMMEDIATE 'DROP VIEW XVLD_TMP_BLD_V'; + EXCEPTION WHEN OTHERS THEN NULL; END; + + BEGIN EXECUTE IMMEDIATE 'DROP VIEW XVLD_TMP_TST_V'; + EXCEPTION WHEN OTHERS THEN NULL; END; + +END; +/ + +-- Compute accuracy per iteration and the average for nfolds +-- from the confusion matrix +-- +EXEC DBMS_OUTPUT.PUT_LINE('Model accuracy by iteration'); + +SELECT a.iter, AVG(ROUND(correct/total,4)) AS accuracy + FROM (SELECT iter, SUM(count) AS correct + FROM dmdtxvld_c + WHERE actual = predicted + GROUP BY iter) a, + (SELECT iter, SUM(count) AS total + FROM dmdtxvld_c + GROUP BY iter) b + WHERE a.iter = b.iter +GROUP BY ROLLUP (a.iter); + +-- Show confusion matrix by iteration and rolled up across iterations +EXEC DBMS_OUTPUT.PUT_LINE('Confusion Matrix by iteration'); +SELECT * + FROM (SELECT iter, actual, predicted, SUM(count) count + FROM dmdtxvld_c + GROUP BY ROLLUP (actual, predicted, iter)) + WHERE predicted IS NOT NULL +ORDER BY iter, actual, predicted; diff --git a/dmexpimpdemo.java b/dmexpimpdemo.java new file mode 100644 index 0000000..dc208b2 --- /dev/null +++ b/dmexpimpdemo.java @@ -0,0 +1,388 @@ +// Copyright (c) 2001, 2006, Oracle. All rights reserved. +// File: dmexpimpdemo.java + +/** + * This sample program describes how to use the ODM Java API for importing + * an ODM model to the Data Mining Server(DMS) and exporting an ODM model from + * the DMS in the native format. + * To illustrate import/export, this program builds a NaiveBayes model + * using "IE_BINNED_DATA_BUILD_JDM" prepared dataset. After building the model, it + * exports the model to "nbexport.dump" file. After exporting the model + * it imports the exported model. + * + * NOTE: + * You need to create a writable directory called dm_dump before executing + * this demo program. + * For example: + * CREATE OR REPLACE DIRECTORY dm_dump AS '/user/temp'; + * GRANT READ, WRITE ON DIRECTORY dm_dump TO ; + *------------------------------------------------------------------------------ + * EXECUTING DEMO PROGRAM + *------------------------------------------------------------------------------ + * Refer to Oracle Data Mining Administrator's Guide + * for guidelines for executing this demo program. + */ +// Generic Java Imports +import java.sql.Statement; + +import java.util.HashMap; +import java.util.Map; +// Java Data Mining (JDM) standard imports +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.NamedObject; +import javax.datamining.algorithm.naivebayes.NaiveBayesSettings; +import javax.datamining.algorithm.naivebayes.NaiveBayesSettingsFactory; +import javax.datamining.base.Task; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.supervised.classification.ClassificationSettings; +import javax.datamining.supervised.classification.ClassificationSettingsFactory; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; +import javax.datamining.task.ExportTask; +import javax.datamining.task.ExportTaskFactory; +import javax.datamining.task.ImportTask; +import javax.datamining.task.ImportTaskFactory; +// Oracle Java Data Mining (JDM) implemented api imports +import oracle.dmt.jdm.base.OraBuildSettings; +import oracle.dmt.jdm.base.OraTask; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.task.OraTransformationTask; +import oracle.dmt.jdm.task.OraTransformationTaskFactory; +import oracle.dmt.jdm.transform.binning.OraBinningTransformFactory; +import oracle.dmt.jdm.transform.binning.OraBinningTransformImpl; +import oracle.dmt.jdm.transform.binning.OraCategoricalBinningType; +import oracle.dmt.jdm.transform.binning.OraNumericalBinningType; + +/** + * This sample program describes how to use the ODM Java API for importing + * an ODM model to the Data Mining Server(DMS) and exporting an ODM model from + * the DMS in the native format. + * To illustrate import/export, this program builds a NaiveBayes model + * using "IE_BINNED_DATA_BUILD_JDM" prepared dataset. After building the model, it + * exports the model to "nbexport.dump" file. After exporting the model + * it imports the exported model. + * + * NOTE: + * You need to create a writable directory called dm_dump before executing + * this demo program. + * For example: + * CREATE OR REPLACE DIRECTORY dm_dump AS '/user/temp'; + * GRANT READ, WRITE ON DIRECTORY dm_dump TO ; + *------------------------------------------------------------------------------ + * EXECUTING DEMO PROGRAM + *------------------------------------------------------------------------------ + * Refer to Oracle Data Mining Administrator's Guide + * for guidelines for executing this demo program. + */ +public class + +dmexpimpdemo + extends Object +{ + + //Connection related data members + private static javax.datamining.resource.Connection m_dmeConn = null; + private static javax.datamining.resource.ConnectionFactory m_dmeConnFactory = + null; + //Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory = null; + private static PhysicalAttributeFactory m_paFactory = null; + private static ClassificationSettingsFactory m_clasFactory = null; + private static NaiveBayesSettingsFactory m_nbFactory = null; + private static BuildTaskFactory m_buildFactory = null; + private static ExportTaskFactory m_exportFactory = null; + private static ImportTaskFactory m_importFactory = null; + private static OraBinningTransformFactory m_binningXformFactory = null; + private static OraTransformationTaskFactory m_xformTaskFactory = null; + + public static void main(String[] args) + { + try + { + if ((args.length != 0) & (args.length != 3)) + { + System.out.println("Usage: java dmexpimpdemo "); + System.out.println(" or: java dmexpimpdemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + // 1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@" + uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Create and save task to build a naive bayes model + buildModel(); + // 6. Create and save task to export the built model + exportModel(); + // 7. Create and save task to import the exported model + importModel(); + // 8. Execute the model build to start executing the sequenece of tasks + m_dmeConn.execute("nbExpImpBuildTask_jdm"); + // 9. Monitor process + monitorTaskExecutionProcess(); + } + catch (Exception anyExp) + { + anyExp.printStackTrace(System.out); + } + finally + { + try + { + // 8. Logout from the Data Mining Engine + m_dmeConn.close(); + } + catch (Exception anyExp1) + { + } //Ignore + } + } + + public static void initFactories() + throws JDMException + { + m_pdsFactory = + (PhysicalDataSetFactory) m_dmeConn.getFactory("javax.datamining.data.PhysicalDataSet"); + m_paFactory = + (PhysicalAttributeFactory) m_dmeConn.getFactory("javax.datamining.data.PhysicalAttribute"); + m_clasFactory = + (ClassificationSettingsFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.ClassificationSettings"); + m_nbFactory = + (NaiveBayesSettingsFactory) m_dmeConn.getFactory("javax.datamining.algorithm.naivebayes.NaiveBayesSettings"); + m_buildFactory = + (BuildTaskFactory) m_dmeConn.getFactory("javax.datamining.task.BuildTask"); + m_exportFactory = + (ExportTaskFactory) m_dmeConn.getFactory("javax.datamining.task.ExportTask"); + m_importFactory = + (ImportTaskFactory) m_dmeConn.getFactory("javax.datamining.task.ImportTask"); + m_binningXformFactory = + (OraBinningTransformFactory) m_dmeConn.getFactory("oracle.dmt.jdm.transform.binning.OraBinningTransform"); + m_xformTaskFactory = + (OraTransformationTaskFactory) m_dmeConn.getFactory("oracle.dmt.jdm.task.OraTransformationTask"); + } + + /** + * This method builds a mining model. The build operation requires the training + * dataset location details and the mining function settings. + * In this example, we will build a classification model using the + * build dataset "IE_BINNED_DATA_BUILD_JDM" in the user schema, with the + * NaiveBayes algorithm. This model can be used to predict which customer + * would respond to a promotion campaign. After completing the build task, the + * model named "nbModel_jdm" will be created in the DMS. + */ + public static void buildModel() + throws JDMException + { + //1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = + m_pdsFactory.create("MINING_DATA_BUILD_V", false); + PhysicalAttribute pa = + m_paFactory.create("cust_id", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + buildData.addAttribute(pa); + m_dmeConn.saveObject("nbExpImpBuildData_jdm", buildData, true); + //2. Create & save Mining Function Settings + //Create NB algorithm settings + NaiveBayesSettings nbAlgo = m_nbFactory.create(); + nbAlgo.setPairwiseThreshold(0.01f); + nbAlgo.setSingletonThreshold(0.01f); + //Create ClassificationSettings + ClassificationSettings buildSettings = m_clasFactory.create(); + buildSettings.setAlgorithmSettings(nbAlgo); + buildSettings.setTargetAttributeName("affinity_card"); + //Set target prior probabilities + Map priorMap = new HashMap(); + priorMap.put(new Double(0), new Double(0.7)); + priorMap.put(new Double(1), new Double(0.3)); + buildSettings.setPriorProbabilitiesMap("affinity_card", priorMap); + //Use auto data prep + ((OraBuildSettings) buildSettings).useAutomatedDataPreparations(true); + m_dmeConn.saveObject("nbExpImpBuildSettings_jdm", buildSettings, true); + //3. Create, save & execute Build Task + BuildTask buildTask = //Build data specification + //Mining function settings name + //Mining model name + m_buildFactory.create("nbExpImpBuildData_jdm", + "nbExpImpBuildSettings_jdm", + "nbExpImpModel_jdm"); + buildTask.setDescription("nbExpImpBuildTask_jdm"); + saveTask(buildTask, "nbExpImpBuildTask_jdm", null); + } + + /** + * This method exports the mining model into a dump file. + * In this example, we will export "nbExpImpModel_jdm" and store the exported + * model into a "nbExport" dump file in "DM_DUMP" directory. + */ + public static void exportModel() + throws JDMException + { + ExportTask exportTask = m_exportFactory.create(); + exportTask.addObjectName("nbExpImpModel_jdm", NamedObject.model); + exportTask.setURI("DM_DUMP/nbExport"); + saveTask(exportTask, "nbExportTask_jdm", "nbExpImpBuildTask_jdm"); + } + + /** + * This method imports the mining model from a dump file. + * In this example, we will import the model "nbExpImpModel_jdm" from + * "nbExport" dump file in "DM_DUMP" directory. + */ + public static void importModel() + throws JDMException + { + //Drop the built model + try + { + m_dmeConn.removeObject("nbExpImpModel_jdm", NamedObject.model); + } + catch (Exception jdmExp) + { + } + + ImportTask importTask = m_importFactory.create(); + importTask.setURI("DM_DUMP/nbExport%U"); + saveTask(importTask, "nbImportTask_jdm", "nbExportTask_jdm"); + } + + /** + * Cleanup the previously created objects if any. + */ + private static void clean() + { + //Drop the imported model + try + { + m_dmeConn.removeObject("nbExpImpModel_jdm", NamedObject.model); + } + catch (Exception jdmExp) + { + } + } + + /** + * This method monitor task execution initiated by the first task + * in the sequence of dependent tasks. In addition, this method displays + * task output results (if any). + * @throws JDMException + */ + public static void monitorTaskExecutionProcess() + throws JDMException + { + //BuildTask + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of nbExpImpBuildTask_jdm. "); + ExecutionStatus buildTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("nbExpImpBuildTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(buildTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + + //If model build is successful, then do export model task + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of nbExportTask_jdm. "); + ExecutionStatus modelExportTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("nbExportTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(modelExportTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + //If model export is successful, then wait for import task completion + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of nbImportTask_jdm. "); + ExecutionStatus modelImportTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("nbImportTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(modelImportTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + } + else + { + System.out.println("It is at state:" + + modelImportTaskCompletionStatus.getState().name() + + ((modelImportTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + modelImportTaskCompletionStatus.getDescription())); + } + } + else + { + System.out.println("It is at state:" + + modelExportTaskCompletionStatus.getState().name() + + ((modelExportTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + modelExportTaskCompletionStatus.getDescription())); + } + } + else + { + System.out.println("It is at state:" + + buildTaskCompletionStatus.getState().name() + + ((buildTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + buildTaskCompletionStatus.getDescription())); + } + } + + /** + * This method saves the given task with the specified task name and task + * dependency (parent task) in the DME. + * + * @param taskObj task object + * @param taskName name of the task + * @param parentTaskName name of the parent task + * + * @return boolean returns true when the task is successful + * @exception JDMException if task execution failed + */ + public static void saveTask(Task taskObj, String taskName, + String parentTaskName) + throws JDMException + { + if (parentTaskName != null) + ((OraTask) taskObj).addDependency(parentTaskName); //Since OJDM 11.1 + //if (!(taskObj instanceof BuildTask)) + ((OraTask) taskObj).overwriteOutput(true); //Since OJDM 11.1 + m_dmeConn.saveObject(taskName, taskObj, true); + } + + public static void trackTaskExecution(String taskName, + ExecutionHandle execHandle) + throws JDMException + { + System.out.print(taskName + " is started, please wait. "); + //Wait for completion of the task + ExecutionStatus status = + execHandle.waitForCompletion(Integer.MAX_VALUE); + //Check the status of the task after completion + boolean isTaskSuccess = + status.getState().equals(ExecutionState.success); + if (isTaskSuccess) //Task completed successfully + System.out.println(taskName + " is successful."); + else //Task failed + System.out.println(taskName + " failed.\nFailure Description: " + + status.getDescription()); + } + +} diff --git a/dmglcdem.sql b/dmglcdem.sql new file mode 100644 index 0000000..ef67cf4 --- /dev/null +++ b/dmglcdem.sql @@ -0,0 +1,461 @@ +Rem +Rem $Header: dmglcdem.sql 22-jan-2008.14:06:04 ramkrish Exp $ +Rem +Rem dmglcdem.sql +Rem +Rem Copyright (c) 2003, 2008, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmglcdem.sql - Sample program for the DBMS_DATA_MINING package. +Rem +Rem DESCRIPTION +Rem This script creates a classification model using GLM based on +Rem data in the SH (Sales History) schema in the RDBMS and +Rem demonstrates the use of SQL prediction functions to test +Rem the model and apply it to new data. +Rem +Rem NOTES +Rem +Rem MODIFIED (MM/DD/YY) +Rem ramkrish 06/14/07 - remove commit after settings +Rem ramkrish 01/22/08 - add prediction_bounds +Rem ramkrish 10/25/07 - replace deprecated get_model calls with catalog +Rem queries +Rem bmilenov 05/08/07 - Change case_id column in row diagnostics table +Rem bmilenov 12/13/06 - Turn ADP on +Rem bmilenov 12/05/06 - Change row diagnostic query +Rem jyarmus 11/21/06 - Change ridge regression constant +Rem jyarmus 10/18/06 - reduce precision of accuracy and AUC +Rem jyarmus 10/13/06 - drop diagnostics table prior to second model +Rem build +Rem jyarmus 10/12/06 - Run with and without ridge +Rem bmilenov 10/04/06 - Remove multicolinear columns +Rem bmilenov 08/22/06 - Drop class weight table +Rem bmilenov 08/18/06 - Cleanup +Rem ramkrish 10/02/03 - Creation + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET echo ON + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM +----------------------------------------------------------------------- +-- Given demographic and purchase data about a set of customers, predict +-- customer's response to an affinity card program using a GLM classifier. +-- + +----------------------------------------------------------------------- +-- SET UP AND ANALYZE THE DATA +----------------------------------------------------------------------- + +------- +-- DATA +------- +-- The data for this sample is composed from base tables in SH Schema +-- (See Sample Schema Documentation) and presented through these views: +-- mining_data_build_v (build data) +-- mining_data_test_v (test data) +-- mining_data_apply_v (apply data) +-- (See dmsh.sql for view definitions). +-- + +----------- +-- ANALYSIS +----------- +-- Data preparation in GLM is performed internally +-- + +----------------------------------------------------------------------- +-- BUILD THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old model with the same name for repeat runs +BEGIN DBMS_DATA_MINING.DROP_MODEL('GLMC_SH_Clas_sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +------------------ +-- SPECIFY SETTINGS +-- +-- Cleanup old settings table for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE glmc_sh_sample_settings'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +-- Cleanup class weights +BEGIN EXECUTE IMMEDIATE 'DROP TABLE glmc_sh_sample_clas_weights'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- Cleanup diagnostics table +BEGIN EXECUTE IMMEDIATE 'DROP TABLE glmc_sh_sample_diag'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- CREATE AND POPULATE A CLASS WEIGHTS TABLE +-- +-- A class weights table is used to influence the weighting of target classes +-- during model creation. +-- +CREATE TABLE glmc_sh_sample_clas_weights ( + target_value NUMBER, + prior_probability NUMBER); +INSERT INTO glmc_sh_sample_clas_weights VALUES (0,0.35); +INSERT INTO glmc_sh_sample_clas_weights VALUES (1,0.65); + +-- CREATE AND POPULATE A SETTINGS TABLE +-- +set echo off +CREATE TABLE glmc_sh_sample_settings ( + setting_name VARCHAR2(30), + setting_value VARCHAR2(30)); +set echo on + +-- The default classification algorithm is Naive Bayes. So override +-- this choice to GLM logistic regression using a settings table. +-- +BEGIN +-- Populate settings table + INSERT INTO glmc_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.algo_name, dbms_data_mining.algo_generalized_linear_model); + INSERT INTO glmc_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.glms_diagnostics_table_name, 'GLMC_SH_SAMPLE_DIAG'); + INSERT INTO glmc_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.prep_auto, dbms_data_mining.prep_auto_on); + -- Examples of other possible overrides are: + --(dbms_data_mining.glms_ridge_regression, dbms_data_mining.glms_ridge_reg_enable); +END; +/ + +--------------------- +-- CREATE A NEW MODEL +-- +-- Build a new GLM Model +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'GLMC_SH_Clas_sample', + mining_function => dbms_data_mining.classification, + data_table_name => 'mining_data_build_v', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + settings_table_name => 'glmc_sh_sample_settings'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30 +column setting_value format a30 +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'GLMC_SH_CLAS_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +column attribute_name format a40 +column attribute_type format a20 +SELECT attribute_name, attribute_type + FROM user_mining_model_attributes + WHERE model_name = 'GLMC_SH_CLAS_SAMPLE' +ORDER BY attribute_name; + +------------------------ +-- DISPLAY MODEL DETAILS +-- +-- Global statistics +SELECT * + FROM TABLE(dbms_data_mining.get_model_details_global('GLMC_SH_Clas_sample')) +ORDER BY global_detail_name; + +-- We see from the global details that the covariance matrix was invalid: +-- VALID_COVARIANCE_MATRIX is 0 +-- As a result we only get a limited set of diagnostics, a sample of which +-- are shown below. +-- +-- Another important consequence of an invalid covariance matrix is that +-- the model cannot predict confidence bounds - i.e. the result of +-- PREDICTION_BOUNDS function in a SQL query is NULL. +-- +-- We also note that RIDGE REGRESSION has been enabled. It may happen that +-- the ridge regression model built on multicollinear predictors is better +-- than a non-ridge model built on a subset of the predictors where the +-- multicollinearity has been reduced sufficiently to produce a valid +-- covariance matrix. +-- + +-- Coefficient statistics +SET line 120 +column class format a20 +column attribute_name format a20 +column attribute_subname format a20 +column attribute_value format a20 + +SELECT * + FROM (SELECT * + FROM TABLE(dbms_data_mining.get_model_details_glm( + 'GLMC_SH_Clas_sample')) + ORDER BY class, attribute_name, attribute_value) + WHERE ROWNUM < 11; + +-- Row diagnostics +SELECT * + FROM (SELECT * + FROM glmc_sh_sample_diag + ORDER BY case_id) + WHERE ROWNUM < 11; + +----------------------------------------------------------------------- +-- TEST THE MODEL +----------------------------------------------------------------------- +------------------------------------ +-- COMPUTE METRICS TO TEST THE MODEL +-- +-- The queries shown below demonstrate the use of new SQL data mining functions +-- along with analytic functions to compute the various test metrics. +-- +-- Modelname: glmc_sh_clas_sample +-- Target attribute: affinity_card +-- Positive target value: 1 +-- (Change as appropriate for a different example) + +-- Compute CONFUSION MATRIX +-- +-- This query demonstates how to generate a confusion matrix using the new +-- SQL prediction functions for scoring. The returned columns match the +-- schema of the table generated by COMPUTE_CONFUSION_MATRIX procedure. +-- +SELECT affinity_card AS actual_target_value, + PREDICTION(glmc_sh_clas_sample USING *) AS predicted_target_value, + COUNT(*) AS value + FROM mining_data_test_v + GROUP BY affinity_card, PREDICTION(glmc_sh_clas_sample USING *) + ORDER BY 1, 2; + +-- Compute ACCURACY +-- +column accuracy format 9.99 + +SELECT SUM(correct)/COUNT(*) AS accuracy + FROM (SELECT DECODE(affinity_card, + PREDICTION(glmc_sh_clas_sample USING *), 1, 0) AS correct + FROM mining_data_test_v); + +-- Compute AUC (Area Under the roc Curve) +-- (See notes on ROC Curve and AUC computation in dmsvcdem.sql) +-- +column auc format 9.99 +WITH +pos_prob_and_counts AS ( +SELECT PREDICTION_PROBABILITY(glmc_sh_clas_sample, 1 USING *) pos_prob, + DECODE(affinity_card, 1, 1, 0) pos_cnt + FROM mining_data_test_v +), +tpf_fpf AS ( +SELECT pos_cnt, + SUM(pos_cnt) OVER (ORDER BY pos_prob DESC) / + SUM(pos_cnt) OVER () tpf, + SUM(1 - pos_cnt) OVER (ORDER BY pos_prob DESC) / + SUM(1 - pos_cnt) OVER () fpf + FROM pos_prob_and_counts +), +trapezoid_areas AS ( +SELECT 0.5 * (fpf - LAG(fpf, 1, 0) OVER (ORDER BY fpf, tpf)) * + (tpf + LAG(tpf, 1, 0) OVER (ORDER BY fpf, tpf)) area + FROM tpf_fpf + WHERE pos_cnt = 1 + OR (tpf = 1 AND fpf = 1) +) +SELECT SUM(area) auc + FROM trapezoid_areas; + +----------------------------------------------------------------------- +-- BUILD THE NEW MODEL +----------------------------------------------------------------------- + +-- Further analysis (i.e. inspecting data for constants, correlations) +-- showed that excluding the columns PRINTER_SUPPLIES, CUST_INCOME_level and +-- BOOKKEEPING_APPLICATION avoid singularities in the data that lead to +-- the invalid covariance matrix. For example, PRINTER_SUPPLIES has a +-- constant 1 as the value in all rows, and the other two columns were +-- found to be strongly correlated with yet another column. + +-- So, in order to demo a full set of diagnostics, we create a new view +-- that excludes the problematic columns, and build a new model against +-- this training data. + +-- Cleanup diagnostics table +BEGIN EXECUTE IMMEDIATE 'DROP TABLE glmc_sh_sample_diag'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- Cleanup old build view +BEGIN EXECUTE IMMEDIATE 'DROP VIEW mining_data_build_v2'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- CREATE a view that excludes columns PRINTER_SUPPLIES, CUST_INCOME_level +-- and BOOKKEEPING_APPLICATION +CREATE VIEW mining_data_build_v2 AS +SELECT CUST_id, CUST_gender, age, CUST_MARITAL_status, COUNTRY_name, + education, occupation, HOUSEHOLD_size, YRS_residence, AFFINITY_card, + BULK_PACK_diskettes, FLAT_PANEL_monitor, HOME_THEATER_package, + Y_BOX_games, OS_DOC_SET_kanji + FROM mining_data_build_v; + +--------------------- +-- CREATE A NEW MODEL +-- +-- Cleanup old model with the same name for repeat runs +BEGIN DBMS_DATA_MINING.DROP_MODEL('GLMC_SH_Clas_sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- Build a new GLM Model +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'GLMC_SH_Clas_sample', + mining_function => dbms_data_mining.classification, + data_table_name => 'mining_data_build_v2', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + settings_table_name => 'glmc_sh_sample_settings'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30 +column setting_value format a30 +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'GLMC_SH_CLAS_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +column attribute_name format a40 +column attribute_type format a20 +SELECT attribute_name, attribute_type + FROM user_mining_model_attributes + WHERE model_name = 'GLMC_SH_CLAS_SAMPLE' +ORDER BY attribute_name; + +------------------------ +-- DISPLAY MODEL DETAILS +-- +-- Global statistics +SELECT * + FROM TABLE(dbms_data_mining.get_model_details_global('GLMC_SH_Clas_sample')) +ORDER BY global_detail_name; + +-- Coefficient statistics +SET line 120 +column class format a20 +column attribute_name format a20 +column attribute_subname format a20 +column attribute_value format a20 + +SELECT * + FROM (SELECT * + FROM TABLE(dbms_data_mining.get_model_details_glm( + 'GLMC_SH_Clas_sample')) + ORDER BY class, attribute_name, attribute_value) + WHERE ROWNUM < 11; + +-- Row diagnostics +SELECT * + FROM (SELECT * + FROM glmc_sh_sample_diag + ORDER BY case_id) + WHERE ROWNUM < 11; + +----------------------------------------------------------------------- +-- TEST THE NEW MODEL +----------------------------------------------------------------------- +------------------------------------ +-- COMPUTE METRICS TO TEST THE MODEL +-- +-- The queries shown below demonstrate the use of new SQL data mining functions +-- along with analytic functions to compute various test metrics. +-- +-- Modelname: glmc_sh_clas_sample +-- Target attribute: affinity_card +-- Positive target value: 1 +-- (Change these as appropriate for a different example) + +-- Compute CONFUSION MATRIX +-- +-- This query demonstates how to generate a confusion matrix using the new +-- SQL prediction functions for scoring. The returned columns match the +-- schema of the table generated by COMPUTE_CONFUSION_MATRIX procedure. +-- +SELECT affinity_card AS actual_target_value, + PREDICTION(glmc_sh_clas_sample USING *) AS predicted_target_value, + COUNT(*) AS value + FROM mining_data_test_v + GROUP BY affinity_card, PREDICTION(glmc_sh_clas_sample USING *) + ORDER BY 1, 2; + +-- Compute ACCURACY +-- +column accuracy format 9.99 + +SELECT SUM(correct)/COUNT(*) AS accuracy + FROM (SELECT DECODE(affinity_card, + PREDICTION(glmc_sh_clas_sample USING *), 1, 0) AS correct + FROM mining_data_test_v); + +-- Compute AUC (Area Under the roc Curve) +-- +-- See notes on ROC Curve and AUC computation above +-- +column auc format 9.99 +WITH +pos_prob_and_counts AS ( +SELECT PREDICTION_PROBABILITY(glmc_sh_clas_sample, 1 USING *) pos_prob, + DECODE(affinity_card, 1, 1, 0) pos_cnt + FROM mining_data_test_v +), +tpf_fpf AS ( +SELECT pos_cnt, + SUM(pos_cnt) OVER (ORDER BY pos_prob DESC) / + SUM(pos_cnt) OVER () tpf, + SUM(1 - pos_cnt) OVER (ORDER BY pos_prob DESC) / + SUM(1 - pos_cnt) OVER () fpf + FROM pos_prob_and_counts +), +trapezoid_areas AS ( +SELECT 0.5 * (fpf - LAG(fpf, 1, 0) OVER (ORDER BY fpf, tpf)) * + (tpf + LAG(tpf, 1, 0) OVER (ORDER BY fpf, tpf)) area + FROM tpf_fpf + WHERE pos_cnt = 1 + OR (tpf = 1 AND fpf = 1) +) +SELECT SUM(area) auc + FROM trapezoid_areas; + +-- Judging from the accuracy and AUC, the ridge regression model is +-- marginally superior to the model produced on the reduced predictor set. + +-------------------------------------------------------------------------- +-- SCORE DATA +-------------------------------------------------------------------------- + +-- now that the model has a valid covariance matrix, it is possible +-- to obtain confidence bounds. +SELECT * + FROM (SELECT CUST_ID, + PREDICTION(GLMC_SH_Clas_sample USING *) pr, + PREDICTION_PROBABILITY(GLMC_SH_Clas_sample USING *) pb, + PREDICTION_BOUNDS(GLMC_SH_Clas_sample USING *).lower pl, + PREDICTION_BOUNDS(GLMC_SH_Clas_sample USING *).upper pu + FROM mining_data_apply_v + ORDER BY CUST_ID) + WHERE ROWNUM < 11 +ORDER BY CUST_ID; diff --git a/dmglcdemo.java b/dmglcdemo.java new file mode 100644 index 0000000..6b48d37 --- /dev/null +++ b/dmglcdemo.java @@ -0,0 +1,968 @@ +// Copyright (c) 2004, 2006, Oracle. All rights reserved. +// File: dmglcdemo.java +import java.math.BigDecimal; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; + +import java.sql.Statement; + +import java.text.DecimalFormat; + +import java.text.MessageFormat; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; + +import java.util.Map; + +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.MiningAlgorithm; +import javax.datamining.MiningFunction; +import javax.datamining.NamedObject; +import javax.datamining.base.AlgorithmSettings; +import javax.datamining.base.Model; +import javax.datamining.base.Task; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.ModelSignature; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.data.SignatureAttribute; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.supervised.classification.ClassificationApplySettings; +import javax.datamining.supervised.classification.ClassificationApplySettingsFactory; +import javax.datamining.supervised.classification.ClassificationModel; +import javax.datamining.supervised.classification.ClassificationSettings; +import javax.datamining.supervised.classification.ClassificationSettingsFactory; +import javax.datamining.supervised.classification.ClassificationTestMetricOption; +import javax.datamining.supervised.classification.ClassificationTestMetrics; +import javax.datamining.supervised.classification.ClassificationTestMetricsTask; +import javax.datamining.supervised.classification.ClassificationTestMetricsTaskFactory; +import javax.datamining.supervised.classification.ClassificationTestTaskFactory; +import javax.datamining.supervised.classification.ConfusionMatrix; +import javax.datamining.supervised.classification.Lift; +import javax.datamining.supervised.classification.ReceiverOperatingCharacterics; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; +import javax.datamining.task.apply.DataSetApplyTask; + +import javax.datamining.task.apply.DataSetApplyTaskFactory; + +import oracle.dmt.jdm.algorithm.glm.OraGLMClassificationSettings; +import oracle.dmt.jdm.algorithm.glm.OraGLMSettingsFactory; +import oracle.dmt.jdm.base.OraBuildSettings; +import oracle.dmt.jdm.base.OraTask; +import oracle.dmt.jdm.modeldetail.glm.OraGLMModelDetail; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.supervised.classification.OraClassificationSettings; +import oracle.dmt.jdm.supervised.classification.OraLift; +import oracle.dmt.jdm.task.OraBuildTask; +import oracle.dmt.jdm.task.OraTransformationTaskFactory; +import oracle.dmt.jdm.transform.OraExpressionTransform; +import oracle.dmt.jdm.transform.OraTransformationFactory; +import oracle.dmt.jdm.transform.OraTransformationSequence; +import oracle.dmt.jdm.transform.normalize.OraNormalizeTransformImpl; +// Copyright (c) 2004, 2006, Oracle. All rights reserved. +// File: dmsvcdemo.java +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to solve a classification problem using Support Vector Machines (SVM) +* algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* How to predict whether a customer responds or not to the new affinity card +* program using a classifier based on SVM algorithm? +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the previous affinity card +* programs. Data exploration and preparing the data is a common step before +* doing data mining. Here in this demo, the following views are created in the user +* schema using CUSTOMERS, COUNTRIES, and SUPPLIMENTARY_DEMOGRAPHICS tables. +* +* MINING_DATA_BUILD_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for building the model. +* +* MINING_DATA_TEST_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for testing the model. +* +* MINING_DATA_APPLY_V: +* This view collects the prospective customers' demographics and purchasing +* details for predicting response for the new affinity card program. +* +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Prepare Data: +* 1. Missing Value treatment for Predictors in Build, Test, and Apply data +* +* "Missing Value" here implies "Missing at Random" values, that is, +* there is no pattern to the missing data, a NULL value does not have a +* special meaning, and there is no correlation either direct or indirect +* with the target or other predictor values. +* +* Missing value imputation is recommended when the fraction of missing +* at random values is high compared to the overall attribute value set. +* +* Contrast this with a "sparse" dataset - where a NULL value for +* an attribute encodes a zero/non-present. Typical examples of domains +* with sparse data are market basket and text mining. Missing value +* imputation should not be used on sparse data. By default, SVM +* interprets all NULL values for a given attribute as "sparse". +* +* Based on the business problem, one should designate the NULL value +* for a given attribute to be "missing at random" or "sparse". For +* example, a NULL value for AGE in demographic data can be missing +* at random if omitting this information is a random occurrence. +* In contrast, a shopping cart record with NULL values for certain +* items is usually considered sparse - because a customer cannot +* buy the entire inventory of items in a store. +* +* Here we are showing a simple approach to missing value treatment: +* +* 1.1. Compute the mean for numerical attributes, and mode for +* categoricals. Store them away in a table for use with +* Test and Apply data. +* +* 1.2. Replace the NULLs in the build, and test and apply, data +* with the computed mean (for numerical), mode (for categorical). +* +* 2. Outlier/Clipping Treatment for Predictors for Build data +* +* For SVM, we recommended that the data be normalized (individual +* attributes need to be on a similar scale) to achieve faster +* convergence of model builds and more accurate models. Large outliers +* in individual attributes can result in sub-optimal normalization +* output and sub-optimal models. Note that outlier/clipping treatment would +* be also beneficial for algorithms that use equi-width-binning +* (e.g., O-Cluster) since outliers in the data would produce sub-optimal bin +* boundaries. +* +* Here we winsorize the tail elements of the data as a preparatory step to +* normalization. +* +* We recommend the use of winsorizing to reduce the influence of outliers on +* the normalization computation. The normalization parameters are computed +* on the winsorized data. Once the normalization parameters are computed, +* they can be used directly on the original data. Winsorizing is not needed +* at test and apply time - it only affects the specification of the +* normalization parameters. +* +* 3. Normalize Predictors in Build, Test, and Apply data, unlike Regression +* using SVM, the target attribute is NOT normalized. +* +* The PrepareData() method in this demo program illustrates the preparation of the +* build, test, and apply data. +* +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a classification model using SVM algorithm. +* +* Test Model: +* Classification models' performance can be evaluated by computing test +* metrics like accuracy, confusion matrix, lift and ROC. The testModel() or +* computeTestMetrics() method illustrates how to perform a test operation to +* compute various metrics. +* +* Apply Model: +* Predicting the target attribute values is the prime function of +* classification models. The applyModel() method illustrates how to +* predict the customer response for an affinity card program. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +// Generic Java api imports + + +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to solve a classification problem using Support Vector Machines (SVM) +* algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* How to predict whether a customer responds or not to the new affinity card +* program using a classifier based on SVM algorithm? +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the previous affinity card +* programs. Data exploration and preparing the data is a common step before +* doing data mining. Here in this demo, the following views are created in the user +* schema using CUSTOMERS, COUNTRIES, and SUPPLIMENTARY_DEMOGRAPHICS tables. +* +* MINING_DATA_BUILD_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for building the model. +* +* MINING_DATA_TEST_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for testing the model. +* +* MINING_DATA_APPLY_V: +* This view collects the prospective customers' demographics and purchasing +* details for predicting response for the new affinity card program. +* +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Prepare Data: +* 1. Missing Value treatment for Predictors in Build, Test, and Apply data +* +* "Missing Value" here implies "Missing at Random" values, that is, +* there is no pattern to the missing data, a NULL value does not have a +* special meaning, and there is no correlation either direct or indirect +* with the target or other predictor values. +* +* Missing value imputation is recommended when the fraction of missing +* at random values is high compared to the overall attribute value set. +* +* Contrast this with a "sparse" dataset - where a NULL value for +* an attribute encodes a zero/non-present. Typical examples of domains +* with sparse data are market basket and text mining. Missing value +* imputation should not be used on sparse data. By default, SVM +* interprets all NULL values for a given attribute as "sparse". +* +* Based on the business problem, one should designate the NULL value +* for a given attribute to be "missing at random" or "sparse". For +* example, a NULL value for AGE in demographic data can be missing +* at random if omitting this information is a random occurrence. +* In contrast, a shopping cart record with NULL values for certain +* items is usually considered sparse - because a customer cannot +* buy the entire inventory of items in a store. +* +* Here we are showing a simple approach to missing value treatment: +* +* 1.1. Compute the mean for numerical attributes, and mode for +* categoricals. Store them away in a table for use with +* Test and Apply data. +* +* 1.2. Replace the NULLs in the build, and test and apply, data +* with the computed mean (for numerical), mode (for categorical). +* +* 2. Outlier/Clipping Treatment for Predictors for Build data +* +* For SVM, we recommended that the data be normalized (individual +* attributes need to be on a similar scale) to achieve faster +* convergence of model builds and more accurate models. Large outliers +* in individual attributes can result in sub-optimal normalization +* output and sub-optimal models. Note that outlier/clipping treatment would +* be also beneficial for algorithms that use equi-width-binning +* (e.g., O-Cluster) since outliers in the data would produce sub-optimal bin +* boundaries. +* +* Here we winsorize the tail elements of the data as a preparatory step to +* normalization. +* +* We recommend the use of winsorizing to reduce the influence of outliers on +* the normalization computation. The normalization parameters are computed +* on the winsorized data. Once the normalization parameters are computed, +* they can be used directly on the original data. Winsorizing is not needed +* at test and apply time - it only affects the specification of the +* normalization parameters. +* +* 3. Normalize Predictors in Build, Test, and Apply data, unlike Regression +* using SVM, the target attribute is NOT normalized. +* +* The PrepareData() method in this demo program illustrates the preparation of the +* build, test, and apply data. +* +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a classification model using SVM algorithm. +* +* Test Model: +* Classification models' performance can be evaluated by computing test +* metrics like accuracy, confusion matrix, lift and ROC. The testModel() or +* computeTestMetrics() method illustrates how to perform a test operation to +* compute various metrics. +* +* Apply Model: +* Predicting the target attribute values is the prime function of +* classification models. The applyModel() method illustrates how to +* predict the customer response for an affinity card program. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +// Java Data Mining (JDM) standard api imports +// Oracle Java Data Mining (JDM) implemented api imports + +public class dmglcdemo extends Object { + // Connection related data members + private static javax.datamining.resource.Connection m_dmeConn; + private static javax.datamining.resource.ConnectionFactory m_dmeConnFactory; + // Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static ClassificationSettingsFactory m_clasFactory; + private static OraGLMSettingsFactory m_glmcFactory; + private static BuildTaskFactory m_buildFactory; + private static DataSetApplyTaskFactory m_dsApplyFactory; + private static ClassificationTestTaskFactory m_testFactory; + private static ClassificationApplySettingsFactory m_applySettingsFactory; + private static ClassificationTestMetricsTaskFactory m_testMetricsTaskFactory; + private static OraTransformationFactory m_xformFactory; + // Global constants + private static DecimalFormat m_df = new DecimalFormat("##.##"); + // Global data members + private static boolean m_displayModelDetails = false; + private static boolean m_displayTestMetricsDetails = false; + + public static void main( String args[] ) { + try { + if (( args.length != 0 ) & ( args.length != 3 )) { + System.out.println("Usage: java dmglcdemo "); + System.out.println(" or: java dmglcdemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + // 1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@"+uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Build a model with supplied prior probability + buildModel(); + // 6. Test model - To compute accuracy and confusion matrix, lift result + // and ROC for the model from an apply output data. + // Please see dnnbdemo.java to see how to test the model + // with a test input data and cost matrix. In SVM, we + // recommend that any known costs be provided to the + // algorithm during build via the prior mechanism. + computeTestMetrics(); + // 7. Apply the model + applyModel(); + } catch(Exception anyExp) { + anyExp.printStackTrace(System.out); + } finally { + try { + // 8. Logout from the Data Mining Engine + m_dmeConn.close(); + } catch(Exception anyExp1) { } // Ignore + } + } + + /** + * Initialize all object factories used in the demo program. + * + * @exception JDMException if factory initalization failed + */ + public static void initFactories() throws JDMException + { + m_pdsFactory = (PhysicalDataSetFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalDataSet"); + m_paFactory = (PhysicalAttributeFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalAttribute"); + m_clasFactory = (ClassificationSettingsFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationSettings"); + m_glmcFactory = (OraGLMSettingsFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.algorithm.glm.OraGLMSettings"); + m_buildFactory = (BuildTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.BuildTask"); + m_testFactory = (ClassificationTestTaskFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationTestTask"); + m_dsApplyFactory = (DataSetApplyTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.apply.DataSetApplyTask"); + m_applySettingsFactory = (ClassificationApplySettingsFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationApplySettings"); + m_testMetricsTaskFactory = (ClassificationTestMetricsTaskFactory) m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationTestMetricsTask"); + m_xformFactory = (OraTransformationFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.transform.OraTransformation" ); + } + + /** + * This method illustrates how to build mining model using + * MINING_DATA_BUILD_V dataset and classification settings with + * SVM algorithm. + * + * By default SVM algorithm chooses an kernel type automatically. This + * choice can be overriden by the user. Linear kernel is preferred high + * dimensional data, and Gaussian kernel for low dimensional data. Here we use + * linear kernel to demonstrate the getModelDetail() API, which applies only + * for models. + * + * @exception JDMException if model build failed + */ + public static void buildModel() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Build Model ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = + m_pdsFactory.create("MINING_DATA_BUILD_V", false); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + buildData.addAttribute(pa); + m_dmeConn.saveObject("glmcBuildData_jdm", buildData, true); + // 2. Create & save Mining Function Settings + //Create GLMC algorithm settings + OraGLMClassificationSettings glmcAlgo = m_glmcFactory.createGLMClassificationSettings(); + glmcAlgo.setDiagnosticsTableName("GLMC_DIAGNOSTICS_TABLE_JDM"); + glmcAlgo.setReferenceCategory(new Integer(1)); + + //Create ClassificationSettings + ClassificationSettings buildSettings = m_clasFactory.create(); + buildSettings.setAlgorithmSettings(glmcAlgo); + buildSettings.setTargetAttributeName("AFFINITY_CARD"); + ((OraBuildSettings)buildSettings).useAutomatedDataPreparations(true); + m_dmeConn.saveObject("glmcBuildSettings_jdm", buildSettings, true); + + //Create TransformationSequence + OraExpressionTransform exprXform = m_xformFactory.createExpressionTransform(); + //Exclude PRINTER_SUPPLIES, CUST_INCOME_LEVEL and BOOKKEEPING_APPLICATION + //to avoid singularities in the data that lead to invalid covariance matrix. + //(When expression is specified as null those attributes will be excluded) + exprXform.addAttributeExpression("PRINTER_SUPPLIES", null, null); + exprXform.addAttributeExpression("CUST_INCOME_LEVEL", null, null); + exprXform.addAttributeExpression("BOOKKEEPING_APPLICATION", null, null); + //Output view can be specified a null in this case, because we are + //not intended to create a view but embed the expression transformations + //with the model + OraTransformationSequence xformSeq = m_xformFactory.createTransformationSequence( + "MINING_DATA_BUILD_V", exprXform, null ); + m_dmeConn.saveObject("glmcTSExcludeAttrs_jdm", xformSeq, true); + + // 3. Create, save & execute Build Task + BuildTask buildTask = m_buildFactory.create( + "glmcBuildData_jdm", //Build data specification + "glmcBuildSettings_jdm", //Mining function settings name + "glmcModel_jdm" //Mining model name + ); + buildTask.setDescription("glmcBuildTask_jdm"); + //Specify expression transformations that are defined to exclude attributes + //as an embedded transformation to the model build + ((OraBuildTask)buildTask).setTransformationSequenceName("glmcTSExcludeAttrs_jdm"); + executeTask(buildTask, "glmcBuildTask_jdm"); + //4. Restore the model from the DME and explore the details of the model + ClassificationModel model = + (ClassificationModel)m_dmeConn.retrieveObject( + "glmcModel_jdm", NamedObject.model); + // Display model build settings + ClassificationSettings retrievedBuildSettings = + (ClassificationSettings)model.getBuildSettings(); + if(buildSettings == null) + System.out.println("Failure to restore build settings."); + else + displayBuildSettings(retrievedBuildSettings, "glmcBuildSettings_jdm"); + // Display model signature + displayModelSignature((Model)model); + displayGLMCModelDetails((Model)model); + } + + + /** + * This method illustrates how to compute test metrics using + * an apply output table that has actual and predicted target values. Here + * apply operation is done on MINING_DATA_TEST_V dataset which creates + * an apply output table with actual and predicted target values. Using + * ClassificationTestMetricsTask, test metrics are computed. This produces + * the same test metrics results as ClassificationTestTask. + * + * @exception JDMException if model test failed + */ + public static void computeTestMetrics() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Test Model - using apply output table ---"); + System.out.println("---------------------------------------------------"); + // 1. Do the apply on test data to create an apply output table + // Create & save PhysicalDataSpecification + PhysicalDataSet applyData = m_pdsFactory.create( + "MINING_DATA_TEST_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "glmcTestApplyData_jdm", applyData, true ); + // 2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + HashMap srcDestMap = new HashMap(); + srcDestMap.put("AFFINITY_CARD", "AFFINITY_CARD"); + clasAS.setSourceDestinationMap( srcDestMap ); + m_dmeConn.saveObject( "glmcTestApplySettings_jdm", clasAS, true); + // 3. Create, store & execute apply Task + DataSetApplyTask applyTask = m_dsApplyFactory.create( + "glmcTestApplyData_jdm", "glmcModel_jdm", + "glmcTestApplySettings_jdm", + "GLMC_TEST_APPLY_OUTPUT_JDM"); + if(executeTask(applyTask, "glmcTestApplyTask_jdm")) { + // 4. Generate test metrics on the above new created apply output table + // Create & save PhysicalDataSpecification + PhysicalDataSet applyOutputData = m_pdsFactory.create( + "GLMC_TEST_APPLY_OUTPUT_JDM", false ); + applyOutputData.addAttribute( pa ); + m_dmeConn.saveObject( "glmcTestApplyOutput_jdm", applyOutputData, true ); + // 5. Create a ClassificationTestMetricsTask + ClassificationTestMetricsTask testMetricsTask = + m_testMetricsTaskFactory.create( "glmcTestApplyOutput_jdm", // apply output data used as input + "AFFINITY_CARD", // actual target column + "PREDICTION", // predicted target column + "svcComputeTestMetrics_jdm" // test metrics result name + ); + testMetricsTask.computeMetric( // enable confusion matrix computation + ClassificationTestMetricOption.confusionMatrix, true ); + testMetricsTask.computeMetric( // enable lift computation + ClassificationTestMetricOption.lift, true ); + testMetricsTask.computeMetric( // enable ROC computation + ClassificationTestMetricOption.receiverOperatingCharacteristics, true ); + testMetricsTask.setPositiveTargetValue( new Integer(1) ); + testMetricsTask.setNumberOfLiftQuantiles( 10 ); + testMetricsTask.setPredictionRankingAttrName( "PROBABILITY" ); + // 6. Store & execute the task + boolean isTaskSuccess = executeTask(testMetricsTask, "glmcTestMetricsTask_jdm"); + if( isTaskSuccess ) { + // 7. Restore & display test metrics + ClassificationTestMetrics testMetrics = + (ClassificationTestMetrics)m_dmeConn.retrieveObject( + "svcComputeTestMetrics_jdm", + NamedObject.testMetrics ); + // Display classification test metrics + displayTestMetricDetails(testMetrics); + } + } + } + + /** + * This method illustrates how to apply the mining model on the + * GLMC_NORM_DATA_APPLY_JDM dataset to predict customer + * response. After completion of the task, the apply output table with the + * predicted results is created at the user specified location. + * + * @exception JDMException if model apply failed + */ + public static void applyModel() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Apply Model ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = m_pdsFactory.create( + "MINING_DATA_APPLY_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "glmcApplyData_jdm", applyData, true ); + // 2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + m_dmeConn.saveObject( "glmcApplySettings_jdm", clasAS, true); + // 3. Create, store & execute apply Task + DataSetApplyTask applyTask = m_dsApplyFactory.create( + "glmcApplyData_jdm", "glmcModel_jdm", + "glmcApplySettings_jdm", "GLMC_APPLY_OUTPUT_JDM"); + executeTask(applyTask, "glmcApplyTask_jdm"); + // 4. Display apply result -- Note that APPLY results do not need to be + // reverse transformed, as done in the case of model details. This is + // because class values of a classification target were not (required to + // be) binned or normalized. + displayTable("GLMC_APPLY_OUTPUT_JDM", + "where ROWNUM < 11", + "order by CUST_ID"); + } + + /** + * This method stores the given task with the specified name in the DMS + * and submits the task for asynchronous execution in the DMS. After + * completing the task successfully it returns true. If there is a task + * failure, then it prints error description and returns false. + * + * @param taskObj task object + * @param taskName name of the task + * + * @return boolean returns true when the task is successful + * @exception JDMException if task execution failed + */ + public static boolean executeTask(Task taskObj, String taskName) + throws JDMException { + boolean isTaskSuccess = false; + ((OraTask)taskObj).overwriteOutput(true); + m_dmeConn.saveObject(taskName, taskObj, true); + ExecutionHandle execHandle = m_dmeConn.execute(taskName); + System.out.print(taskName + " is started, please wait. "); + //Wait for completion of the task + ExecutionStatus status = execHandle.waitForCompletion(Integer.MAX_VALUE); + //Check the status of the task after completion + isTaskSuccess = status.getState().equals(ExecutionState.success); + if( isTaskSuccess ) { + //Task completed successfully + System.out.println(taskName + " is successful."); + } else {//Task failed + System.out.println(taskName + " is failed.\nFailure Description: " + + status.getDescription() ); + } + return isTaskSuccess; + } + + private static void displayBuildSettings( + ClassificationSettings clasSettings, String buildSettingsName) + { + // Display build settings table + System.out.println("BuildSettings Details from the " + + buildSettingsName + " table:"); + displayTable(buildSettingsName, "", "order by SETTING_NAME"); + // Display build settings object obtained from the model + System.out.println("BuildSettings Details from the " + + buildSettingsName + " model build settings object:"); + String objName = clasSettings.getName(); + if(objName != null) + System.out.println("Name = " + objName); + String objDescription = clasSettings.getDescription(); + if(objDescription != null) + System.out.println("Description = " + objDescription); + java.util.Date creationDate = clasSettings.getCreationDate(); + String creator = clasSettings.getCreatorInfo(); + String targetAttrName = clasSettings.getTargetAttributeName(); + System.out.println("Target attribute name = " + targetAttrName); + AlgorithmSettings algoSettings = clasSettings.getAlgorithmSettings(); + if(algoSettings == null) + System.out.println("Failure: clasSettings.getAlgorithmSettings() returns null"); + MiningAlgorithm algo = algoSettings.getMiningAlgorithm(); + if(algo == null) System.out.println("Failure: algoSettings.getMiningAlgorithm() returns null"); + System.out.println("Algorithm Name: " + algo.name()); + MiningFunction function = clasSettings.getMiningFunction(); + if(function == null) System.out.println("Failure: clasSettings.getMiningFunction() returns null"); + System.out.println("Function Name: " + function.name()); + + try { + Map map = ((OraClassificationSettings)clasSettings).getTargetWeightsMap(); + if(map != null) System.out.println("Target Weights Map: " + map.toString()); + } catch(Exception jdmExp) + { + System.out.println("Failure: clasSettings.getTargetWeightsMap()throws exception"); + jdmExp.printStackTrace(); + } + + // List of GLM algorithm settings availabe in linear kernel + String diagnsticsTableName = ((OraGLMClassificationSettings)algoSettings).getDiagnosticsTableName(); + System.out.println("Diagnostics Table Name: " + diagnsticsTableName); + + Object refCategory = ((OraGLMClassificationSettings)algoSettings).getReferenceCategory(); + System.out.println("Reference category: " + refCategory); + + boolean useRidge = ((OraGLMClassificationSettings)algoSettings).useRidgeRegression(); + System.out.println("Use Ridge Regression: " + useRidge); + + } + + /** + * This method displayes GLMC model signature. + * + * @param model model object + * @exception JDMException if failed to retrieve model signature + */ + public static void displayModelSignature(Model model) throws JDMException + { + String modelName = model.getName(); + System.out.println("Model Name: " + modelName); + ModelSignature modelSignature = model.getSignature(); + System.out.println("Model Signature: ( Attribute Name, Attribute Type )"); + MessageFormat mfSign = new MessageFormat(" ( {0}, {1} )"); + String[] vals = new String[2]; + Collection sortedSet = modelSignature.getAttributes(); + Iterator attrIterator = sortedSet.iterator(); + while(attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute)attrIterator.next(); + vals[0] = attr.getName(); + vals[1] = attr.getDataType().name(); + System.out.println( mfSign.format(vals) ); + } + } + + /** + * This method displayes GLMC model details. The coefficient indicates the + * relative influence of a given (attribute, value) pair on the target value. + * A negative coefficient value indicates a negative influence. + * + * @param glmcModelDetails svm classification model details object + * @exception JDMException if failed to retrieve model details + */ + public static void displayGLMCModelDetails( + Model model) throws JDMException + { + // Obtains model details + OraGLMModelDetail glmcModelDetails = + (OraGLMModelDetail)model.getModelDetail(); + //Get computer high-level statitics of the model + Map glblDetails = glmcModelDetails.getGlobalDetails(); + if(m_displayModelDetails) { + System.out.println("Global Model details:"); + System.out.println(glblDetails.toString()); + } + //Get all attribute coefficients without any filters + ResultSet rsGLM = glmcModelDetails.getAttributeCoefficients(null, null, null, null); + //Display first coeficcient record + try { + rsGLM.next(); + //To display model details enable explicitely by setting m_displayModelDetails to true + if(m_displayModelDetails) { + System.out.println("Target value " + rsGLM.getString("CLASS") ); + System.out.println("Attribute name " + rsGLM.getString("ATTRIBUTE_NAME")); + System.out.println("Attribute value " + rsGLM.getString("ATTRIBUTE_VALUE")); + System.out.println("Coefficient " + rsGLM.getDouble("COEFFICIENT")); + System.out.println("Standard Error " + rsGLM.getDouble("STD_ERROR")); + System.out.println("Test static " + rsGLM.getDouble("TEST_STATISTIC")); + System.out.println("P Value " + rsGLM.getDouble("P_VALUE")); + System.out.println("Variance Inflation Factor " + rsGLM.getDouble("VIF")); + System.out.println("Std. Coefficient " + rsGLM.getDouble("STD_COEFFICIENT")); + System.out.println("Lower Coefficient Limit " + rsGLM.getDouble("LOWER_COEFF_LIMIT")); + System.out.println("Upper Coefficient Limit " + rsGLM.getDouble("UPPER_COEFF_LIMIT")); + System.out.println("Exp Coefficient " + rsGLM.getDouble("EXP_COEFFICIENT")); + System.out.println("Exp Lower Coefficient " + rsGLM.getDouble("EXP_LOWER_COEFF_LIMIT")); + System.out.println("Exp Upper Coefficient " + rsGLM.getDouble("EXP_UPPER_COEFF_LIMIT")); + } + } catch(SQLException anyExp) { + anyExp.printStackTrace(); + } + //After using the details must close the statement associated with the resultset and the resultset + Statement stmtGLM = null; + try { + stmtGLM = rsGLM.getStatement(); + rsGLM.close(); + stmtGLM.close(); + } catch(SQLException anyExp) { + + } finally { + try { if(rsGLM != null) rsGLM.close(); } catch(SQLException sqlExp) {} + } + } + + /** + * Display classification test metrics object + * + * @param testMetrics classification test metrics object + * @exception JDMException if failed to retrieve test metric details + */ + public static void displayTestMetricDetails( + ClassificationTestMetrics testMetrics) throws JDMException + { + // Retrieve Oracle SVMC model test metrics deatils extensions + // Test Metrics Name + System.out.println("Test Metrics Name = " + testMetrics.getName()); + // Model Name + System.out.println("Model Name = " + testMetrics.getModelName()); + // Test Data Name + System.out.println("Test Data Name = " + testMetrics.getTestDataName()); + // Accuracy + System.out.println("Accuracy = " + m_df.format(testMetrics.getAccuracy().doubleValue())); + // Confusion Matrix + ConfusionMatrix confusionMatrix = testMetrics.getConfusionMatrix(); + Collection categories = confusionMatrix.getCategories(); + Iterator xIterator = categories.iterator(); + System.out.println("Confusion Matrix: Accuracy = " + m_df.format(confusionMatrix.getAccuracy())); + System.out.println("Confusion Matrix: Error = " + m_df.format(confusionMatrix.getError())); + if(m_displayTestMetricsDetails) + System.out.println("Confusion Matrix:( Actual, Prection, Value )"); + MessageFormat mf = new MessageFormat(" ( {0}, {1}, {2} )"); + String[] vals = new String[3]; + while(xIterator.hasNext()) + { + Object actual = xIterator.next(); + vals[0] = actual.toString(); + Iterator yIterator = categories.iterator(); + while(yIterator.hasNext()) + { + Object predicted = yIterator.next(); + vals[1] = predicted.toString(); + long number = confusionMatrix.getNumberOfPredictions(actual, predicted); + vals[2] = Long.toString(number); + if(m_displayTestMetricsDetails) + System.out.println(mf.format(vals)); + } + } + // Lift + Lift lift = testMetrics.getLift(); + String targetAttrName = lift.getTargetAttributeName(); + Object positiveTargetVal = lift.getPositiveTargetValue(); + long totalCases = lift.getTotalCases(); + long totalPositiveCases = lift.getTotalPositiveCases(); + int numberOfQuantiles = lift.getNumberOfQuantiles(); + if(m_displayTestMetricsDetails) { + System.out.println("Lift Details:"); + System.out.println("Lift: Target Attribute Name = " + targetAttrName); + System.out.println("Lift: Positive Target Value = " + positiveTargetVal); + System.out.println("Lift: Total Cases = " + totalCases); + System.out.println("Lift: Total Positive Cases = " + totalPositiveCases); + System.out.println("Lift: Number Of Quantiles = " + numberOfQuantiles); + System.out.println("Lift: ( QUANTILE_NUMBER, TOTAL_CASES, QUANTILE_PERCENT_SIZE, POSITIVE_CASES, NEGATIVE_CASES, PROBABILITY_THRESHOLD, LIFT, CUMULATIVE_LIFT, GAIN, CUMULATIVE_GAIN, TARGET_DENSITY, CUMULATIVE_TARGET_DENSITY)"); + } + MessageFormat mfLift = + new MessageFormat(" ( {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10} )"); + + double[] totalCasesPerQuantile = ((OraLift)lift).getCases();//Total cases per quantile + double[] quantilePercentageSize = ((OraLift)lift).getPercentageSize();//Quantile pecentage size + double[] positiveCasesPerQuantile = ((OraLift)lift).getNumberOfPositiveCases();//Positive target cases per quantile + double[] negativeCasesPerQuantile = ((OraLift)lift).getNumberOfNegativeCases();//Negative target cases per quantile + double[] probabilityOrCostThresholdPerQuantile = ((OraLift)lift).getProbabilityOrCostThreshold();//Probability or cost threshold per quantile + double[] liftPerQuantile = ((OraLift)lift).getLift();//Lift values for all quantiles + double[] targetDensityPerQuantile = ((OraLift)lift).getTargetDensity();//Target densities per quantile + + double[] cumulativeLift = ((OraLift)lift).getCumulativeLift(); + double[] cumulativeGain = ((OraLift)lift).getCumulativeGain(); + double[] cumulativeTargetDensity = ((OraLift)lift).getCumulativeTargetDensity(); + + String[] messageParams = new String[11]; + + for (int iQuantile = 0; iQuantile < numberOfQuantiles; iQuantile++) + { + //Assign message parameters + messageParams[0] = Integer.toString(iQuantile+1); //QUANTILE_NUMBER + messageParams[1] = m_df.format(totalCasesPerQuantile[iQuantile]); //TOTAL_CASES + messageParams[2] = m_df.format(quantilePercentageSize[iQuantile]);//QUANTILE_PERCENT_SIZE + messageParams[3] = m_df.format(positiveCasesPerQuantile[iQuantile]); //POSITIVE_CASES + messageParams[4] = m_df.format(negativeCasesPerQuantile[iQuantile]); //NEGATIVE_CASES + messageParams[5] = m_df.format(probabilityOrCostThresholdPerQuantile[iQuantile]); //PROBABILITY_THRESHOLD + messageParams[6] = m_df.format(liftPerQuantile[iQuantile]); //LIFT + messageParams[7] = m_df.format(cumulativeLift[iQuantile]); //CUMULATIVE_LIFT + messageParams[8] = m_df.format(cumulativeGain[iQuantile]); //CUMULATIVE_GAIN + messageParams[9] = m_df.format(targetDensityPerQuantile[iQuantile]); //TARGET_DENSITY + messageParams[10] = m_df.format(cumulativeTargetDensity[iQuantile]); //CUMULATIVE_TARGET_DENSITY + if(m_displayTestMetricsDetails) + System.out.println(mfLift.format(messageParams)); + } + // ROC + ReceiverOperatingCharacterics roc = testMetrics.getROC(); + double areaUnderCurve = roc.getAreaUnderCurve(); + int nROCThresh = roc.getNumberOfThresholdCandidates(); + if(m_displayTestMetricsDetails) { + System.out.println("ROC Details:"); + System.out.println("ROC: Area Under Curve = " + m_df.format(areaUnderCurve)); + System.out.println("ROC: Number Of Threshold Candidates = " + nROCThresh); + System.out.println("ROC: ( INDEX, PROBABILITY, TRUE_POSITIVES, FALSE_NEGATIVES, FALSE_POSITIVES, TRUE_NEGATIVES, TRUE_POSITIVE_FRACTION, FALSE_POSITIVE_FRACTION )"); + } + MessageFormat mfROC = new MessageFormat(" ( {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7} )"); + String[] rocVals = new String[8]; + for(int iROC=1; iROC <= nROCThresh; iROC++) + { + rocVals[0] = Integer.toString(iROC); //INDEX + rocVals[1] = m_df.format(roc.getProbabilityThreshold(iROC));//PROBABILITY + rocVals[2] = Long.toString(roc.getPositives(iROC, true));//TRUE_POSITIVES + rocVals[3] = Long.toString(roc.getNegatives(iROC, false));//FALSE_NEGATIVES + rocVals[4] = Long.toString(roc.getPositives(iROC, false));//FALSE_POSITIVES + rocVals[5] = Long.toString(roc.getNegatives(iROC, true));//TRUE_NEGATIVES + rocVals[6] = m_df.format(roc.getHitRate(iROC));//TRUE_POSITIVE_FRACTION + rocVals[7] = m_df.format(roc.getFalseAlarmRate(iROC));//FALSE_POSITIVE_FRACTION + if(m_displayTestMetricsDetails) + System.out.println(mfROC.format(rocVals)); + } + } + + private static void displayTable(String tableName, String whereCause, String orderByColumn) + { + StringBuffer emptyCol = new StringBuffer(" "); + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + PreparedStatement pStmt = null; + ResultSet rs = null; + try + { + pStmt = dbConn.prepareStatement("SELECT * FROM " + tableName + " " + whereCause + " " + orderByColumn); + rs = pStmt.executeQuery(); + ResultSetMetaData rsMeta = rs.getMetaData(); + int colCount = rsMeta.getColumnCount(); + StringBuffer header = new StringBuffer(); + System.out.println("Table : " + tableName); + // Build table header + for(int iCol=1; iCol<=colCount; iCol++) + { + String colName = rsMeta.getColumnName(iCol); + header.append(emptyCol.replace(0, colName.length(), colName)); + emptyCol = new StringBuffer(" "); + } + System.out.println(header.toString()); + // Write table data + while(rs.next()) + { + StringBuffer rowContent = new StringBuffer(); + for(int iCol=1; iCol<=colCount; iCol++) + { + int sqlType = rsMeta.getColumnType(iCol); + Object obj = rs.getObject(iCol); + String colContent = null; + + if(obj instanceof java.lang.Number) + { + try + { + BigDecimal bd = (BigDecimal)obj; + if(bd.scale() > 5) + { + colContent = m_df.format(obj); + } else + { + colContent = bd.toString(); + } + } catch(Exception anyExp) { + colContent = m_df.format(obj); + } + } else + { + if(obj == null) + colContent = "NULL"; + else + colContent = obj.toString(); + } + rowContent.append(" "+emptyCol.replace(0, colContent.length(), colContent)); + emptyCol = new StringBuffer(" "); + } + System.out.println(rowContent.toString()); + } + } catch(Exception anySqlExp) { + anySqlExp.printStackTrace(); + } // Ignore + } + + private static void clean() + { + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + Statement stmt = null; + //Drop prepared tables + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP TABLE GLMC_DIAGNOSTICS_TABLE_JDM PURGE"); + } catch(SQLException anySqlExp) {} // Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + //Drop the model + try { + m_dmeConn.removeObject("glmcModel_jdm", NamedObject.model); + } catch(JDMException jdmExp) {} + } +} diff --git a/dmglrdem.sql b/dmglrdem.sql new file mode 100644 index 0000000..c925e45 --- /dev/null +++ b/dmglrdem.sql @@ -0,0 +1,346 @@ +Rem +Rem $Header: dmglrdem.sql 22-jan-2008.14:06:12 ramkrish Exp $ +Rem +Rem dmglrdem.sql +Rem +Rem Copyright (c) 2003, 2008, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmglrdem.sql - Sample program for the DBMS_DATA_MINING package. +Rem +Rem DESCRIPTION +Rem This script creates a regression model using GLM based on +Rem data in the SH (Sales History) schema in the RDBMS and +Rem demonstrates the use of SQL prediction functions to test +Rem the model and apply it to new data. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ramkrish 06/14/07 - remove commit after settings +Rem ramkrish 01/22/08 - add prediction_bounds +Rem ramkrish 10/25/07 - replace deprecated get_model calls with catalog +Rem queries +Rem bmilenov 05/08/07 - Change case_id column in row diagnostics table +Rem bmilenov 12/13/06 - Turn ADP on +Rem bmilenov 12/05/06 - Change row diagnostic query +Rem jyarmus 11/21/06 - Change ridge regression constant +Rem jyarmus 10/13/06 - drop diagnostics table prior to second model +Rem build +Rem jyarmus 10/12/06 - build with and without columns causing +Rem a singularity in covariance matrix +Rem bmilenov 10/04/06 - Remove multicolinear columns +Rem bmilenov 08/22/06 - Remove filtered view +Rem bmilenov 08/18/06 - Cleanup +Rem ramkrish 10/02/03 - Creation + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET echo ON + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM +----------------------------------------------------------------------- +-- Given demographic, purchase, and affinity card membership data for a +-- set of customers, predict customer's age. Since age is a continuous +-- variable, this is a regression problem. + +----------------------------------------------------------------------- +-- SET UP AND ANALYZE DATA +----------------------------------------------------------------------- + +-- The data for this sample is composed from base tables in the SH Schema +-- (See Sample Schema Documentation) and presented through these views: +-- mining_data_build_v (build data) +-- mining_data_test_v (test data) +-- mining_data_apply_v (apply data) +-- (See dmsh.sql for view definitions). +-- +----------- +-- ANALYSIS +----------- +-- Data preparation for GLM is performed internally + +----------------------------------------------------------------------- +-- BUILD THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old model with same name (if any) +BEGIN + DBMS_DATA_MINING.DROP_MODEL('GLMR_SH_Regr_sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +------------------- +-- SPECIFY SETTINGS +-- +-- Cleanup old settings table for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE glmr_sh_sample_settings'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- Cleanup diagnostic table +BEGIN EXECUTE IMMEDIATE 'DROP TABLE glmr_sh_sample_diag'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +CREATE TABLE glmr_sh_sample_settings ( + setting_name VARCHAR2(30), + setting_value VARCHAR2(30)); + +BEGIN +-- Populate settings table + INSERT INTO glmr_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.algo_name, dbms_data_mining.algo_generalized_linear_model); + INSERT INTO glmr_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.glms_diagnostics_table_name, 'GLMR_SH_SAMPLE_DIAG'); + INSERT INTO glmr_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.prep_auto, dbms_data_mining.prep_auto_on); + -- Examples of other possible overrides are: + --(dbms_data_mining.glms_ridge_regression, + -- dbms_data_mining.glms_ridge_reg_enable); +END; +/ + +--------------------- +-- CREATE A NEW MODEL +-- +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'GLMR_SH_Regr_sample', + mining_function => dbms_data_mining.regression, + data_table_name => 'mining_data_build_v', + case_id_column_name => 'cust_id', + target_column_name => 'age', + settings_table_name => 'glmr_sh_sample_settings'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30 +column setting_value format a30 +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'GLMR_SH_REGR_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +column attribute_name format a40 +column attribute_type format a20 +SELECT attribute_name, attribute_type + FROM user_mining_model_attributes + WHERE model_name = 'GLMR_SH_REGR_SAMPLE' +ORDER BY attribute_name; + +------------------------ +-- DISPLAY MODEL DETAILS +-- +-- Global statistics +SELECT * + FROM TABLE(dbms_data_mining.get_model_details_global('GLMR_SH_Regr_sample')) +ORDER BY global_detail_name; + +-- We see from the global details that the covariance matrix was invalid: +-- VALID_COVARIANCE_MATRIX is 0 +-- As a result we only get a limited set of diagnostics, a sample of which +-- are shown below + +-- Coefficient statistics +SET line 120 +column class format a20 +column attribute_name format a20 +column attribute_subname format a20 +column attribute_value format a20 + +SELECT * + FROM (SELECT * + FROM TABLE(dbms_data_mining.get_model_details_glm( + 'GLMR_SH_Regr_sample')) + ORDER BY class, attribute_name, attribute_value) + WHERE ROWNUM < 11; + +-- Row diagnostics +SELECT * + FROM (SELECT * + FROM glmr_sh_sample_diag + ORDER BY case_id) + WHERE ROWNUM < 11; + +----------------------------------------------------------------------- +-- TEST THE MODEL +----------------------------------------------------------------------- + +------------------------------------ +-- COMPUTE METRICS TO TEST THE MODEL +-- + +-- 1. Root Mean Square Error - Sqrt(Mean((x - x')^2)) +-- 2. Mean Absolute Error - Mean(|(x - x')|) +-- +column rmse format 9999.99 +column mae format 9999.99 +SELECT SQRT(AVG((A.pred - B.age) * (A.pred - B.age))) rmse, + AVG(ABS(a.pred - B.age)) mae + FROM (SELECT cust_id, prediction(GLMR_SH_Regr_sample using *) pred + FROM mining_data_test_v) A, + mining_data_test_v B + WHERE A.cust_id = B.cust_id; + +-- Further analysis showed that excluding the columns +-- PRINTER_SUPPLIES, CUST_INCOME_level and BOOKKEEPING_APPLICATION +-- avoid singularities in the data +-- that lead to the invalid covariance matrix. Below we create a new view +-- that excludes the problematic columns, thereby enabling computation of a +-- full set of diagnostics +-- (See notes in dmglcdem.sql) + +----------------------------------------------------------------------- +-- BUILD A NEW MODEL +----------------------------------------------------------------------- + +-- Cleanup old build view +BEGIN EXECUTE IMMEDIATE 'DROP VIEW mining_data_build_v2'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- CREATE a view that excludes columns PRINTER_SUPPLIES, CUST_INCOME_level +-- and BOOKKEEPING_APPLICATION +CREATE VIEW mining_data_build_v2 AS +SELECT CUST_id, CUST_gender, age, CUST_MARITAL_status, COUNTRY_name, + education, occupation, HOUSEHOLD_size, YRS_residence, + AFFINITY_card, BULK_PACK_diskettes, FLAT_PANEL_monitor, + HOME_THEATER_package, Y_BOX_games, OS_DOC_SET_kanji + FROM mining_data_build_v; + +-- Cleanup diagnostic table +BEGIN EXECUTE IMMEDIATE 'DROP TABLE glmr_sh_sample_diag'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +--------------------- +-- CREATE A NEW MODEL +-- +-- Cleanup old model with same name (if any) +BEGIN + DBMS_DATA_MINING.DROP_MODEL('GLMR_SH_Regr_sample'); +EXCEPTION WHEN OTHERS THEN + NULL; +END; +/ + +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'GLMR_SH_Regr_sample', + mining_function => dbms_data_mining.regression, + data_table_name => 'mining_data_build_v2', + case_id_column_name => 'cust_id', + target_column_name => 'age', + settings_table_name => 'glmr_sh_sample_settings'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30 +column setting_value format a30 +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'GLMR_SH_REGR_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +column attribute_name format a40 +column attribute_type format a20 +SELECT attribute_name, attribute_type + FROM user_mining_model_attributes + WHERE model_name = 'GLMR_SH_REGR_SAMPLE' +ORDER BY attribute_name; + +------------------------ +-- DISPLAY MODEL DETAILS +-- +-- Global statistics +SELECT * + FROM TABLE(dbms_data_mining.get_model_details_global( + 'GLMR_SH_Regr_sample')) +ORDER BY global_detail_name; + +-- Coefficient statistics +SET line 120 +column class format a20 +column attribute_name format a20 +column attribute_subname format a20 +column attribute_value format a20 + +SELECT * + FROM (SELECT * + FROM TABLE(dbms_data_mining.get_model_details_glm( + 'GLMR_SH_Regr_sample')) + ORDER BY class, attribute_name, attribute_value) + WHERE ROWNUM < 11; + +-- Row diagnostics +SELECT * + FROM (SELECT * + FROM glmr_sh_sample_diag + ORDER BY case_id) + WHERE ROWNUM < 11; + +----------------------------------------------------------------------- +-- TEST THE MODEL +----------------------------------------------------------------------- + +------------------------------------ +-- COMPUTE METRICS TO TEST THE MODEL +-- + +-- 1. Root Mean Square Error - Sqrt(Mean((x - x')^2)) +-- 2. Mean Absolute Error - Mean(|(x - x')|) +-- +column rmse format 9999.99 +column mae format 9999.99 +SELECT SQRT(AVG((A.pred - B.age) * (A.pred - B.age))) rmse, + AVG(ABS(a.pred - B.age)) mae + FROM (SELECT cust_id, prediction(GLMR_SH_Regr_sample using *) pred + FROM mining_data_test_v) A, + mining_data_test_v B + WHERE A.cust_id = B.cust_id; + +-- 3. Residuals +-- If the residuals show substantial variance between +-- the predicted value and the actual, you can consider +-- changing the algorithm parameters. +-- +SELECT TO_CHAR(ROUND(pred, 4)) prediction, residual + FROM (SELECT A.pred, (A.pred - B.age) residual + FROM (SELECT cust_id, prediction(GLMR_SH_Regr_sample using *) pred + FROM mining_data_test_v) A, + mining_data_test_v B + WHERE A.cust_id = B.cust_id + ORDER BY A.pred ASC) + WHERE ROWNUM < 11; + +----------------------------------------------------------------------- +-- SCORE NEW DATA +----------------------------------------------------------------------- + +-- now that the model has a valid covariance matrix, it is possible +-- to obtain confidence bounds. +SELECT * + FROM (SELECT CUST_ID, + PREDICTION(GLMR_SH_Regr_sample USING *) pr, + PREDICTION_BOUNDS(GLMR_SH_Regr_sample USING *).lower pl, + PREDICTION_BOUNDS(GLMR_SH_Regr_sample USING *).upper pu + FROM mining_data_apply_v + ORDER BY CUST_ID) + WHERE ROWNUM < 11 +ORDER BY CUST_ID; diff --git a/dmglrdemo.java b/dmglrdemo.java new file mode 100644 index 0000000..aff7f6d --- /dev/null +++ b/dmglrdemo.java @@ -0,0 +1,787 @@ +// Copyright (c) 2004, 2006, Oracle. All rights reserved. +// File: dmglmrdemo.java +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to solve a regression problem using Support Vector Machines (GLM) algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* Given demographic, purchase, and affinity card membership data for a set of +* customers, predict customer's age. Since age is a continuous variable, this +* is a regression problem. +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the +* previous affinity card programs. Data exploration and preparing the data is a +* common step before doing data mining. Here in this demo, the following views are +* created in the user schema using CUSTOMERS, COUNTRIES, and +* SUPPLIMENTARY_DEMOGRAPHICS tables. +* +* MINING_DATA_BUILD_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for building the model. +* +* MINING_DATA_TEST_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for testing the model. +* +* MINING_DATA_APPLY_V: +* This view collects the prospective customers' demographics, purchasing, +* and affinity card response details for predicting customer's age. +* +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Prepare Data: +* 1. Missing Value treatment for Predictors in Build, Test, and Apply data +* See dmsvcdemo.java for a definition of missing values, and the steps to be +* taken for missing value imputation. GLM interprets all NULL values for a +* given attribute as "sparse". We skip missing values treatment in this demo. +* +* 2. Outlier/Clipping Treatment for Predictors for Build data +* See dmsvcdemo.java for discussion on outlier treatment. We skip outlier +* treatment in this demo. +* +* 3. Normalize Predictors in Build, Test, and Apply data. +* See dmsvcdemo.java for discussion on normalization treatment. The target is +* also normalized for GLM regression to achieve convergence of model builds +* with better performance. +* +* NOTE: AGE is the only predictor with continuous values in this dataset. +* +* The PrepareData() method in this demo program illustrates the preparation of the +* build, test, and apply data. +* +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a regression model using GLM algorithm. +* +* Test Model: +* Regression models performance can be evaluated by computing different types +* of error rates. The testModel() or computeTestMetrics() method illustrates how +* to perform the test operation to compute various error rates. +* +* Apply Model: +* Predicting the target attribute values is the prime function of regression +* models. The applyModel() method illustrates how to predict the customer's age. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +// Generic Java api imports +import java.math.BigDecimal; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; + +import java.text.DecimalFormat; +import java.text.MessageFormat; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.MiningAlgorithm; +import javax.datamining.MiningFunction; +import javax.datamining.NamedObject; +import javax.datamining.base.AlgorithmSettings; +import javax.datamining.base.Model; +import javax.datamining.base.Task; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.ModelSignature; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.data.SignatureAttribute; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.supervised.regression.RegressionApplySettings; +import javax.datamining.supervised.regression.RegressionApplySettingsFactory; +import javax.datamining.supervised.regression.RegressionModel; +import javax.datamining.supervised.regression.RegressionSettings; +import javax.datamining.supervised.regression.RegressionSettingsFactory; +import javax.datamining.supervised.regression.RegressionTestMetrics; +import javax.datamining.supervised.regression.RegressionTestMetricsTask; +import javax.datamining.supervised.regression.RegressionTestMetricsTaskFactory; +import javax.datamining.supervised.regression.RegressionTestTask; +import javax.datamining.supervised.regression.RegressionTestTaskFactory; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; +import javax.datamining.task.apply.DataSetApplyTask; +import javax.datamining.task.apply.DataSetApplyTaskFactory; + + +import oracle.dmt.jdm.algorithm.glm.OraGLMClassificationSettings; +import oracle.dmt.jdm.algorithm.glm.OraGLMRegressionSettings; +import oracle.dmt.jdm.algorithm.glm.OraGLMSettingsFactory; +import oracle.dmt.jdm.base.OraBuildSettings; +import oracle.dmt.jdm.base.OraTask; +import oracle.dmt.jdm.modeldetail.glm.OraGLMModelDetail; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.supervised.regression.OraRegressionApplySettings; +import oracle.dmt.jdm.supervised.regression.OraRegressionTestMetrics; +import oracle.dmt.jdm.task.OraBuildTask; +import oracle.dmt.jdm.transform.OraExpressionTransform; +import oracle.dmt.jdm.transform.OraTransformationFactory; +import oracle.dmt.jdm.transform.OraTransformationSequence; + +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to solve a regression problem using Support Vector Machines (GLM) algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* Given demographic, purchase, and affinity card membership data for a set of +* customers, predict customer's age. Since age is a continuous variable, this +* is a regression problem. +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the +* previous affinity card programs. Data exploration and preparing the data is a +* common step before doing data mining. Here in this demo, the following views are +* created in the user schema using CUSTOMERS, COUNTRIES, and +* SUPPLIMENTARY_DEMOGRAPHICS tables. +* +* MINING_DATA_BUILD_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for building the model. +* +* MINING_DATA_TEST_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for testing the model. +* +* MINING_DATA_APPLY_V: +* This view collects the prospective customers' demographics, purchasing, +* and affinity card response details for predicting customer's age. +* +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Prepare Data: +* 1. Missing Value treatment for Predictors in Build, Test, and Apply data +* See dmsvcdemo.java for a definition of missing values, and the steps to be +* taken for missing value imputation. GLM interprets all NULL values for a +* given attribute as "sparse". We skip missing values treatment in this demo. +* +* 2. Outlier/Clipping Treatment for Predictors for Build data +* See dmsvcdemo.java for discussion on outlier treatment. We skip outlier +* treatment in this demo. +* +* 3. Normalize Predictors in Build, Test, and Apply data. +* See dmsvcdemo.java for discussion on normalization treatment. The target is +* also normalized for GLM regression to achieve convergence of model builds +* with better performance. +* +* NOTE: AGE is the only predictor with continuous values in this dataset. +* +* The PrepareData() method in this demo program illustrates the preparation of the +* build, test, and apply data. +* +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a regression model using GLM algorithm. +* +* Test Model: +* Regression models performance can be evaluated by computing different types +* of error rates. The testModel() or computeTestMetrics() method illustrates how +* to perform the test operation to compute various error rates. +* +* Apply Model: +* Predicting the target attribute values is the prime function of regression +* models. The applyModel() method illustrates how to predict the customer's age. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +public class dmglrdemo extends Object { +// Java Data Mining (JDM) standard api imports +// Oracle Java Data Mining (JDM) implemented api imports + + + // Connection related data members + private static javax.datamining.resource.Connection m_dmeConn; + private static javax.datamining.resource.ConnectionFactory m_dmeConnFactory; + // Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static RegressionSettingsFactory m_regrFactory; + private static OraGLMSettingsFactory m_glmrFactory; + private static BuildTaskFactory m_buildFactory; + private static DataSetApplyTaskFactory m_dsApplyFactory; + private static RegressionTestTaskFactory m_testFactory; + private static RegressionApplySettingsFactory m_applySettingsFactory; + private static RegressionTestMetricsTaskFactory m_testMetricsTaskFactory; + private static OraTransformationFactory m_xformFactory = null; + // Global constants + private static DecimalFormat m_df = new DecimalFormat("##.##"); + // Global data members + private static boolean m_displayModelDetails = false; + + public static void main( String args[] ) { + try { + if ( args.length != 3 ) { + System.out.println("Usage: java dmglrdemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + // 1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@"+uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Build a model + buildModel(); + // 5a. Test model - To compute different type of error rates for the + // model from a test input data. + testModel(); + // 5b. Test model - To compute different type of error rates for the + // model from an apply output data. + //computeTestMetrics(); + // 6. Apply the model + applyModel(); + } catch(Exception anyExp) { + anyExp.printStackTrace(System.out); + } finally { + try { + // 8. Logout from the Data Mining Engine + m_dmeConn.close(); + } catch(Exception anyExp1) { }//Ignore + } + } + + /** + * Initialize all object factories used in the demo program. + * + * @exception JDMException if factory initalization failed + */ + public static void initFactories() throws JDMException + { + m_pdsFactory = (PhysicalDataSetFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalDataSet"); + m_paFactory = (PhysicalAttributeFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalAttribute"); + m_regrFactory = (RegressionSettingsFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.regression.RegressionSettings"); + m_glmrFactory = (OraGLMSettingsFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.algorithm.glm.OraGLMSettings"); + m_buildFactory = (BuildTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.BuildTask"); + m_dsApplyFactory = (DataSetApplyTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.apply.DataSetApplyTask"); + m_testFactory = (RegressionTestTaskFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.regression.RegressionTestTask"); + m_applySettingsFactory = (RegressionApplySettingsFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.regression.RegressionApplySettings"); + m_testMetricsTaskFactory = (RegressionTestMetricsTaskFactory) m_dmeConn.getFactory( + "javax.datamining.supervised.regression.RegressionTestMetricsTask"); + m_xformFactory = (OraTransformationFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.transform.OraTransformation" ); + } + + /** + * This method illustrates how to build mining model using + * GLMR_NORM_DATA_BUILD_JDM dataset and regression settings with + * GLM algorithm. + * + * By default GLM algorithm chooses a kernel type automatically. This + * choice can be overriden by the user. Linear kernel is preferred for high + * dimensional data, and Gaussian kernel for low dimensional data. Here we use + * Gaussian kernel in this demo. + * + * @exception JDMException if model build failed + */ + public static void buildModel() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Build Model ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = m_pdsFactory.create("MINING_DATA_BUILD_V", false); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + buildData.addAttribute(pa); + m_dmeConn.saveObject("glmrBuildData_jdm", buildData, true); + // 2. Create & save Mining Function Settings + // 2. Create & save Mining Function Settings + // Create GLMC algorithm settings + OraGLMRegressionSettings glmrAlgo = m_glmrFactory.createGLMRegressionSettings(); + glmrAlgo.setDiagnosticsTableName("GLMR_DIAGNOSTICS_TABLE_JDM"); + + //Create TransformationSequence + OraExpressionTransform exprXform = m_xformFactory.createExpressionTransform(); + //Exclude PRINTER_SUPPLIES, CUST_INCOME_LEVEL and BOOKKEEPING_APPLICATION + //to avoid singularities in the data that lead to invalid covariance matrix. + //(When expression is specified as null those attributes will be excluded) + exprXform.addAttributeExpression("PRINTER_SUPPLIES", null, null); + exprXform.addAttributeExpression("CUST_INCOME_LEVEL", null, null); + exprXform.addAttributeExpression("BOOKKEEPING_APPLICATION", null, null); + //Output view can be specified a null in this case, because we are + //not intended to create a view but embed the expression transformations + //with the model + OraTransformationSequence xformSeq = m_xformFactory.createTransformationSequence( + "MINING_DATA_BUILD_V", exprXform, null ); + m_dmeConn.saveObject("glmrTSExcludeAttrs_jdm", xformSeq, true); + + // Create RegressionSettings + RegressionSettings buildSettings = m_regrFactory.create(); + buildSettings.setAlgorithmSettings(glmrAlgo); + buildSettings.setTargetAttributeName("AGE"); + ((OraBuildSettings)buildSettings).useAutomatedDataPreparations(true); + m_dmeConn.saveObject("glmrBuildSettings_jdm", buildSettings, true); + // 3. Create, save & execute Build Task + BuildTask buildTask = m_buildFactory.create( + "glmrBuildData_jdm", //Build data specification + "glmrBuildSettings_jdm", //Mining function settings name + "glmrModel_jdm" //Mining model name + ); + buildTask.setDescription("glmrBuildTask_jdm"); + //Specify expression transformations that are defined to exclude attributes + //as an embedded transformation to the model build + ((OraBuildTask)buildTask).setTransformationSequenceName("glmrTSExcludeAttrs_jdm"); + executeTask(buildTask, "glmrBuildTask_jdm"); + // 4. Restore the model from the DME and explore the details of the model + RegressionModel model = + (RegressionModel)m_dmeConn.retrieveObject( + "glmrModel_jdm", NamedObject.model); + // Display model build settings + RegressionSettings retrievedBuildSettings = + (RegressionSettings)model.getBuildSettings(); + if(buildSettings == null) + System.out.println("Failure to restore build settings."); + else + displayBuildSettings(retrievedBuildSettings, "glmrBuildSettings_jdm"); + // Display model signature + displayModelSignature((Model)model); + // To display model details enable explicitely by setting m_displayModelDetails to true + displayGLMRModelDetails(model); + } + + /** + * This method illustrates how to test the mining model with the + * GLMR_NORM_DATA_TEST_JDM dataset using regression test task. After + * completion of the task, a regression test metrics object is created + * in the DMS. Regression test metrics object encapsulates + * different types of error rates. + * + * @exception JDMException if model test failed + */ + public static void testModel() + throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Test Model - using test input table ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet testData = m_pdsFactory.create( + "MINING_DATA_TEST_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + testData.addAttribute( pa ); + m_dmeConn.saveObject( "glmrTestData_jdm", testData, true ); + // 2. Create, store & execute Test Task + RegressionTestTask testTask = m_testFactory.create( + "glmrTestData_jdm", "glmrModel_jdm", "glmrTestMetrics_jdm" ); + // 3. Store & execute the task + boolean isTaskSuccess = executeTask(testTask, "glmrTestTask_jdm"); + if( isTaskSuccess ) { + // 4. Restore & display test metrics + RegressionTestMetrics testMetrics = + (RegressionTestMetrics)m_dmeConn.retrieveObject( + "glmrTestMetrics_jdm", + NamedObject.testMetrics ); + // 5. Display regression test metrics + displayTestMetricDetails(testMetrics); + } + } + + /** + * This method illustrates how to compute test metrics using + * an apply output table that has actual and predicted target values. Here the + * apply operation is done on the GLMR_NORM_DATA_TEST_JDM dataset. It creates + * an apply output table with actual and predicted target values. Using + * RegressionTestMetricsTask test metrics are computed. This produces + * the same test metrics results as RegressionTestTask. + * + * @exception JDMException if model test failed + */ + public static void computeTestMetrics() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Test Model - using apply output table ---"); + System.out.println("---------------------------------------------------"); + // 1. Do the apply on test data to create an apply output table + // Create & save PhysicalDataSpecification + PhysicalDataSet applyData = + m_pdsFactory.create( "MINING_DATA_TEST_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "glmrTestApplyData_jdm", applyData, true ); + // 2. Create & save RegressionApplySettings + RegressionApplySettings regreAS = m_applySettingsFactory.create(); + HashMap sourceAttrMap = new HashMap(); + sourceAttrMap.put( "AGE", "AGE" ); + regreAS.setSourceDestinationMap( sourceAttrMap ); + m_dmeConn.saveObject( "glmrTestApplySettings_jdm", regreAS, true); + // 3. Create, store & execute apply Task + DataSetApplyTask applyTask = m_dsApplyFactory.create( + "glmrTestApplyData_jdm", "glmrModel_jdm", "glmrTestApplySettings_jdm", + "GLMR_TEST_APPLY_OUTPUT_JDM"); + if(executeTask(applyTask, "glmrTestApplyTask_jdm")) { + // 4. Generate test metrics on the above new created apply output table + // Create & save PhysicalDataSpecification + PhysicalDataSet applyOutputData = m_pdsFactory.create( + "GLMR_TEST_APPLY_OUTPUT_JDM", false ); + applyOutputData.addAttribute( pa ); + m_dmeConn.saveObject( "glmrTestApplyOutput_jdm", applyOutputData, true ); + // 5. Create a RegressionTestMetricsTask + RegressionTestMetricsTask testMetricsTask = + m_testMetricsTaskFactory.create( "glmrTestApplyOutput_jdm", // apply output data used as input + "AGE", // actual target column + "PREDICTION", // predicted target column + "glrComputeTestMetrics_jdm" // test metrics result name + ); + // 6. Store & execute the task + boolean isTaskSuccess = executeTask(testMetricsTask, "glmrTestMetricsTask_jdm"); + if( isTaskSuccess ) { + // 7. Restore & display test metrics + RegressionTestMetrics testMetrics = + (RegressionTestMetrics)m_dmeConn.retrieveObject( + "glrComputeTestMetrics_jdm", + NamedObject.testMetrics ); + // 8. Display regression test metrics + displayTestMetricDetails(testMetrics); + } + } + } + + /** + * This method illustrates how to apply mining model on + * GLMR_NORM_DATA_APPLY_JDM dataset to predict customer's age. + * After completion of the task apply output table with the + * predicted results is created at the user specified location. + * + * @exception JDMException if model apply failed + */ + public static void applyModel() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Apply Model ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = + m_pdsFactory.create("MINING_DATA_APPLY_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "glmrApplyData_jdm", applyData, true ); + // 2. Create & save RegressionApplySettings + RegressionApplySettings regrAS = m_applySettingsFactory.create(); + m_dmeConn.saveObject( "glmrApplySettings_jdm", regrAS, true); + // 3. Create, store & execute apply Task + DataSetApplyTask applyTask = m_dsApplyFactory.create( + "glmrApplyData_jdm", "glmrModel_jdm", "glmrApplySettings_jdm", + "GLMR_APPLY_OUTPUT_JDM"); + executeTask(applyTask, "glmrApplyTask_jdm"); + // 4. Display apply result + displayTable("GLMR_APPLY_OUTPUT_JDM", + "where ROWNUM < 11", + "order by CUST_ID"); + } + + /** + * This method stores the given task with the specified name in the DMS + * and submits the task for asynchronous execution in the DMS. After + * completing the task successfully it returns true. If there is a task + * failure, then it prints error description and returns false. + * + * @param taskObj task object + * @param taskName name of the task + * + * @return boolean returns true when the task is successful + * @exception JDMException if task execution failed + */ + public static boolean executeTask(Task taskObj, String taskName) + throws JDMException { + boolean isTaskSuccess = false; + ((OraTask)taskObj).overwriteOutput(true); + m_dmeConn.saveObject(taskName, taskObj, true); + ExecutionHandle execHandle = m_dmeConn.execute(taskName); + System.out.print(taskName + " is started, please wait. "); + //Wait for completion of the task + ExecutionStatus status = execHandle.waitForCompletion(Integer.MAX_VALUE); + //Check the status of the task after completion + isTaskSuccess = status.getState().equals(ExecutionState.success); + if( isTaskSuccess ) { + //Task completed successfully + System.out.println(taskName + " is successful."); + } else {//Task failed + System.out.println(taskName + " is failed.\nFailure Description: " + + status.getDescription() ); + } + return isTaskSuccess; + } + + private static void displayBuildSettings( + RegressionSettings regrSettings, String buildSettingsName) + { + // Display build settings table + System.out.println("BuildSettings Details from the " + + buildSettingsName + " table:"); + displayTable(buildSettingsName, "", "order by SETTING_NAME"); + // Display build settings object obtained from the model + System.out.println("BuildSettings Details from the " + + buildSettingsName + " object:"); + String objName = regrSettings.getName(); + if(objName != null) + System.out.println("Name = " + objName); + String objDescription = regrSettings.getDescription(); + if(objDescription != null) + System.out.println("Description = " + objDescription); + java.util.Date creationDate = regrSettings.getCreationDate(); + String creator = regrSettings.getCreatorInfo(); + String targetAttrName = regrSettings.getTargetAttributeName(); + System.out.println("Target attribute name = " + targetAttrName); + AlgorithmSettings algoSettings = regrSettings.getAlgorithmSettings(); + if(algoSettings == null) + System.out.println("Failure: regrSettings.getAlgorithmSettings() returns null"); + MiningAlgorithm algo = algoSettings.getMiningAlgorithm(); + if(algo == null) System.out.println("Failure: algoSettings.getMiningAlgorithm() returns null"); + System.out.println("Algorithm Name: " + algo.name()); + MiningFunction function = regrSettings.getMiningFunction(); + if(function == null) System.out.println("Failure: regrSettings.getMiningFunction() returns null"); + System.out.println("Function Name: " + function.name()); + // List of GLM algorithm settings availabe + + String diagnsticsTableName = ((OraGLMRegressionSettings)algoSettings).getDiagnosticsTableName(); + System.out.println("Diagnostics Table Name: " + diagnsticsTableName); + + boolean useRidge = ((OraGLMRegressionSettings)algoSettings).useRidgeRegression(); + System.out.println("Use Ridge Regression: " + useRidge); + + } + + /** + * This method displayes GLMR model signature. + * + * @param model model object + * @exception JDMException if failed to retrieve model signature + */ + public static void displayModelSignature(Model model) throws JDMException + { + String modelName = model.getName(); + System.out.println("Model Name: " + modelName); + ModelSignature modelSignature = model.getSignature(); + System.out.println("Model Signature: ( Attribute Name, Attribute Type )"); + MessageFormat mfSign = new MessageFormat(" ( {0}, {1} )"); + String[] vals = new String[2]; + Collection sortedSet = modelSignature.getAttributes(); + Iterator attrIterator = sortedSet.iterator(); + while(attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute)attrIterator.next(); + vals[0] = attr.getName(); + vals[1] = attr.getDataType().name(); + System.out.println( mfSign.format(vals) ); + } + } + + /** + * This method displays GLMR model details. The coefficient indicates the + * relative influence of a given (attribute, value). A negative coefficient + * value indicates a negative influence. + * + * @param model glm regression model object + * @exception JDMException if failed to retrieve model details + */ + public static void displayGLMRModelDetails( + Model model) throws JDMException + { + // Obtains model details + OraGLMModelDetail glmrModelDetails = + (OraGLMModelDetail)model.getModelDetail(); + //Get computer high-level statitics of the model + Map glblDetails = glmrModelDetails.getGlobalDetails(); + if(m_displayModelDetails) { + System.out.println("Global Model details:"); + System.out.println(glblDetails.toString()); + } + //Get all attribute coefficients without any filters + ResultSet rsGLM = glmrModelDetails.getAttributeCoefficients(null, null, null, null); + //Display first coeficcient record + try { + rsGLM.next(); + if(m_displayModelDetails) { + System.out.println("Target value " + rsGLM.getString("CLASS") ); + System.out.println("Attribute name " + rsGLM.getString("ATTRIBUTE_NAME")); + System.out.println("Attribute value " + rsGLM.getString("ATTRIBUTE_VALUE")); + System.out.println("Coefficient " + rsGLM.getDouble("COEFFICIENT")); + System.out.println("Standard Error " + rsGLM.getDouble("STD_ERROR")); + System.out.println("Test static " + rsGLM.getDouble("TEST_STATISTIC")); + System.out.println("P Value " + rsGLM.getDouble("P_VALUE")); + System.out.println("Variance Inflation Factor " + rsGLM.getDouble("VIF")); + System.out.println("Std. Coefficient " + rsGLM.getDouble("STD_COEFFICIENT")); + System.out.println("Lower Coefficient Limit " + rsGLM.getDouble("LOWER_COEFF_LIMIT")); + System.out.println("Upper Coefficient Limit " + rsGLM.getDouble("UPPER_COEFF_LIMIT")); + System.out.println("Exp Coefficient " + rsGLM.getDouble("EXP_COEFFICIENT")); + System.out.println("Exp Lower Coefficient " + rsGLM.getDouble("EXP_LOWER_COEFF_LIMIT")); + System.out.println("Exp Upper Coefficient " + rsGLM.getDouble("EXP_UPPER_COEFF_LIMIT")); + } + } catch(SQLException anyExp) { + anyExp.printStackTrace(); + } + //After using the details must close the statement associated with the resultset and the resultset + Statement stmtGLM = null; + try { + stmtGLM = rsGLM.getStatement(); + rsGLM.close(); + stmtGLM.close(); + } catch(SQLException anyExp) { + + } finally { + try { if(rsGLM != null) rsGLM.close(); } catch(SQLException sqlExp) {} + } + } + + /** + * Display regression test metrics object + * + * @param testMetrics classification test metrics object + * @exception JDMException if failed to retrieve test metric details + */ + public static void displayTestMetricDetails( + RegressionTestMetrics testMetrics) throws JDMException + { + //Retrieve Oracle GLMR model test metrics deatils extensions + // Name + System.out.println("Test Metrics Name = " + testMetrics.getName()); + // Model Name + System.out.println("Model Name = " + testMetrics.getModelName()); + // Test Data Name + System.out.println("Test Data Name = " + testMetrics.getTestDataName()); + // Mean Absolute Error + System.out.println("Mean Absolute Error = " + m_df.format(testMetrics.getMeanAbsoluteError().doubleValue())); + // Mean Actual Value + System.out.println("Mean Actual Value = " + m_df.format(testMetrics.getMeanActualValue().doubleValue())); + // Mean Predicted Value + System.out.println("Mean Predicted Value = " + m_df.format(testMetrics.getMeanPredictedValue().doubleValue())); + // Root Mean Squared Error + System.out.println("Root Mean Squared Error = " + m_df.format(testMetrics.getRMSError().doubleValue())); + } + + private static void displayTable(String tableName, String whereCause, String orderByColumn) + { + StringBuffer emptyCol = new StringBuffer(" "); + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + PreparedStatement pStmt = null; + ResultSet rs = null; + try + { + pStmt = dbConn.prepareStatement("SELECT * FROM " + tableName + " " + whereCause + " " + orderByColumn); + rs = pStmt.executeQuery(); + ResultSetMetaData rsMeta = rs.getMetaData(); + int colCount = rsMeta.getColumnCount(); + StringBuffer header = new StringBuffer(); + System.out.println("Table : " + tableName); + // Build table header + for(int iCol=1; iCol<=colCount; iCol++) + { + String colName = rsMeta.getColumnName(iCol); + header.append(emptyCol.replace(0, colName.length(), colName)); + emptyCol = new StringBuffer(" "); + } + System.out.println(header.toString()); + // Write table data + while(rs.next()) + { + StringBuffer rowContent = new StringBuffer(); + for(int iCol=1; iCol<=colCount; iCol++) + { + int sqlType = rsMeta.getColumnType(iCol); + Object obj = rs.getObject(iCol); + String colContent = null; + + if(obj instanceof java.lang.Number) + { + try + { + BigDecimal bd = (BigDecimal)obj; + if(bd.scale() > 5) + { + colContent = m_df.format(obj); + } else + { + colContent = bd.toString(); + } + } catch(Exception anyExp) { + colContent = m_df.format(obj); + } + } else + { + if(obj == null) + colContent = "NULL"; + else + colContent = obj.toString(); + } + rowContent.append(" "+emptyCol.replace(0, colContent.length(), colContent)); + emptyCol = new StringBuffer(" "); + } + System.out.println(rowContent.toString()); + } + } catch(Exception anySqlExp) { + anySqlExp.printStackTrace(); + } // Ignore + } + + private static void clean() + { + //Drop prepared views + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + Statement stmt = null; + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP TABLE GLMR_DIAGNOSTICS_TABLE_JDM purge"); + } catch(SQLException anySqlExp) {}//Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + //Drop the model + try { + m_dmeConn.removeObject("glmrModel_jdm", NamedObject.model); + } catch(JDMException jdmExp) {} + } +} diff --git a/dmhpdemo.sql b/dmhpdemo.sql new file mode 100644 index 0000000..08349bb --- /dev/null +++ b/dmhpdemo.sql @@ -0,0 +1,1885 @@ +Rem +Rem $Header: dmhpdemo.sql 08-oct-2006.20:42:26 sylin Exp $ +Rem +Rem dmhpdemo.sql +Rem +Rem Copyright (c) 2005, 2006, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmhpdemo.sql - Demo for the Hierarchical Profiler package DBMS_HPROF +Rem +Rem DESCRIPTION +Rem dbmshpro_demo package demonstrates how to generate html reports from +Rem dbms hierarchical profiler tables. +Rem +Rem NOTES +Rem The Hierarchical Profiler produces hierarchical profiler information +Rem from the raw trace and stored them in the follwoing tables: +Rem dbmshp_runs - information on hierarchical profiler runs. +Rem dbmshp_function_info - information on each function profiled. +Rem dbmshp_parent_child_info - parent-child level profiler information. +Rem +Rem The analyze_reports procedures in dbmshpro_demo package produces +Rem a collection of html reports that present information derived from the +Rem raw profiler output stored in the hierarchical profiler tables. +Rem +Rem MODIFIED (MM/DD/YY) +Rem lvbcheng 09/18/06 - Add comments +Rem sylin 04/11/05 - Created +Rem + +/**************************************************************************** + * + * The following example illustrates how to use dbms hierarchical profiler + * package dbms_hprof to collect, analyze profile information, and then + * use this dbmshpro_demo package to produce useful html reports. + * + * Before start collecting any hierarchical profiler information, use + * dbmshptab.sql script in rdbms/admin directory to create the tables + * required for persistently storing the hierarchical profiler data. + * + * Profiling program. + * + * Example: + * + * 1. Create directory object for hierarchical profiler. + * - connect say SYS or someone else who can create + * directory objects. + * connect sys/ as sysdba; + * - create directory "plshprof_dir" as '/home/dbmshpdemo/plshprof'; + * - grant read on directory "plshprof_dir" to dbmshpdemo; + * - grant write on directory "plshprof_dir" to dbmshpdemo; + * + * 2. Profiling program + * sqlplus dbmshpdemo/dbmshpdemo + * execute dbms_hprof.start_profiling('plshprof_dir', 'test1.trc'); + * execute test; + * execute dbms_hprof.stop_profiling; + * + * 3. Analyzing the raw trace data generated by step 2 and get the runid from + * the dbms_hprof.analyze run. + * DECLARE + * runid number; + * BEGIN + * runid := dbms_hprof.analyze('plshprof_dir', 'test1.trc', + * run_comment =>'First run of test'); + * END; + * / + * + * 4. Use dbmshpro_demo.analyze to generate useful html reports. + * + * DECLARE + * runid1 number; + * BEGIN + * runid1 := dbms_hprof.analyze('plshprof_dir', 'test1.trc', + * run_comment =>'First run of test'); + * dbmshpro_demo.analyze_reports('plshprof_dir', 'test1', runid); + * END; + * / + * + * 6. Modify test program to improve performance. + * + * 7. Repeat step 2 to get a new raw trace output file, test2.trc. + * + * 8. Repeat step 3 with the new raw trace output file from step 6. + * + * 9. Use dbmshpro_demo.analyze to generate useful html diff reports for + * the 2 runs. + * + * BEGIN + * dbmshpro_demo.analyze_reports(location, 'testdif', runid1, runid2); + * END; + * / + ***************************************************************************/ + +CREATE OR REPLACE PACKAGE dbmshpro_demo AUTHID CURRENT_USER IS + /* analyze_reports takes a location, a file name and a run_id + * and generates a report based on data collected in the trace + * file located at directory object with run_id + * . + * + * ARGUMENTS: + * location - a directory object that points to a directory on the + * server file system where the trace file can be found. + * fname - file name of the trace file. + * run_id - target run id. + */ + PROCEDURE analyze_reports(location IN VARCHAR2, + fname IN VARCHAR2, + run_id IN NUMBER); + + /* This analyze_reports overload takes two run numbers to generate a diff + * report of the two runs. + */ + PROCEDURE analyze_reports(location IN VARCHAR2, + fname IN VARCHAR2, + run1_id IN NUMBER, + run2_id IN NUMBER); +END dbmshpro_demo; +/ +show errors + +CREATE OR REPLACE PACKAGE BODY dbmshpro_demo IS + + DBMSHP_SUBTREETIME CONSTANT PLS_INTEGER := 1; + DBMSHP_FUNCTIONTIME CONSTANT PLS_INTEGER := 2; + DBMSHP_CALLS CONSTANT PLS_INTEGER := 3; + DBMSHP_NAME CONSTANT PLS_INTEGER := 4; + DBMSHP_MEAN_SUBTREETIME CONSTANT PLS_INTEGER := 5; + DBMSHP_MEAN_FUNCTIONTIME CONSTANT PLS_INTEGER := 6; + DBMSHP_FILE_LINE_SIZE CONSTANT PLS_INTEGER := 32767; + + TYPE NumList IS TABLE OF NUMBER(38,1); + TYPE NumList2 IS TABLE OF NUMBER(38,0); + TYPE NameList IS TABLE OF VARCHAR2(4000); + TYPE RawList IS TABLE OF RAW(32); + CRLF VARCHAR2(2 char) := ' +'; + + runid NUMBER; + runid2 NUMBER; + namebuf VARCHAR2(200); + buf VARCHAR2(32767) := ''; + myclob CLOB; + page_size INTEGER; + sql_stmt VARCHAR2(4000); + total_time NUMBER; + total_calls NUMBER; + filelocation VARCHAR2(200); + filename VARCHAR2(200); + fullname VARCHAR2(300); + time_mode VARCHAR2(20); + units VARCHAR2(20) := ' (microsecs) '; + perf_time1 NUMBER(38,0); + perf_time2 NUMBER(38,0); + + /* Internal routine to write data to target file. + * IMPLEMENTATION NOTES: + * It uses two levels of buffering, one a string buffer, + * a second one a clob. One arguably could use just the clob. + */ + PROCEDURE write_data(data VARCHAR2, flush BOOLEAN) IS + BEGIN + + IF (length(buf) + length(data) > 32767) THEN + dbms_lob.writeappend(myclob, length(buf), buf); + buf := data; + ELSE + buf := buf || data; + END IF; + + IF (flush) THEN + dbms_lob.writeappend(myclob, length(buf), buf); + buf := ''; + END IF; + END; + + PROCEDURE write_plstinfo IS + Buffer VARCHAR2(32767); + Amount BINARY_INTEGER := page_size; + Position INTEGER := 1; + file_handle UTL_FILE.FILE_TYPE; + BEGIN + + -- Open file + file_handle := UTL_FILE.FOPEN(filelocation, fullname, 'wb', + DBMSHP_FILE_LINE_SIZE); + + BEGIN + LOOP + DBMS_LOB.READ(myclob, Amount, Position, Buffer); + Position := Position + Amount; + UTL_FILE.PUT_RAW(file_handle, UTL_RAW.CAST_TO_RAW(Buffer)); + END LOOP; + + EXCEPTION + WHEN NO_DATA_FOUND THEN + dbms_output.put_line(fullname || ': *created*'); + WHEN OTHERS THEN + dbms_output.put_line(fullname || ': *failed*'); + END; + + -- Reset myclob + dbms_lob.trim(myclob, 0); + + -- Close file + UTL_FILE.FCLOSE(file_handle); + + commit; + END; + + /* Generate everything up to the title line of the HTML page body. */ + PROCEDURE report_title(title varchar2) IS + BEGIN + write_data( + '' || CRLF || + '' || CRLF || + '' || title || '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '

' || title || '

' || CRLF, + FALSE); + END; + + /* Construct namebuf with ".. (Line )" */ + PROCEDURE get_name(line VARCHAR2, owner VARCHAR2, module VARCHAR2, + function VARCHAR2) IS + + BEGIN + + IF (line IS NULL OR line = 0) THEN + IF (module IS NULL) THEN + namebuf := SUBSTR(function,1,100); + ELSE + namebuf := SUBSTR + (owner || '.' || module || '.' || function, 1, 100); + END IF; + ELSE + IF (module IS NULL) THEN + namebuf := SUBSTR(function || ' (Line '||line||')',1,100); + ELSE + namebuf := SUBSTR + (owner||'.'||module||'.'||function||' (Line '||line||')',1,100); + END IF; + END IF; + END; + + /* Generate PL/SQL Time Analysis single run start page */ + PROCEDURE single_run_start_page IS + BEGIN + + write_data( + '' || CRLF || + 'PL/SQL ' || time_mode || ' Analysis for ' || filename || + '' || CRLF || + '' || CRLF || + '

PL/SQL ' || time_mode || ' Analysis for ' || filename || + '

' || CRLF || + '

' || total_time || units || time_mode || ' and '|| total_calls || + ' function calls

' || CRLF || + '

The Hierarchical Profiler produces a collection of ' || CRLF || + 'reports that present information derived from the raw ' || CRLF || + 'profiler output in a variety of formats. The following ' || CRLF || + 'reports have been found to be the most generally useful as ' || CRLF || + 'starting points for browsing:

' || CRLF || + '

' || time_mode || units || 'Summary Reports:

' || CRLF || + '' || CRLF || + '

In addition, the following reports are also available:' || + '

' || CRLF || + '' || CRLF || '' || CRLF || '', + TRUE); + + write_plstinfo; + END; + + /* Generate start page of a difference mode report using + * runid and runid2. + * Returns FALSE if the two runids have the same total run time. + */ + FUNCTION diff_mode_start_page RETURN BOOLEAN IS + fsum1 NUMBER(38,0); + fsum2 NUMBER(38,0); + timediff NUMBER(38,0); + percent NUMBER(38,0); + perform VARCHAR2(15) := ''; + fcount PLS_INTEGER; + BEGIN + + report_title('PL/SQL ' || time_mode || units || 'Analysis - Summary Page'); + + sql_stmt := + 'SELECT SUM(function_elapsed_time) FROM dbmshp_function_info ' || + 'WHERE runid = :b1'; + EXECUTE IMMEDIATE sql_stmt INTO fsum1 USING runid; + EXECUTE IMMEDIATE sql_stmt INTO fsum2 USING runid2; + + IF (fsum1 = fsum2) THEN + write_data('

No Differences Encountered

', TRUE); + write_plstinfo; + return FALSE; + END IF; + + timediff := ABS(fsum2 - fsum1); + percent := timediff/fsum1*100; + + IF (fsum2 > fsum1) THEN + perform := 'regression'; + ELSIF (fsum2 < fsum1) THEN + perform := 'improvement'; + END IF; + + -- dbmshp_t1 view contains function level profiler information from + -- dbmshp_function_info table for a particular run specified by runid. + sql_stmt := + 'CREATE OR REPLACE VIEW dbmshp_t1 AS ' || + 'SELECT calls, function_elapsed_time ftime, symbolid sid, ' || + 'SUBSTR(decode(owner, null, '''', owner||''.'')||' || + 'decode(module,null, '''', module),1,100) mname, ' || + 'SUBSTR(decode(owner, null, '''', owner||''.'')||' || + 'decode(module, null, '''', module||''.'')||' || + 'decode(function,null, '''', function),1,100) name, ' || + 'hash, line#, namespace, subtree_elapsed_time stime ' || + 'FROM dbmshp_function_info WHERE runid = ' || runid; + + EXECUTE IMMEDIATE sql_stmt; + + -- dbmshp_t2 view contains function level profiler information from + -- dbmshp_function_info table for a particular run specified by runid2. + sql_stmt := + 'CREATE OR REPLACE VIEW dbmshp_t2 AS ' || + 'SELECT calls, function_elapsed_time ftime, symbolid sid, ' || + 'SUBSTR(decode(owner, null, '''', owner||''.'')||' || + 'decode(module,null, '''', module),1,100) mname, ' || + 'SUBSTR(decode(owner, null, '''', owner||''.'')||' || + 'decode(module, null, '''', module||''.'')||' || + 'decode(function,null, '''', function),1,100) name, ' || + 'hash, line#, namespace, subtree_elapsed_time stime ' || + 'FROM dbmshp_function_info WHERE runid = ' || runid2; + + EXECUTE IMMEDIATE sql_stmt; + + -- dbmshp_diftab view contains function level profiler differences + -- information from dbmshp_t1 and dbmshp_t2 views. + sql_stmt := + 'CREATE OR REPLACE VIEW dbmshp_diftab AS SELECT ' || + 'dbmshp_t1.name, dbmshp_t1.sid sid, dbmshp_t1.calls c1, ' || + 'dbmshp_t2.calls c2, dbmshp_t1.ftime r1, dbmshp_t2.ftime r2, ' || + 'dbmshp_t1.stime s1, dbmshp_t2.stime s2, ' || + '(dbmshp_t1.stime-dbmshp_t1.ftime) d1, ' || + '(dbmshp_t2.stime-dbmshp_t2.ftime) d2, ' || + '(dbmshp_t2.calls-dbmshp_t1.calls) calls, ' || + '(dbmshp_t2.calls-dbmshp_t1.calls)/dbmshp_t1.calls*100 callsrels, ' || + 'dbmshp_t1.namespace, dbmshp_t1.mname mname, ' || + 'dbmshp_t1.name||decode(dbmshp_t1.line#,0,'''',' || + '''(Line ''||dbmshp_t1.line#||'')'') names, ' || + 'dbmshp_t1.hash, (dbmshp_t2.ftime-dbmshp_t1.ftime) ftime, ' || + '(dbmshp_t2.ftime-dbmshp_t1.ftime)/dbmshp_t1.ftime*100 ftimerel, ' || + '(dbmshp_t2.ftime/dbmshp_t2.calls)-' || + '(dbmshp_t1.ftime/dbmshp_t1.calls) mftime, ' || + '((dbmshp_t2.ftime/dbmshp_t2.calls)-' || + '(dbmshp_t1.ftime/dbmshp_t1.calls))/' || + '(dbmshp_t1.ftime/dbmshp_t1.calls)*100 mftimerel, ' || + '(dbmshp_t2.stime-dbmshp_t1.stime) stime ' || + 'FROM dbmshp_t1, dbmshp_t2 WHERE ' || + '(substr(dbmshp_t1.name||dbmshp_t1.hash,1,100) = ' || + 'substr(dbmshp_t2.name||dbmshp_t2.hash,1,100))' || + ' AND (dbmshp_t1.namespace = dbmshp_t2.namespace) AND ' || + '(dbmshp_t1.ftime <> 0) UNION SELECT ' || + 'name, sid, calls c1, calls c2, ' || + 'ftime r1, ftime r2, stime s1, stime s2, ' || + '(stime-ftime) d1, (stime-ftime) d2, ' || + '0, 0 callsrels, namespace, ' || + 'mname, ' || + 'name||decode(line#,0,'''',''(Line ''||line#||'')'') names, ' || + 'hash, 0, 0 ftimerel, 0 mftime, 0 mftimerel, 0 ' || + 'FROM dbmshp_t1 ' || + 'WHERE ftime = 0 ' || + 'UNION SELECT ' || + 'name, sid, 0 c1, calls c2, ' || + '0 r1, ftime r2, 0 s1, stime s2, ' || + '0 d1, (stime-ftime) d2, ' || + 'calls, 0 callsrels, namespace, ' || + 'mname, ' || + 'name||decode(line#,0,'''',''(Line ''||line#||'')'') names, ' || + 'hash, ftime, 0 ftimerel, 0 mftime, 0 mftimerel, stime ' || + 'FROM dbmshp_t2 ' || + 'WHERE name NOT IN (SELECT name from dbmshp_t1) ' || + 'UNION SELECT ' || + 'name, sid, calls c1, 0 c2, ' || + 'ftime r1, 0 r2, stime s1, 0 s2, ' || + '(stime-ftime) d1, 0 d2, ' || + '-calls, 0 callsrels, namespace, ' || + 'mname, ' || + 'name||''(Line ''||line#||'')'' names, ' || + 'hash, -ftime, 0 ftimerel, 0 mftime, 0 mftimerel, -stime ' || + 'FROM dbmshp_t1 ' || + 'WHERE name NOT IN (SELECT name from dbmshp_t2)'; + + EXECUTE IMMEDIATE sql_stmt; + + write_data( + 'This analysis finds a net ' || perform || ' of ' || + '' || timediff || ' microsecs (' || time_mode || ') or ' || + percent || '% (' || fsum1 || ' versus ' || + fsum2 || ').
' || CRLF, + FALSE); + + sql_stmt := + 'SELECT COUNT(*) FROM dbmshp_diftab'; + EXECUTE IMMEDIATE sql_stmt INTO fcount; + + write_data( + 'Here is a summary of the ' || fcount || ' most important ' || + 'individual function regressions and improvements.' || CRLF || + '

Function Level Difference Reports:

' || CRLF || + '' || CRLF || '

' || + 'In addition, the following reports are also available:

' || CRLF || + '' || CRLF || '' || CRLF || '', + TRUE); + + write_plstinfo; + RETURN TRUE; + END; + + /* Generate function level summary reports sorted on a particular + * attribute. + */ + PROCEDURE function_level_report(ordertype PLS_INTEGER, + mean_report BOOLEAN) IS + orderclause VARCHAR2(100); + sortedby VARCHAR2(100); + bstime VARCHAR2(30) := ''; + bftime VARCHAR2(30) := ''; + bmstime VARCHAR2(30) := ''; + bmftime VARCHAR2(30) := ''; + bcalls VARCHAR2(30) := ''; + bname VARCHAR2(30) := ''; + mstimes NumList2; + mftimes NumList2; + stimes NumList; + ftimes NumList; + dtimes NumList; + calls NumList; + owners NameList; + modules NameList; + fnames NameList; + lines NumList; + hashtab RawList; + stimeind NUMBER(38,1); + ftimeind NUMBER(38,1); + dtimeind NUMBER(38,1); + callsind NUMBER(38,1); + + BEGIN + + IF (ordertype = DBMSHP_SUBTREETIME) THEN + orderclause := 'subtree_elapsed_time desc'; + sortedby := 'Total Subtree Time'; + bstime := ''; + ELSIF (ordertype = DBMSHP_FUNCTIONTIME) THEN + orderclause := 'function_elapsed_time desc'; + sortedby := 'Total Function Time'; + bftime := ''; + ELSIF (ordertype = DBMSHP_CALLS) THEN + orderclause := 'calls desc'; + sortedby := 'Total Number of Calls'; + bcalls := ''; + ELSIF (ordertype = DBMSHP_NAME) THEN + orderclause := + 'SUBSTR(owner||''.''||module||''.''||function, 1, 100) asc'; + sortedby := 'Name'; + bname := ''; + ELSIF (ordertype = DBMSHP_MEAN_SUBTREETIME) THEN + orderclause := '(subtree_elapsed_time/calls) desc'; + sortedby := 'Mean Subtree Time'; + bmstime := ''; + ELSIF (ordertype = DBMSHP_MEAN_FUNCTIONTIME) THEN + orderclause := '(function_elapsed_time/calls) desc'; + sortedby := 'Mean Function Time'; + bmftime := ''; + END IF; + + report_title(time_mode || ' Report' || units || 'Sorted By ' || sortedby); + + write_data( + '' || CRLF || '' || CRLF, + FALSE); + + IF (mean_report = TRUE) THEN + write_data( + '' || CRLF || + '' || CRLF, FALSE); + END IF; + + write_data( + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF, FALSE); + + sql_stmt := 'SELECT subtree_elapsed_time, function_elapsed_time, ' || + '(subtree_elapsed_time-function_elapsed_time), ' || + 'calls, owner, module, function, line#, hash, ' || + '(subtree_elapsed_time/calls), (function_elapsed_time/calls) ' || + 'FROM dbmshp_function_info ' || + 'WHERE runid = :b1 ' || + ' ORDER BY ' || orderclause; + + EXECUTE IMMEDIATE sql_stmt BULK COLLECT INTO + stimes, ftimes, dtimes, calls, owners, modules, fnames, + lines, hashtab, mstimes, mftimes + USING runid; + + FOR i in stimes.FIRST..stimes.LAST LOOP + + get_name(lines(i), owners(i), modules(i), fnames(i)); + + stimeind := stimes(i)/total_time*100; + ftimeind := ftimes(i)/total_time*100; + dtimeind := dtimes(i)/total_time*100; + callsind := calls(i)/total_calls*100; + + write_data('' || CRLF, FALSE); + + IF (mean_report = TRUE) THEN + write_data( + bmstime || mstimes(i) || '' || CRLF || + bmftime || mftimes(i) || '' || CRLF, FALSE); + END IF; + + write_data( + bstime || stimes(i) || '' || CRLF || + bstime || stimeind || '%' || CRLF || + bftime || ftimes(i) || '' || CRLF || + bftime || ftimeind || '%' || CRLF || + '' || CRLF || + '' || CRLF || + bcalls || calls(i) || '' || CRLF || + bcalls || callsind || '%' || CRLF || + bname || '' || namebuf || '' || CRLF || + '' || CRLF, FALSE); + END LOOP; + + write_data(CRLF || '
Mean Subtree TimeMean Function TimeSubtree TimeInd%Function TimeInd%Descendants TimeInd%CallsInd%Function Name
' || dtimes(i) || '' || dtimeind || '%
' || CRLF || '' || CRLF || '', + TRUE); + + write_plstinfo; + END; + + /* Generate namespace level summary report */ + PROCEDURE namespace_report IS + names NameList; + ftimes NumList; + calls Numlist; + ftimeind NUMBER(38,1); + callsind NUMBER(38,1); + BEGIN + + report_title(time_mode || ' Report' || units || ': Grouped By Namespace'); + + write_data( + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF, FALSE); + + sql_stmt := 'SELECT namespace, sum(function_elapsed_time), sum(calls) ' || + 'FROM dbmshp_function_info ' || + 'WHERE runid = :b1 group by namespace'; + + EXECUTE IMMEDIATE sql_stmt BULK COLLECT INTO + names, ftimes, calls USING runid; + + FOR i in ftimes.first..ftimes.last LOOP + ftimeind := ftimes(i)/total_time*100; + callsind := calls(i)/total_calls*100; + + write_data( + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF, FALSE); + END LOOP; + + write_data('
NamespaceFunction TimeInd%CallsInd%
' || names(i) || '' || ftimes(i) || '' || ftimeind || '%' || calls(i) || '' || callsind || '%
' || CRLF || '' || CRLF || '', TRUE); + + write_plstinfo; + END; + + /* Generate parents and children report */ + PROCEDURE parent_child_report IS + stimes NumList; + ftimes NumList; + dtimes NumList; + calls NumList; + owners NameList; + modules NameList; + fnames NameList; + lines NumList; + hashtab RawList; + pstimes NumList; + pftimes NumList; + pcalls NumList; + sids NumList; + pids NumList; + x PLS_INTEGER; + dtime NUMBER; + stimeind NUMBER(38,1); + ftimeind NUMBER(38,1); + dtimeind NUMBER(38,1); + callsind NUMBER(38,1); + + BEGIN + + report_title('Parents and Children Report with ' || + time_mode || units); + + sql_stmt := 'SELECT subtree_elapsed_time, function_elapsed_time, ' || + 'calls, owner, module, function, line#, hash, symbolid, ' || + '(subtree_elapsed_time-function_elapsed_time) ' || + 'FROM dbmshp_function_info WHERE runid = :b1 ' || + 'ORDER BY symbolid'; + + EXECUTE IMMEDIATE sql_stmt BULK COLLECT INTO + stimes, ftimes, calls, owners, modules, fnames, lines, hashtab, + sids, dtimes USING runid; + + FOR i in 1..sids.COUNT LOOP + get_name(lines(i), owners(i), modules(i), fnames(i)); + + stimeind := stimes(i)/total_time*100; + ftimeind := ftimes(i)/total_time*100; + dtimeind := dtimes(i)/total_time*100; + callsind := calls(i)/total_calls*100; + + -- Output name + write_data('' || namebuf || '' || CRLF, FALSE); + + -- Output table + write_data( + '' || CRLF || + '' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ''|| CRLF || + '' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || '' || CRLF, FALSE); + + -- output Parent info. + sql_stmt := 'SELECT parentsymid, ' || + 'subtree_elapsed_time, function_elapsed_time, calls ' || + 'FROM dbmshp_parent_child_info WHERE runid = :b1 AND ' || + 'childsymid = :b2 ORDER BY subtree_elapsed_time desc'; + + EXECUTE IMMEDIATE sql_stmt BULK COLLECT INTO + pids, pstimes, pftimes, pcalls USING runid, sids(i); + + write_data( + '' || CRLF || + ' ' || CRLF || + '' || CRLF, FALSE); + + -- entry + IF (pids.COUNT = 0) THEN + write_data( + '' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + '' || CRLF, FALSE); + END IF; + + FOR j in 1..pids.COUNT LOOP + x := pids(j); + + get_name(lines(x), owners(x), modules(x), fnames(x)); + + dtime := pstimes(j)-pftimes(j); + + IF stimes(i) = 0 THEN + stimeind := 0; + ELSE + stimeind := pstimes(j)/stimes(i)*100; + END IF; + IF ftimes(i) = 0 THEN + ftimeind := 0; + ELSE + ftimeind := pftimes(j)/ftimes(i)*100; + END IF; + IF dtimes(i) = 0 THEN + dtimeind := 0; + ELSE + dtimeind := dtime/dtimes(i)*100; + END IF; + callsind := pcalls(j)/calls(i)*100; + + write_data( + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || '' || CRLF, FALSE); + END LOOP; + + -- output children info. + sql_stmt := 'SELECT childsymid, subtree_elapsed_time, ' || + 'function_elapsed_time, calls FROM dbmshp_parent_child_info ' || + 'WHERE runid = :b1 AND parentsymid = :b2 ' || + 'ORDER BY subtree_elapsed_time desc'; + EXECUTE IMMEDIATE sql_stmt BULK COLLECT INTO pids, pstimes, + pftimes, pcalls USING runid, sids(i); + + IF pids.COUNT > 0 THEN + write_data('' || CRLF, FALSE); + END IF; + + FOR j in 1..pids.COUNT LOOP + x := pids(j); + get_name(lines(x), owners(x), modules(x), fnames(x)); + + dtime := pstimes(j)-pftimes(j); + + IF dtimes(i) = 0 THEN + stimeind := 0; + ELSE + stimeind := pstimes(j)/dtimes(i)*100; + END IF; + IF ftimes(x) = 0 THEN + ftimeind := 0; + ELSE + ftimeind := pftimes(j)/ftimes(x)*100; + END IF; + IF dtimes(x) = 0 THEN + dtimeind := 0; + ELSE + dtimeind := dtime/dtimes(x)*100; + END IF; + callsind := pcalls(j)/calls(x)*100; + + write_data( + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF, FALSE); + END LOOP; + + write_data('
Subtree TimeInd%Function TimeInd%Descendants TimeInd%CallsInd%Function Name
' || stimes(i) || '' || stimeind || '%' || ftimes(i) || '' || ftimeind || '%' || dtimes(i) || '' || dtimeind || '%' || calls(i) || '' || callsind || '%' || CRLF || + ' ' || namebuf || '' || CRLF || + '
' || CRLF || + ' Parents:' || CRLF || + '
' || stimes(i) || '100%' || ftimes(i) || '100%' || dtimes(i) || '100%' || calls(i) || '100%' || CRLF || + ' root' || CRLF || + '
' || pstimes(j) || '' || stimeind || '%' || pftimes(j) || '' || ftimeind || '%' || dtime || '' || dtimeind || '%' || pcalls(j) || '' || callsind || '%' || CRLF || + ' ' || namebuf || + '
Children:
' || pstimes(j) || '' || stimeind || '%' || pftimes(j) || '' || ftimeind || '%' || dtime || '' || dtimeind || '%' || pcalls(j) || '' || callsind || '%' || CRLF || + ' ' || namebuf || '

'|| CRLF, FALSE); + END LOOP; + + write_data('' || CRLF || '', TRUE); + + write_plstinfo; + END; + + /* Generate module level summary reports */ + PROCEDURE module_report(ordertype PLS_INTEGER) IS + orderclause VARCHAR2(100); + sortedby VARCHAR2(100); + bftime VARCHAR2(30) := ''; + bcalls VARCHAR2(30) := ''; + bname VARCHAR2(30) := ''; + ftimes NumList; + calls NumList; + fnames NameList; + owners NameList; + modules NameList; + ftimeind NUMBER(38,1); + callsind NUMBER(38,1); + + BEGIN + + IF (ordertype = DBMSHP_FUNCTIONTIME) THEN + orderclause := 'sum(function_elapsed_time) desc'; + sortedby := '(Total Module Time)'; + bftime := ''; + ELSIF (ordertype = DBMSHP_CALLS) THEN + orderclause := 'sum(calls) desc'; + sortedby := '(Total Number of Calls)'; + bcalls := ''; + ELSIF (ordertype = DBMSHP_NAME) THEN + orderclause := 'substr(owner || ''.'' || module, 1, 100) asc'; + sortedby := '(Module Name)'; + bname := ''; + END IF; + + report_title(time_mode || ' Report:' || units || + 'Group by Module Name Sorted By ' || sortedby); + + write_data( + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF, FALSE); + + sql_stmt := 'SELECT sum(function_elapsed_time), sum(calls), ' || + 'SUBSTR(owner||''.''||module, 1, 50) FROM dbmshp_function_info ' || + 'WHERE runid = :b1 ' || + 'GROUP BY module, owner ' || + ' ORDER BY ' || orderclause; + + EXECUTE IMMEDIATE sql_stmt BULK COLLECT INTO + ftimes, calls, fnames USING runid; + + FOR i in ftimes.first..ftimes.last LOOP + ftimeind := ftimes(i)/total_time*100; + callsind := calls(i)/total_calls*100; + + IF (fnames(i) = '.') THEN + fnames(i) := ''; + END IF; + + write_data( + '' || CRLF || + bftime || ftimes(i) || '' || CRLF || + bftime || ftimeind || '%' || CRLF || + bcalls || calls(i) || '' || CRLF || + bcalls || callsind || '%' || CRLF || + bname || fnames(i) || '' || CRLF || + '' || CRLF, FALSE); + END LOOP; + + write_data('
Module TimeInd%CallsInd%Module Name
' || CRLF || '' || CRLF || '', TRUE); + + write_plstinfo; + + END; + + /* Generate functions with performance improvements/regressions report */ + PROCEDURE performance_report(where_clause VARCHAR2, pmode VARCHAR2) IS + cumind NUMBER(38,1) := 0; + perf_time NUMBER(38,0); + ftimeind NUMBER(38,1); + stimes NumList; + ftimes NumList; + dtimes NumList; + calls NumList; + callrels NumList; + fnames NameList; + ftimerels NumList; + mftimes NumList2; + mtimerels NumList; + hashtab RawList; + + BEGIN + + sql_stmt := 'SELECT SUM(ftime) FROM dbmshp_diftab WHERE ' || where_clause; + EXECUTE IMMEDIATE sql_stmt INTO perf_time; + + sql_stmt := + 'SELECT calls, callsrels, names, hash, ftime, stime, (stime-ftime), ' || + 'ftimerel, mftime, mftimerel FROM dbmshp_diftab WHERE ' || + where_clause || ' ORDER BY ftime desc'; + + EXECUTE IMMEDIATE sql_stmt BULK COLLECT INTO + calls, callrels, fnames, hashtab, ftimes, stimes, dtimes, ftimerels, + mftimes, mtimerels; + + write_data( + '' || CRLF || + 'Function with Performance ' || pmode || + ': Sorted by Function Time' || units || 'Delta' || CRLF || + '' || CRLF || + '

Function ' || time_mode || units || 'Data for Performance ' || + pmode || '

' || CRLF || + 'Total ' || pmode || ': ' || abs(perf_time) || ' microsecs ' || + time_mode || '' || CRLF || + '
' || CRLF ||
+      '' ||
+      '' ||
+      '' ||
+      '' ||
+      '' ||
+      '' ||
+      '' ||
+      '' ||
+      '' ||
+      '' ||
+      '' ||
+      '' || CRLF,
+      FALSE);
+
+    FOR i in 1..fnames.COUNT LOOP
+      ftimeind := ftimes(i)/perf_time*100;
+      cumind := cumind + ftimeind;
+      IF (cumind > 100) THEN
+        cumind := 100;
+      END IF;
+      write_data(
+        '' || CRLF ||
+        '' || CRLF ||
+        '' || CRLF ||
+        ''
+          ELSE '' || ftimerels(i) || '%' END) || CRLF ||
+        '' || CRLF ||
+        '' || CRLF ||
+        '' || CRLF ||
+        '' || CRLF ||
+        ''
+          ELSE callrels(i) || '%' END) || CRLF ||
+        ''
+          ELSE mftimes(i) || '' END) || CRLF ||
+        ''
+          ELSE mtimerels(i) || '%' END) || CRLF ||
+        '' || CRLF,
+        FALSE);
+    END LOOP;
+
+    write_data('
Subtree TimeFunction Time DeltaRel%Ind%Cum%Descendants Time DeltaCalls DeltaRel%Mean Function Time DeltaRel%Function Name
' || stimes(i) || '' || ftimes(i) || '' || (CASE ftimerels(i) WHEN 0 THEN '' || ftimeind || '%' || cumind || '%' || dtimes(i) || '' || calls(i) || '' || (CASE callrels(i) WHEN 0 THEN '' || (CASE mftimes(i) WHEN 0 THEN '' || (CASE mtimerels(i) WHEN 0 THEN '' || CRLF || + '' || fnames(i) || + '
', TRUE); + write_plstinfo; + END; + + /* Generate function level difference reports sorted on a particular + * attribute. + */ + PROCEDURE diff_function_level_report(ordertype PLS_INTEGER) IS + orderclause VARCHAR2(100); + sortedby VARCHAR2(100); + bstime VARCHAR2(30) := ''; + bftime VARCHAR2(30) := ''; + bmstime VARCHAR2(30) := ''; + bmftime VARCHAR2(30) := ''; + bcalls VARCHAR2(30) := ''; + bname VARCHAR2(30) := ''; + calls NumList; + callrels NumList; + fnames NameList; + stimes NumList; + ftimes NumList; + dtimes NumList; + mftimes NumList2; + ftimerels NumList; + mtimerels NumList; + ftimeind NUMBER(38,1); + + BEGIN + IF (ordertype = DBMSHP_SUBTREETIME) THEN + orderclause := 'stime desc'; + sortedby := 'Total Subtree '; + bstime := ''; + ELSIF (ordertype = DBMSHP_FUNCTIONTIME) THEN + orderclause := 'ftime desc'; + sortedby := 'Total Function '; + bftime := ''; + ELSIF (ordertype = DBMSHP_CALLS) THEN + orderclause := 'calls desc'; + sortedby := 'Total Number of Calls '; + bcalls := ''; + ELSIF (ordertype = DBMSHP_NAME) THEN + orderclause := 'names asc'; + sortedby := 'Function Name '; + bname := ''; + END IF; + + report_title('Function ' || time_mode || units || 'Data Sorted By ' || + sortedby || time_mode || units || 'Delta for ' || filename); + + write_data( + '' || CRLF || '' || CRLF || + '' || + '' || + '' || + '' || CRLF, + FALSE); + + sql_stmt := 'SELECT SUM(ftime) FROM dbmshp_diftab WHERE ftime > 0'; + EXECUTE IMMEDIATE sql_stmt INTO perf_time1; + + sql_stmt := 'SELECT SUM(ftime) FROM dbmshp_diftab WHERE ftime < 0'; + EXECUTE IMMEDIATE sql_stmt INTO perf_time2; + + sql_stmt := + 'SELECT calls, callsrels, names, ftime, stime, (stime-ftime), ' || + 'ftimerel, mftime, mftimerel FROM dbmshp_diftab ' || + 'ORDER BY ' || orderclause; + + EXECUTE IMMEDIATE sql_stmt BULK COLLECT INTO + calls, callrels, fnames, ftimes, stimes, dtimes, ftimerels, + mftimes, mtimerels; + + FOR i in 1..fnames.COUNT LOOP + + IF (ftimes(i) < 0) THEN + ftimeind := ftimes(i)/perf_time2*100; + ELSE + ftimeind := ftimes(i)/perf_time1*100; + END IF; + + write_data( + '' || CRLF || + bstime || stimes(i) || '' || CRLF || + bftime || ftimes(i) || '' || CRLF || + bftime || (CASE ftimerels(i) WHEN 0 THEN '' + ELSE ftimerels(i) || '%' END) || CRLF || + bftime || (CASE ftimeind WHEN 0 THEN '' + ELSE ftimeind || '%' END) || CRLF || + '' || CRLF || + bcalls || calls(i) || '' || CRLF || + bcalls || (CASE callrels(i) WHEN 0 THEN '' + ELSE callrels(i) || '%' END) || CRLF || + '' + ELSE mftimes(i)|| '' END) || CRLF || + '' + ELSE mtimerels(i) || '%' END) || CRLF || + bname || '' || fnames(i) || + '' || CRLF, + FALSE); + END LOOP; + + write_data( + '
Subtree Time DeltaFunction Time DeltaRel%Ind%Descendants Time DeltaCalls DeltaRel%Mean Function Time DeltaRel%Function Name
' || dtimes(i) || '' || (CASE mftimes(i) WHEN 0 THEN '' || (CASE mtimerels(i) WHEN 0 THEN '
' || CRLF || CRLF || '' || CRLF || '', + TRUE); + + write_plstinfo; + END; + + /* Generate namespace level difference report */ + PROCEDURE diff_namespace_report IS + units VARCHAR2(20) := ' (in microsecs) '; + ftimes1 NumList; + ftimes2 NumList; + ftimes NumList; + calls NumList; + calls1 NumList; + calls2 NumList; + fnames NameList; + + BEGIN + + report_title(time_mode||' Report' || units || 'Group By Namespace'); + + write_data( + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF, FALSE); + + sql_stmt := + 'SELECT sum(r1), sum(r2), sum(ftime), ' || + 'sum(c1), sum(c2), sum(calls), namespace ' || + 'FROM dbmshp_diftab GROUP BY namespace ' || + 'ORDER BY namespace'; + + EXECUTE IMMEDIATE sql_stmt BULK COLLECT INTO + ftimes1, ftimes2, ftimes, calls1, calls2, calls, fnames; + + FOR i in ftimes.first..ftimes.last LOOP + write_data( + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF, FALSE); + END LOOP; + + write_data('
Namespace' || time_mode || 'Calls
First TraceSecond TraceDeltaFirst TraceSecond TraceDelta
' || fnames(i) || '' || ftimes1(i) || '' || ftimes2(i) || '' || ftimes(i) || '' || calls1(i) || '' || calls2(i) || '' || calls(i) || '
' || CRLF || '' || CRLF || '', TRUE); + write_plstinfo; + END; + + /* Generate module level difference report */ + PROCEDURE diff_module_report(ordertype PLS_INTEGER) IS + orderclause VARCHAR2(30); + sortedby VARCHAR2(30); + bftime VARCHAR2(30) := ''; + bcalls VARCHAR2(30) := ''; + bname VARCHAR2(30) := ''; + ftimes NumList; + fnames NameList; + calls NumList; + ftimes1 NumList; + ftimes2 NumList; + calls1 NumList; + calls2 NumList; + + BEGIN + + IF (ordertype = DBMSHP_FUNCTIONTIME) THEN + orderclause := 'delta desc'; + sortedby := 'Module Time' || units; + bftime := ''; + ELSIF (ordertype = DBMSHP_CALLS) THEN + orderclause := 'calls desc'; + sortedby := 'Call Count'; + bcalls := ''; + ELSIF (ordertype = DBMSHP_NAME) THEN + orderclause := 'mname'; + sortedby := 'Module Name'; + bname := ''; + END IF; + + report_title('Module Level Difference Report - Sorted by ' || sortedby); + + write_data( + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF, FALSE); + + sql_stmt := + 'SELECT sum(r1), sum(r2), sum(ftime) delta, ' || + 'sum(c1), sum(c2), sum(calls) calls, mname ' || + 'FROM dbmshp_diftab GROUP BY mname ' || + 'ORDER BY ' || orderclause; + + EXECUTE IMMEDIATE sql_stmt BULK COLLECT INTO + ftimes1, ftimes2, ftimes, calls1, calls2, calls, fnames; + + FOR i in ftimes.first..ftimes.last LOOP + write_data( + '' || CRLF || + '' || CRLF || + '' || CRLF || + bftime || ftimes(i) || '' || CRLF || + '' || CRLF || + '' || CRLF || + bcalls || calls(i) || '' || CRLF || + bname || fnames(i) || '' || CRLF || + '' || CRLF, FALSE); + END LOOP; + + write_data('
Module TimeCallsModule Name
First TraceSecond TraceDeltaFirst TraceSecond TraceDelta
' || ftimes1(i) || '' || ftimes2(i) || '' || calls1(i) || '' || calls2(i) || '
' || CRLF || '' || CRLF || '', TRUE); + write_plstinfo; + END; + + /* Generate parents and children difference report */ + PROCEDURE diff_parent_child_report IS + fnames NameList; + pnames NameList; + cnames NameList; + stimes NumList; + ftimes NumList; + dtimes NumList; + mftimes NumList2; + calls NumList; + mtimerels NumList; + stimes1 NumList; + stimes2 NumList; + ftimes1 NumList; + ftimes2 NumList; + dtimes1 NumList; + dtimes2 NumList; + calls1 NumList; + calls2 NumList; + hashtab RawList; + hashtab2 RawList; + ftimeind NUMBER(38,1); + stimeind NUMBER(38,1); + dtimeind NUMBER(38,1); + callsind NUMBER(38,1); + pstimes NumList; + pftimes NumList; + pcalls NumList; + sids NumList; + pids NumList; + cids NumList; + x PLS_INTEGER; + dtime NUMBER; + perform VARCHAR2(50); + fsum1 NUMBER(38,0); + fsum2 NUMBER(38,0); + csum1 NUMBER(38,0); + csum2 NUMBER(38,0); + stimeind1 NUMBER(38,1); + stimeind2 NUMBER(38,1); + ftimeind1 NUMBER(38,1); + ftimeind2 NUMBER(38,1); + dtimeind1 NUMBER(38,1); + dtimeind2 NUMBER(38,1); + callsind1 NUMBER(38,1); + callsind2 NUMBER(38,1); + mftime1 NUMBER(38,1); + mftime2 NUMBER(38,1); + mstime NUMBER(38,1); + mstime1 NUMBER(38,1); + mstime2 NUMBER(38,1); + mstimeind NUMBER(38,1); + mdtime NUMBER(38,1); + mdtime1 NUMBER(38,1); + mdtime2 NUMBER(38,1); + mdtimeind NUMBER(38,1); + + BEGIN + + -- dbmshp_pct1 view contains parent-child level profiler information from + -- dbmshp_parent_child_info and dbmshp_function_info tables for a + -- particular run specified by runid. + sql_stmt := + 'CREATE OR REPLACE VIEW dbmshp_pct1 AS SELECT ' || + 'p.parentsymid pid, p.childsymid cid, ' || + 'p.subtree_elapsed_time stime, p.function_elapsed_time ftime, ' || + 'p.calls, f.namespace, f.hash, f.line#, ' || + 'x.hash phash, x.namespace pnamespace, x.line# pline, ' || + 'SUBSTR(decode(f.owner, null, '''', f.owner||''.'')||' || + 'decode(f.module, null, '''', f.module||''.'')||' || + 'decode(f.function,null, '''', f.function),1,100) name, ' || + 'SUBSTR(decode(x.owner, null, '''', x.owner||''.'')||' || + 'decode(x.module, null, '''', x.module||''.'')||' || + 'decode(x.function,null, '''', x.function),1,100) pname ' || + 'FROM dbmshp_parent_child_info p, dbmshp_function_info f, ' || + '(select * from dbmshp_function_info) x ' || + 'WHERE f.runid = ' || runid || ' AND p.runid = ' || runid || + ' AND x.runid = ' || runid || + ' AND p.childsymid = f.symbolid' || + ' AND p.parentsymid = x.symbolid'; + EXECUTE IMMEDIATE sql_stmt; + + -- dbmshp_pct2 view contains parent-child level profiler information from + -- dbmshp_parent_child_info and dbmshp_function_info tables for a + -- particular run specified by runid2. + sql_stmt := + 'CREATE OR REPLACE VIEW dbmshp_pct2 AS SELECT ' || + 'p.parentsymid pid, p.childsymid cid, ' || + 'p.subtree_elapsed_time stime, p.function_elapsed_time ftime, ' || + 'p.calls, f.namespace, f.hash, f.line#, ' || + 'x.hash phash, x.namespace pnamespace, x.line# pline, ' || + 'SUBSTR(decode(f.owner, null, '''', f.owner||''.'')||' || + 'decode(f.module, null, '''', f.module||''.'')||' || + 'decode(f.function,null, '''', f.function),1,100) name, ' || + 'SUBSTR(decode(x.owner, null, '''', x.owner||''.'')||' || + 'decode(x.module, null, '''', x.module||''.'')||' || + 'decode(x.function,null, '''', x.function),1,100) pname ' || + 'FROM dbmshp_parent_child_info p, dbmshp_function_info f, ' || + '(select * from dbmshp_function_info) x ' || + 'WHERE f.runid = ' || runid2 || ' AND p.runid = ' || runid2 || + ' AND x.runid = ' || runid2 || + ' AND p.childsymid = f.symbolid' || + ' AND p.parentsymid = x.symbolid'; + EXECUTE IMMEDIATE sql_stmt; + + -- dbmshp_pcdiftab view contains parent-child level profiler differences + -- information from dbmshp_pct1 and dbmshp_pct2 views. + sql_stmt := + 'CREATE OR REPLACE VIEW dbmshp_pcdiftab AS SELECT ' || + 'dbmshp_pct1.pid pid, dbmshp_pct1.cid cid, ' || + '(dbmshp_pct2.stime-dbmshp_pct1.stime) stime,' || + '(dbmshp_pct2.ftime-dbmshp_pct1.ftime) ftime, ' || + '(dbmshp_pct2.calls-dbmshp_pct1.calls) calls, ' || + 'dbmshp_pct1.namespace, dbmshp_pct1.hash, ' || + 'dbmshp_pct1.pname||decode(dbmshp_pct1.pline,0,'''',' || + '''(Line ''||dbmshp_pct1.pline||'')'') pname, dbmshp_pct1.phash, ' || + 'dbmshp_pct1.name||decode(dbmshp_pct1.line#,0,'''',' || + '''(Line ''||dbmshp_pct1.line#||'')'') ' || + 'names FROM dbmshp_pct1, dbmshp_pct2 WHERE ' || + '(substr(dbmshp_pct1.name||dbmshp_pct1.hash,1,100) = ' || + 'substr(dbmshp_pct2.name||dbmshp_pct2.hash,1,100)) AND ' || + '(dbmshp_pct1.namespace = dbmshp_pct2.namespace) AND ' || + '(substr(dbmshp_pct1.pname||dbmshp_pct1.phash,1,100) = ' || + 'substr(dbmshp_pct2.pname||dbmshp_pct2.phash,1,100)) AND ' || + '(dbmshp_pct1.pnamespace = dbmshp_pct2.pnamespace) ' || + 'UNION SELECT ' || + 'pid, cid, stime, ftime, calls, namespace, hash, ' || + 'pname||decode(pline,0,'''',''(Line ''||pline||'')'') ' || + 'pname, phash, ' || + 'name||decode(line#,0,'''',''(Line ''||line#||'')'') ' || + 'names FROM dbmshp_pct2 ' || + 'WHERE name NOT IN (SELECT name from dbmshp_pct1) ' || + 'OR pname NOT IN (SELECT pname from dbmshp_pct1) ' || + 'UNION SELECT ' || + 'pid, cid, -stime, -ftime, -calls, namespace, hash, ' || + 'pname||decode(pline,0,'''',''(Line ''||pline||'')'') ' || + 'pname, phash, ' || + 'name||decode(line#,0,'''',''(Line ''||line#||'')'') ' || + 'names FROM dbmshp_pct1 ' || + 'WHERE name NOT IN (SELECT name from dbmshp_pct2) ' || + 'OR pname NOT IN (SELECT pname from dbmshp_pct2)'; + + EXECUTE IMMEDIATE sql_stmt; + + report_title('Parents and Children Difference Report with ' || + time_mode || units); + + sql_stmt := 'SELECT SUM(ftime), SUM(calls) FROM dbmshp_t1'; + EXECUTE IMMEDIATE sql_stmt INTO fsum1, csum1; + + sql_stmt := 'SELECT SUM(ftime), SUM(calls) FROM dbmshp_t2'; + EXECUTE IMMEDIATE sql_stmt INTO fsum2, csum2; + + sql_stmt := + 'SELECT calls, names, hash, ftime, stime, sid, (stime-ftime), ' || + 'mftime, mftimerel, c1, c2, r1, r2, s1, s2, d1, d2 ' || + 'FROM dbmshp_diftab ORDER BY sid'; + + EXECUTE IMMEDIATE sql_stmt BULK COLLECT INTO + calls, fnames, hashtab, ftimes, stimes, sids, dtimes, mftimes, mtimerels, + calls1, calls2, ftimes1, ftimes2, stimes1, stimes2, dtimes1, dtimes2; + + FOR i in 1..sids.COUNT LOOP + IF (ftimes(i) < 0) THEN + ftimeind := ftimes(i)/perf_time2*100; + perform := '(' || ftimeind || '% of total improvement)'; + ELSIF (ftimes(i) > 0) THEN + ftimeind := ftimes(i)/perf_time1*100; + perform := '(' || ftimeind || '% of total regression)'; + ELSE + perform := ''; + END IF; + + IF ftimes1(i) = 0 THEN + ftimeind := 0; + ELSE + ftimeind := ftimes(i)/ftimes1(i)*100; + END IF; + ftimeind1 := ftimes1(i)/fsum1*100; + ftimeind2 := ftimes2(i)/fsum2*100; + + IF stimes1(i) = 0 THEN + stimeind := 0; + ELSE + stimeind := stimes(i)/stimes1(i)*100; + END IF; + stimeind1 := stimes1(i)/fsum1*100; + stimeind2 := stimes2(i)/fsum2*100; + + IF dtimes1(i) = 0 THEN + dtimeind := 0; + ELSE + dtimeind := dtimes(i)/dtimes1(i)*100; + END IF; + dtimeind1 := dtimes1(i)/fsum1*100; + dtimeind2 := dtimes2(i)/fsum2*100; + + IF calls1(i) = 0 THEN + callsind := 0; + mftime1 := 0; + mstime1 := 0; + mdtime1 := 0; + ELSE + callsind := calls(i)/calls1(i)*100; + mftime1 := ftimes1(i)/calls1(i); + mstime1 := stimes1(i)/calls1(i); + mdtime1 := dtimes1(i)/calls1(i); + END IF; + callsind1 := calls1(i)/csum1*100; + callsind2 := calls2(i)/csum2*100; + + IF calls2(i) = 0 THEN + mftime2 := 0; + mstime2 := 0; + mdtime2 := 0; + ELSE + mftime2 := ftimes2(i)/calls2(i); + mstime2 := stimes2(i)/calls2(i); + mdtime2 := dtimes2(i)/calls2(i); + END IF; + + mstime := mstime2-mstime1; + mdtime := mdtime2-mdtime1; + + IF mstime1 = 0 THEN + mstimeind := 0; + ELSE + mstimeind := mstime/mstime1*100; + END IF; + + IF mdtime1 = 0 THEN + mdtimeind := 0; + ELSE + mdtimeind := mdtime/mdtime1*100; + END IF; + + write_data( + '

Comparision for ' || fnames(i) || '' || perform || + '

' || CRLF || + '' || CRLF || + '' || + '' || + '' || + '' || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + (CASE (ftimes1(i)+ftimes2(i)) WHEN 0 THEN '' ELSE + '' || + '' ELSE + ftimes1(i) || '' END) || + '' ELSE + ftimes2(i) || '' END) || + '' || CRLF || + '' || CRLF END) || + (CASE dtimes1(i) WHEN 0 THEN '' ELSE + '' || + '' || + '' || + '' || CRLF || + '' || CRLF || + '' || + '' || + '' || + '' || CRLF || + '' || CRLF END) || + '' || + '' ELSE + calls1(i) || '' END) || + '' ELSE + calls2(i) || '' END) || + '' || CRLF || + '' || CRLF || + (CASE (mftime1+mftime2) WHEN 0 THEN '' ELSE + '' || + '' ELSE + mftime1 || '' END) || '' || + '' ELSE + mftime2 || '' END) || '' || + '' ELSE + mftimes(i) || '' END) || + '' ELSE + mtimerels(i) || '%' END) || CRLF || + '' || CRLF END) || + (CASE mdtime1 WHEN 0 THEN '' ELSE + '' || + '' || + '' || + '' || CRLF || + '' || CRLF || + '' || + '' || + '' || + '' || CRLF || + '' || CRLF END) || '
' || fnames(i) || 'First TraceSecond TraceDiffDiff%
MeasureInd%MeasureInd%
' || + 'Function ' || time_mode || ' (microsecs)s' || (CASE ftimes1(i) WHEN 0 THEN '' || ftimeind1 || '%' || (CASE ftimes2(i) WHEN 0 THEN '' || ftimeind2 || '%' || ftimes(i) || '' || ftimeind || '%
' || + 'Descendants ' || time_mode || ' (microsecs)s' || dtimes1(i) || '' || dtimeind1 || '%' || dtimes2(i) || '' || dtimeind2 || '%' || dtimes(i) || '' || dtimeind || '%
' || + 'Subtree ' || time_mode || ' (microsecs)s' || stimes1(i) || '' || stimeind1 || '%' || stimes2(i) || '' || stimeind2 || '%' || stimes(i) || '' || stimeind || '%
' || + 'Function Calls' || (CASE calls1(i) WHEN 0 THEN '' || callsind1 || '%' || (CASE calls2(i) WHEN 0 THEN '' || callsind2 || '%' || calls(i) || '' || callsind || '%
' || + 'Mean Function ' || time_mode || ' (microsecs)s' || (CASE mftime1 WHEN 0 THEN '' || (CASE mftime2 WHEN 0 THEN '' || (CASE mftimes(i) WHEN 0 THEN '' || (CASE mtimerels(i) WHEN 0 THEN '
' || + 'Mean Descendants ' || time_mode || ' (microsecs)s' || mdtime1 || '' || mdtime2 || '' || mdtime || '' || mdtimeind || '%
' || + 'Mean Subtree ' || time_mode || ' (microsecs)s' || mstime1 || '' || mstime2 || '' || mstime || '' || mstimeind || '%

' || CRLF, + FALSE); + + -- Output name + write_data('' || fnames(i) || '' || CRLF, FALSE); + + -- Output table + write_data( + '' || CRLF || + '' || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ''|| CRLF || + '' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + '' || CRLF, FALSE); + + -- output Parent info. + sql_stmt := 'SELECT pid, stime, ftime, calls, pname, phash ' || + 'FROM dbmshp_pcdiftab WHERE names||hash = :b1 and cid = :b2 ' || + 'ORDER BY stime desc'; + + EXECUTE IMMEDIATE sql_stmt BULK COLLECT INTO + pids, pstimes, pftimes, pcalls, pnames, hashtab2 + USING fnames(i)||hashtab(i), sids(i); + + write_data( + '' || CRLF || + ' ' || CRLF || + '' || CRLF, FALSE); + + -- entry + IF (pids.COUNT = 0) THEN + write_data( + '' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + '' || CRLF, FALSE); + END IF; + + FOR j in 1..pnames.COUNT LOOP + IF (pstimes(j) <> 0 OR pftimes(j) <> 0) THEN + dtime := pstimes(j)-pftimes(j); + + write_data( + '' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + ' ' || CRLF || + '' || CRLF, FALSE); + END IF; + END LOOP; + + -- output children info. + sql_stmt := 'SELECT cid, stime, ftime, calls, names, hash ' || + 'FROM dbmshp_pcdiftab WHERE pname||phash = :b1 and pid = :b2 ' || + 'order by stime asc'; + + EXECUTE IMMEDIATE sql_stmt BULK COLLECT + INTO cids, pstimes, pftimes, pcalls, cnames, hashtab2 + USING fnames(i)||hashtab(i), sids(i); + + IF cids.COUNT > 0 THEN + write_data('' || CRLF, FALSE); + END IF; + + FOR j in 1..cids.COUNT LOOP + IF (pstimes(j) <> 0 OR pftimes(j) <> 0) THEN + dtime := pstimes(j)-pftimes(j); + + write_data( + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF || + '' || CRLF, FALSE); + END IF; + END LOOP; + + write_data('
Subtree Time DeltaFunction Time DeltaDescendants Time DeltaCalls DeltaFunction Name
' || stimes(i) || '' || ftimes(i) || '' || dtimes(i) || '' || calls(i) || '' || CRLF || + ' ' || fnames(i) || '' || CRLF || '
' || CRLF || + ' Parents:' || CRLF || + '
' || stimes(i) || '' || ftimes(i) || '' || dtimes(i) || '' || calls(i) || '' || CRLF || + ' root' || CRLF || + '
' || pstimes(j) || '' || pftimes(j) || '' || dtime || '' || pcalls(j) || '' || CRLF || + ' ' || pnames(j) || '' || CRLF || '
Children:
' || pstimes(j) || '' || pftimes(j) || '' || dtime || '' || pcalls(j) || '' || CRLF || + ' ' || cnames(j) || '' || CRLF || '

'|| CRLF, FALSE); + END LOOP; + + write_data( + '' || CRLF || '', + TRUE); + write_plstinfo; + END; + + /* analyze_reports takes a location, a file name and a run_id + * and generates a report based on data collected in the trace + * file located at directory object with run_id + * . + * + * The report is composed of several HTML files including: + * 1. A time analysis report + * 2. A subtree time report + * 3. A function time report + * 4. A function call count report + * 5. A function name report + * 6. A mean subtree time report + * 7. A mean function time report + * 8. A group by namespace report + * 9. A group by module name report + * 10.A total function call count report + * 11.A module name report + * 12.A parent child diff report + * + * There are many other potential reports that one could wish + * to generate. These reports and their implementations demonstrate + * ways of leveraging the trace information left in the PL/SQL trace + * files. + */ + PROCEDURE analyze_reports(location IN VARCHAR2, + fname IN VARCHAR2, + run_id IN NUMBER) IS + BEGIN + + filename := fname; + filelocation := location; + runid := run_id; + + -- Get total number of time + time_mode := 'Elapsed Time'; + sql_stmt := + 'SELECT SUM(FUNCTION_ELAPSED_TIME) FROM dbmshp_function_info ' || + 'WHERE runid = :b1'; + EXECUTE IMMEDIATE sql_stmt INTO total_time USING runid; + + -- Get total number of function calls + sql_stmt := 'SELECT SUM(CALLS) FROM dbmshp_function_info ' || + 'WHERE runid = :b1'; + EXECUTE IMMEDIATE sql_stmt INTO total_calls USING runid; + + -- Generate PL/SQL Time Analysis report + fullname := filename||'.html'; + single_run_start_page; + + -- Generate Sort by Subtree Time report + fullname := filename||'_subtree.html'; + function_level_report(DBMSHP_SUBTREETIME, FALSE); + + -- Generate Sort by Function Time report + fullname := filename||'_function.html'; + function_level_report(DBMSHP_FUNCTIONTIME, FALSE); + + -- Generate Sort by Function Call Count report + fullname := filename||'_calls.html'; + function_level_report(DBMSHP_CALLS, FALSE); + + -- Generate Sort by Function Name report + fullname := filename||'_name.html'; + function_level_report(DBMSHP_NAME, FALSE); + + -- Generate Sort by Mean Subtree Time report + fullname := filename||'_mean_subtree.html'; + function_level_report(DBMSHP_MEAN_SUBTREETIME, TRUE); + + -- Generate Sort by Mean Function Time report + fullname := filename||'_mean_function.html'; + function_level_report(DBMSHP_MEAN_FUNCTIONTIME, TRUE); + + -- Generate Group by Namespace report + fullname := filename||'_namespace.html'; + namespace_report; + + -- Generate Group by Module Name reports + -- Sorted by Total Function Time + fullname := filename||'_module_function.html'; + module_report(DBMSHP_FUNCTIONTIME); + + -- Sorted by Total Function Call Count + fullname := filename||'_module_calls.html'; + module_report(DBMSHP_CALLS); + + -- Sorted by Module Name + fullname := filename||'_module_name.html'; + module_report(DBMSHP_NAME); + + -- Generate Parent Child Time report + fullname := filename||'_parent_child.html'; + parent_child_report; + END; + + PROCEDURE analyze_reports(location IN VARCHAR2, + fname IN VARCHAR2, + run1_id IN NUMBER, + run2_id IN NUMBER) IS + BEGIN + + filename := fname; + filelocation := location; + runid := run1_id; + runid2 := run2_id; + + time_mode := 'Elapsed Time'; + + -- Generate PL/SQL Time Diff Summary report + fullname := filename || '.html'; + + IF (diff_mode_start_page = TRUE) THEN + -- Generate performance regression report + fullname := filename || '_fr.html'; + performance_report('ftime > 0', 'Regressions'); + + -- Generate performance improvement report + fullname := filename || '_fi.html'; + performance_report('ftime < 0', 'Improvements'); + + -- Generate Sort by Total Subtree Time report + fullname := filename || '_ns.html'; + diff_function_level_report(DBMSHP_SUBTREETIME); + + -- Generate Sort by Total Function Time report + fullname := filename || '_nf.html'; + diff_function_level_report(DBMSHP_FUNCTIONTIME); + + -- Generate Sort by Function Call Count report + fullname := filename || '_nc.html'; + diff_function_level_report(DBMSHP_CALLS); + + -- Generate Sort by Function Name report + fullname := filename || '_nn.html'; + diff_function_level_report(DBMSHP_NAME); + + -- Generate Group by Namespace reports + fullname := filename || '_nsp.html'; + diff_namespace_report; + + -- Generate Group by Module Name reports + -- Sorted by Total Function Time + fullname := filename || '_2f.html'; + diff_module_report(DBMSHP_FUNCTIONTIME); + + -- Sorted by Total Function Call Count + fullname := filename || '_2c.html'; + diff_module_report(DBMSHP_CALLS); + + -- Sorted by Module Name + fullname := filename || '_2n.html'; + diff_module_report(DBMSHP_NAME); + + -- Generate Parent Child Difference reports + fullname := filename || '_pc.html'; + diff_parent_child_report; + + EXECUTE IMMEDIATE 'DROP VIEW dbmshp_t1'; + EXECUTE IMMEDIATE 'DROP VIEW dbmshp_t2'; + EXECUTE IMMEDIATE 'DROP VIEW dbmshp_diftab'; + EXECUTE IMMEDIATE 'DROP VIEW dbmshp_pct1'; + EXECUTE IMMEDIATE 'DROP VIEW dbmshp_pct2'; + EXECUTE IMMEDIATE 'DROP VIEW dbmshp_pcdiftab'; + END IF; + END; + +BEGIN + dbms_lob.createtemporary(myclob, true); + page_size := dbms_lob.getchunksize(myclob); + + -- Write a multiple of the page size that is closest to 32K + IF (page_size < 32767) THEN + page_size := 32767 / page_size * page_size; + END IF; + +END dbmshpro_demo; +/ +show errors + diff --git a/dmkmdemo.java b/dmkmdemo.java new file mode 100644 index 0000000..3b085d6 --- /dev/null +++ b/dmkmdemo.java @@ -0,0 +1,1011 @@ +// Copyright (c) 2001, 2006, Oracle. All rights reserved. +// File: dmkmdemo.java +// Generic api imports +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import java.util.Collection; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Set; +import java.util.TreeMap; + +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.NamedObject; +import javax.datamining.algorithm.kmeans.ClusteringDistanceFunction; +import javax.datamining.algorithm.kmeans.KMeansSettingsFactory; +import javax.datamining.base.Task; +import javax.datamining.clustering.Cluster; +import javax.datamining.clustering.ClusteringApplySettings; +import javax.datamining.clustering.ClusteringApplySettingsFactory; +import javax.datamining.clustering.ClusteringModel; +import javax.datamining.clustering.ClusteringSettings; +import javax.datamining.clustering.ClusteringSettingsFactory; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.AttributeType; +import javax.datamining.data.Interval; +import javax.datamining.data.IntervalClosure; +import javax.datamining.data.ModelSignature; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.data.SignatureAttribute; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.rule.CompoundPredicate; +import javax.datamining.rule.Rule; +import javax.datamining.rule.SimplePredicate; +import javax.datamining.statistics.AttributeStatisticsSet; +import javax.datamining.statistics.UnivariateStatistics; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; +import javax.datamining.task.apply.DataSetApplyTask; +import javax.datamining.task.apply.DataSetApplyTaskFactory; + +import oracle.dmt.jdm.OraPLSQLMappings; +import oracle.dmt.jdm.algorithm.kmeans.OraKMeansSettings; +import oracle.dmt.jdm.algorithm.kmeans.OraSplitCriterion; +import oracle.dmt.jdm.base.OraBuildSettings; +import oracle.dmt.jdm.base.OraTask; +import oracle.dmt.jdm.clustering.OraCluster; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.rule.OraSimplePredicate; +import oracle.dmt.jdm.task.OraTransformationTask; +import oracle.dmt.jdm.task.OraTransformationTaskFactory; +import oracle.dmt.jdm.transform.normalize.OraNormalizeTransformFactory; +import oracle.dmt.jdm.transform.normalize.OraNormalizeTransformImpl; +import oracle.dmt.jdm.transform.normalize.OraNormalizeType; + + +// Java Data Mining (JDM) standard imports +// Oracle Java Data Mining (JDM) implemented api imports + +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to cluster data records based on their Eucledian distance similarity. +* The k-Means (KM) clustering model provides the user with insight about the +* discovered groups. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* Segment the demographic data into 10 clusters and study the individual +* clusters. Apply clustering model to new data and rank the clusters on probability. +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the previous affinity card +* programs. Data exploration and preparing the data is a common step before +* doing data mining. Here in this demo, the following views are created +* in the user schema using CUSTOMERS, COUNTRIES and SUPPLIMENTARY_DEMOGRAPHICS +* tables. +* +* MINING_DATA_BUILD_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for building the model. +* +* MINING_DATA_APPLY_V: +* This view collects the prospective customers' demographics and purchasing +* details for scoring against the clustering model. +* +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Prepare Data: +* In general, attributes need to be similar scale in order to be treated +* equally during the model build. Therefore normalization is required. +* The prepareData() method illustrates the normalization of the build and apply +* data. +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a clustering model using KM algorithm. +* Apply Model: +* The results of an APPLY operation will contain a list of the cluster +* identifiers for each case, and the associated probabilities. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +public class + +dmkmdemo + extends Object +{ + //Connection related data members + private static javax.datamining.resource.Connection m_dmeConn; + private static javax.datamining.resource.ConnectionFactory m_dmeConnFactory; + //Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static ClusteringSettingsFactory m_clusFactory; + private static KMeansSettingsFactory m_kmeansFactory; + private static BuildTaskFactory m_buildFactory; + private static DataSetApplyTaskFactory m_dsApplyFactory; + private static ClusteringApplySettingsFactory m_applySettingsFactory; + private static OraNormalizeTransformFactory m_normalizeXformFactory; + private static OraTransformationTaskFactory m_xformTaskFactory; + // Global constants used for formatting output + private static String TAB = " "; + private static String CR = "\n"; + private static String CR_TAB = "\n "; + private static String HORZ_LINE = "----"; + private static String UNDERLINE = + "*************************************"; + private static String LEAF_CLUSTERS_HEADER = + "* Leaf clusters *"; + private static String RULES_CLUSTERS_HEADER = + "* Rules *"; + private static String RULES_CLUSTERS_HIERARCHY_HEADER = + "* Printing clusters hierarchy *"; + + public static void main(String[] args) + { + try + { + if ((args.length != 0) & (args.length != 3)) + { + System.out.println("Usage: java dmkmdemo "); + System.out.println(" or: java dmkmdemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + //1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@" + uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Save task to build a model + buildModel(); + // 5. Save task to apply a model + applyModel(); + // 6. Execute build task and apply task follows + m_dmeConn.execute("kmBuildTask_jdm"); + //7. Monitor execution of the tasks + monitorTaskExecutionProcess(); + } + catch (Exception anyExp) + { + anyExp.printStackTrace(System.out); + } + finally + { + try + { + // 7. Logout from the Data Mining Engine + m_dmeConn.close(); + } + catch (Exception anyExp1) + { + } //Ignore + } + } + + /** + * Initialize all object factories used in the demo program. + * + * @exception JDMException if factory initalization failed + */ + public static void initFactories() + throws JDMException + { + m_pdsFactory = + (PhysicalDataSetFactory) m_dmeConn.getFactory("javax.datamining.data.PhysicalDataSet"); + m_paFactory = + (PhysicalAttributeFactory) m_dmeConn.getFactory("javax.datamining.data.PhysicalAttribute"); + m_clusFactory = + (ClusteringSettingsFactory) m_dmeConn.getFactory("javax.datamining.clustering.ClusteringSettings"); + m_kmeansFactory = + (KMeansSettingsFactory) m_dmeConn.getFactory("javax.datamining.algorithm.kmeans.KMeansSettings"); + m_buildFactory = + (BuildTaskFactory) m_dmeConn.getFactory("javax.datamining.task.BuildTask"); + m_dsApplyFactory = + (DataSetApplyTaskFactory) m_dmeConn.getFactory("javax.datamining.task.apply.DataSetApplyTask"); + m_applySettingsFactory = + (ClusteringApplySettingsFactory) m_dmeConn.getFactory("javax.datamining.clustering.ClusteringApplySettings"); + m_normalizeXformFactory = + (OraNormalizeTransformFactory) m_dmeConn.getFactory("oracle.dmt.jdm.transform.normalize.OraNormalizeTransform"); + m_xformTaskFactory = + (OraTransformationTaskFactory) m_dmeConn.getFactory("oracle.dmt.jdm.task.OraTransformationTask"); + } + + /** + * This method illustrates how to build a clustering mining model using + * the kMeans algorithm. + * + * After completing the build task, the model named "kmModel_jdm" will + * be created. + * + * @exception JDMException if model build failed + */ + public static void buildModel() + throws JDMException + { + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = + m_pdsFactory.create("MINING_DATA_BUILD_V", false); + PhysicalAttribute pa = + m_paFactory.create("cust_id", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + buildData.addAttribute(pa); + m_dmeConn.saveObject("kmBuildData_jdm", buildData, true); + // 2. Create & save Mining Function Settings + // Create kMeans algorithm settings + OraKMeansSettings kmAlgo = + (OraKMeansSettings) m_kmeansFactory.create(); + kmAlgo.setDistanceFunction(ClusteringDistanceFunction.euclidean); + kmAlgo.setMaxNumberOfIterations(10); + kmAlgo.setMinErrorTolerance(0.01); + kmAlgo.setSplitCriterion(OraSplitCriterion.clusterVariance); + kmAlgo.setNumberOfBins(10); + kmAlgo.setBlockGrowth(2); + kmAlgo.setMinPercentageAtrrSupport(0.1); + + // 3. Create ClusteringSettings + ClusteringSettings buildSettings = m_clusFactory.create(); + buildSettings.setAlgorithmSettings(kmAlgo); + buildSettings.setMaxNumberOfClusters(10); + ((OraBuildSettings) buildSettings).useAutomatedDataPreparations(true); + m_dmeConn.saveObject("kmBuildSettings_jdm", buildSettings, true); + // 4. Create, save & execute Build Task + BuildTask buildTask = //Build data specification + //Mining function settings name + //Mining model name + m_buildFactory.create("kmBuildData_jdm", "kmBuildSettings_jdm", + "kmModel_jdm"); + buildTask.setDescription("kmBuildTask_jdm"); + saveTask(buildTask, "kmBuildTask_jdm", null); + + } + + /** + * + * For a descriptive mining function like Clustering, "Scoring" involves + * providing the probability values for each cluster. + * After completing the apply task, an apply output table + * "km_apply_output_jdm" will be created at the user specfied location. + * + * @exception JDMException if model apply failed + */ + public static void applyModel() + throws JDMException + { + //1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = + m_pdsFactory.create("MINING_DATA_APPLY_V", false); + PhysicalAttribute pa = + m_paFactory.create("cust_id", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + applyData.addAttribute(pa); + m_dmeConn.saveObject("kmApplyData_jdm", applyData, true); + //2. Create & save ClassificationApplySettings + ClusteringApplySettings clusAS = m_applySettingsFactory.create(); + m_dmeConn.saveObject("kmApplySettings_jdm", clusAS, true); + + //3. Create, store & execute apply Task + DataSetApplyTask applyTask = + m_dsApplyFactory.create("kmApplyData_jdm", "kmModel_jdm", + "kmApplySettings_jdm", + "km_apply_output_jdm"); + saveTask(applyTask, "kmApplyTask_jdm", "kmBuildTask_jdm"); + } + + /** + * This method monitor task execution initiated by the first task + * in the sequence of dependent tasks. In addition, this method displays + * task output results (if any). + * @throws JDMException + */ + public static void monitorTaskExecutionProcess() + throws JDMException + { + //1. Monitor BuildTask + //Wait for the completion of the task + System.out.print("Waiting for the completion of kmBuildTask_jdm. "); + ExecutionStatus buildTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("kmBuildTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //If successful + if (ExecutionState.success.equals(buildTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + //Restore the model from the DME and explore the details of the model + ClusteringModel model = + (ClusteringModel) m_dmeConn.retrieveObject("kmModel_jdm", + NamedObject.model); + displayKMModelDetails(model); + //2. Monitor applyTask + //Wait for the completion of the task + { + System.out.print("Waiting for the completion of kmApplyTask_jdm. "); + ExecutionStatus applyTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("kmApplyTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //If successful + if (ExecutionState.success.equals(applyTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + //Display results + displayScoringResults(); + } + else + { + System.out.println("It is at state:" + + applyTaskCompletionStatus.getState().name() + + ((applyTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + applyTaskCompletionStatus.getDescription())); + } + } + } + else + { + System.out.println("It is at state:" + + buildTaskCompletionStatus.getState().name() + + ((buildTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + buildTaskCompletionStatus.getDescription())); + } + } + + /** + * Shows scoring results. + * BUSINESS CASE 1: List the clusters into which the customers in this + * dataset have been grouped. + * BUSINESS CASE 2: List ten most representative (based on likelihood) + * customers of cluster 2. + */ + public static void displayScoringResults() + { + // BUSINESS CASE 1: List the clusters into which the customers in this + // dataset have been grouped. + String sqlCase1 = + "SELECT clus, COUNT(*) AS CNT FROM " + " (SELECT cluster_id CLUS, " + + " ROW_NUMBER() OVER " + + " (PARTITION BY CUST_ID ORDER BY PROBABILITY DESC) CLUS_RNK " + + " FROM km_apply_output_jdm) " + "WHERE CLUS_RNK = 1 " + + "GROUP BY CLUS ORDER BY CNT DESC"; + + Statement stmt = null; + ResultSet rs = null; + java.sql.Connection dbConn = + ((OraConnection) m_dmeConn).getDatabaseConnection(); + try + { + stmt = dbConn.createStatement(); + rs = stmt.executeQuery(sqlCase1); + System.out.println("Cluster ID Count"); + System.out.println("----------------------------"); + while (rs.next()) + { + int clus = rs.getInt(1); + int cnt = rs.getInt(2); + System.out.println(TAB + clus + TAB + TAB + cnt); + } + } + catch (SQLException anySqlExp) + { + System.out.println(anySqlExp); + } + finally + { + try + { + stmt.close(); + } + catch (Exception anySqlExp) + { + } + } + + // BUSINESS CASE 2: List ten most representative (based on likelihood) + // customers of cluster 2 + + String sqlCase2 = + "SELECT * from " + " (SELECT cust_id, probability from km_apply_output_jdm " + + " WHERE CLUSTER_ID = 2 ORDER BY probability DESC) " + + "WHERE ROWNUM < 11"; + + stmt = null; + rs = null; + try + { + stmt = dbConn.createStatement(); + rs = stmt.executeQuery(sqlCase2); + System.out.println("Cust_ID Probability"); + System.out.println("----------------------------"); + while (rs.next()) + { + int custid = rs.getInt(1); + String probability = rs.getString(2); + System.out.println(TAB + custid + TAB + TAB + probability); + } + } + catch (SQLException anySqlExp) + { + System.out.println(anySqlExp); + } + finally + { + try + { + stmt.close(); + } + catch (Exception anySqlExp) + { + } + } + } + + /** + * This method saves the given task with the specified task name and task + * dependency (parent task) in the DME. + * + * @param taskObj task object + * @param taskName name of the task + * @param parentTaskName name of the parent task + * + * @return boolean returns true when the task is successful + * @exception JDMException if task execution failed + */ + public static void saveTask(Task taskObj, String taskName, + String parentTaskName) + throws JDMException + { + if (parentTaskName != null) + ((OraTask) taskObj).addDependency(parentTaskName); //Since OJDM 11.1 + ((OraTask) taskObj).overwriteOutput(true); //Since OJDM 11.1 + m_dmeConn.saveObject(taskName, taskObj, true); + } + + /** + * This method displayes KM model details. + * + * @param model to be presented + * + * @exception JDMException if failed to retrieve model details + */ + public static void displayKMModelDetails(ClusteringModel model) + throws JDMException + { + String modelName = model.getName(); + System.out.println("Model Name: " + modelName); + System.out.println("Clustering model details:"); + System.out.println(TAB + "Number of clusters: " + + model.getNumberOfClusters()); + System.out.println(TAB + "Number of tree levels: " + + model.getNumberOfLevels()); + Collection clusters = model.getClusters(); + if (clusters == null || clusters.isEmpty() == true) + { + System.out.println("Unable to retrieve clusters."); + return; + } + + // Display root cluster(s) + Collection vRootClusters = model.getRootClusters(); + Cluster[] rootCluster = null; + if (vRootClusters != null && vRootClusters.isEmpty() == false) + { + rootCluster = + (Cluster[]) vRootClusters.toArray(new Cluster[vRootClusters.size()]); + if (rootCluster != null) + System.out.println(TAB + "Root Cluster Id: " + + rootCluster[0].getClusterId()); + } + + // Display leaf clusters + Collection vLeafClusters = model.getLeafClusters(); + if (vLeafClusters != null && vLeafClusters.isEmpty() == false) + { + Cluster[] leafClusters = + (Cluster[]) vLeafClusters.toArray(new Cluster[vLeafClusters.size()]); + System.out.println(UNDERLINE); + System.out.println(LEAF_CLUSTERS_HEADER); + System.out.println(UNDERLINE); + for (int ni = 0; ni < leafClusters.length; ni++) + { + printSingleClusterDetails(leafClusters[ni]); + if (ni == 0) + { + // display first leaf cluster statistics + printClusterStatistics(model, leafClusters[ni], 1); + } + } + } + + // Display all model rules + Collection vRules = model.getRules(); + if (vRules != null && vRules.isEmpty() == false) + { + Rule[] rules = (Rule[]) vRules.toArray(new Rule[vRules.size()]); + System.out.println(CR + CR + UNDERLINE); + System.out.println(RULES_CLUSTERS_HEADER); + System.out.println(UNDERLINE); + for (int rl = 0; rl < rules.length; rl++) + { + printRuleNoDetails(rules[rl], 0); + } + } + + if (rootCluster != null) + { + // print hierarchy + System.out.println(CR + CR + UNDERLINE); + System.out.println(RULES_CLUSTERS_HIERARCHY_HEADER); + System.out.println(UNDERLINE); + // 1.print root + printRootClusterDetails(rootCluster[0]); + // 1.print children + Cluster[] children = rootCluster[0].getChildren(); + int indent = 0; + if (children != null) + { + for (int k = 0; k < children.length; k++) + { + printRecursiveClusterDetails(model, children[k], indent); + } + } + return; + } + + // print flat structure + Cluster[] arrayClusters = + (Cluster[]) clusters.toArray(new Cluster[clusters.size()]); + for (int ni = 0; ni < arrayClusters.length; ni++) + { + printSingleClusterDetails(arrayClusters[ni]); + } + System.out.println(CR + UNDERLINE + CR); + } + + + private static String getIndentation(int indent, String sText) + { + StringBuffer sbIndent = new StringBuffer(TAB); + for (int in = 0; in < indent; in++) + sbIndent.append(TAB); + + StringBuffer outPut = new StringBuffer(sbIndent.toString()); + outPut.append(sText); + return outPut.toString(); + } + + /** + * This method recursively displayes Cluster details. + * + * @param model model to be presented + * @param cluster current cluster which details are being presented + * @param indent indentation level to illustrate cluster parent-child relation + * + * @exception JDMException if failed to retrieve cluster details + */ + public static void printRecursiveClusterDetails(ClusteringModel model, + Cluster cluster, + int indent) + throws JDMException + { + indent++; + System.out.println(getIndentation(indent, + "Cluster Id: " + cluster.getClusterId()) + + CR + + getIndentation(indent, "Case Count: " + cluster.getCaseCount()) + + CR + + getIndentation(indent, "Tree Level: " + cluster.getLevel()) + + CR + + getIndentation(indent, "Dispersion: " + ((OraCluster) cluster).getDispersion()) + + CR + + getIndentation(indent, "Parent's id: " + (cluster.getParent() != + null? + String.valueOf(cluster.getParent().getClusterId()): + ""))); + + Cluster[] ancestors = cluster.getAncestors(); + if (ancestors != null) + { + StringBuffer sbTab = new StringBuffer("Anchestors"); + if (ancestors.length == 0) + sbTab.append(" : None"); + for (int j = 0; j < ancestors.length; j++) + { + for (int sp = 0; sp < j; sp++) + sbTab.append(":" + ancestors[j].getClusterId() + " "); + } + System.out.print(getIndentation(indent, sbTab.toString())); + } + + Cluster[] children = cluster.getChildren(); + if (children != null) + { + System.out.println(CR + getIndentation(indent, "Children:")); + for (int k = 0; k < children.length; k++) + { + Cluster childCluster = children[k]; + printRecursiveClusterDetails(model, childCluster, indent); + } + } + else + { + System.out.print(CR + + getIndentation(indent, "No child clusters" + CR)); + Rule rule = cluster.getRule(); + //Print Rule Details for leaf clusters only + printRuleDetails(rule, indent); + } + indent--; + } + + /** + * This method prints Rules details with antecedent and consequent information. + * + * @param rule rule which details are being presented + * @param indent indentation level to illustrate cluster parent-child relation + * + * @exception JDMException if failed to retrieve cluster details + */ + public static void printRuleDetails(Rule rule, int indent) + { + System.out.println(CR_TAB + + getIndentation(indent, "Rule number:" + rule.getRuleIdentifier()) + + CR_TAB + TAB + + getIndentation(indent, "Support: " + rule.getSupport()) + + CR_TAB + TAB + + getIndentation(indent, "Confidence: " + + rule.getConfidence())); + CompoundPredicate antecedent = + (CompoundPredicate) rule.getAntecedent(); + System.out.println(CR_TAB + TAB + + getIndentation(indent, ("Antecedent: "))); + printAntecedent(antecedent, indent); + + CompoundPredicate consequent = + (CompoundPredicate) rule.getConsequent(); + System.out.println(CR_TAB + TAB + + getIndentation(indent, ("Consequent: "))); + printConsequent(consequent, indent); + } + + /** + * This method prints Rules details without antecedent and consequent information. + * + * @param rule rule which details are being presented + * @param indent indentation level to illustrate cluster parent-child relation + */ + public static void printRuleNoDetails(Rule rule, int indent) + { + System.out.println(CR_TAB + + getIndentation(indent, "Rule number:" + rule.getRuleIdentifier()) + + CR_TAB + TAB + + getIndentation(indent, "Support: " + rule.getSupport()) + + CR_TAB + TAB + + getIndentation(indent, "Confidence: " + + rule.getConfidence())); + } + + /** + * This method prints antecedent information. + * + * @param predicate antecedent being presented + * @param indent indentation level to illustrate cluster parent-child relation + * + * @exception JDMException if failed to retrieve antecedent details + */ + public static void printAntecedent(CompoundPredicate predicate, + int indent) + { + try + { + SimplePredicate[] sps = + (SimplePredicate[]) predicate.getPredicates(); + if (sps == null) + return; + + // combine predicates by attribute name + Hashtable htNamePredicateMap = new Hashtable(); + for (int i = 0; i < sps.length; i++) + { + StringBuffer simplePredicate = printSimplePredicate(sps[i]); + String attrName = sps[i].getAttributeName(); + StringBuffer attrTotalPredicate = + (StringBuffer) htNamePredicateMap.get(attrName); + if (attrTotalPredicate == null) + htNamePredicateMap.put(attrName, simplePredicate); + else + { + attrTotalPredicate.append(" AND " + simplePredicate); + } + } + Enumeration en = htNamePredicateMap.keys(); + while (en.hasMoreElements()) + { + String name = (String) en.nextElement(); + StringBuffer sb = (StringBuffer) htNamePredicateMap.get(name); + System.out.println(getIndentation(indent, + (TAB + TAB + TAB + sb.toString()))); + } + } + catch (Exception e) + { + System.out.println("Error printing Antecedant"); + } + } + + /** + * This method prints consequent information. + * + * @param predicate consequent being presented + * @param indent indentation level to illustrate cluster parent-child relation + * + * @exception JDMException if failed to retrieve consequent details + */ + public static void printConsequent(CompoundPredicate predicate, + int indent) + { + try + { + SimplePredicate[] sps = + (SimplePredicate[]) predicate.getPredicates(); + if (sps == null) + return; + + for (int i = 0; i < sps.length; i++) + { + StringBuffer simplePredicate = printSimplePredicate(sps[i]); + if (i < sps.length - 1) + simplePredicate.append(" AND "); + System.out.println(getIndentation(indent, + TAB + TAB + TAB + simplePredicate.toString())); + } + } + catch (Exception e) + { + System.out.println("Error printing Consequent"); + } + } + + /** + * This method prints SimplePredicate information. + * + * @param predicate SimplePredicate being presented + * + * @exception JDMException if failed to retrieve SimplePredicate details + */ + public static StringBuffer printSimplePredicate(SimplePredicate predicate) + throws JDMException + { + StringBuffer sb = new StringBuffer(); + if (predicate.isNumericalValue()) + { + //((OraSimplePredicate)predicate).getComparisonOperatorValue() + " " + + sb.append(predicate.getAttributeName() + " " + + OraPLSQLMappings.getComparisonOperatorValue_tree(((OraSimplePredicate) predicate).getComparisonOperator()) + + " " + predicate.getNumericalValue()); + } + else + { + //((OraSimplePredicate)predicate).getComparisonOperatorValue() + " " + sb = + new StringBuffer(predicate.getAttributeName() + " " + OraPLSQLMappings.getComparisonOperatorValue_tree(((OraSimplePredicate) predicate).getComparisonOperator()) + + " "); + Object[] inValues = predicate.getCategoryValues(); + if (inValues != null) + { + for (int i = 0; i < inValues.length; i++) + { + sb.append(inValues[i]); + if (i != inValues.length - 1) + sb.append(","); + } + } + } + return sb; + } + + /** + * This method shows details of the root cluster. + * + * @param cluster root cluster + * + * @exception JDMException if failed to retrieve root cluster details + */ + public static void printRootClusterDetails(Cluster cluster) + throws JDMException + { + System.out.println(CR + "Root Cluster Id: " + cluster.getClusterId() + + CR_TAB + "Case Count: " + cluster.getCaseCount() + + CR_TAB + "Tree Level: " + cluster.getLevel() + + CR_TAB + "Dispersion: " + + ((OraCluster) cluster).getDispersion() + CR_TAB + + "Children:"); + } + + /** + * This method shows details of any cluster. + * + * @param cluster clusterbeing presented + * + * @exception JDMException if failed to retrieve this cluster details + */ + public static void printSingleClusterDetails(Cluster cluster) + throws JDMException + { + System.out.println(CR + "Cluster Id: " + cluster.getClusterId() + + CR_TAB + "Case Count: " + cluster.getCaseCount() + + CR_TAB + "Tree Level: " + cluster.getLevel() + + CR_TAB + "Dispersion: " + + ((OraCluster) cluster).getDispersion() + CR_TAB + + "Parent's id: " + + (cluster.getParent() != null? String.valueOf(cluster.getParent().getClusterId()): + "") + CR_TAB + "Is root Cluster: " + + cluster.isRoot() + CR_TAB + "Is leaf Cluster: " + + cluster.isLeaf()); + + Cluster[] ancestors = cluster.getAncestors(); + StringBuffer sbTab = new StringBuffer(TAB + "Anchestors "); + if (ancestors != null) + { + for (int j = 0; j < ancestors.length; j++) + { + for (int sp = 0; sp < j; sp++) + sbTab.append(":" + ancestors[j].getClusterId() + " "); + } + } + else + { + sbTab.append("None"); + } + System.out.print(sbTab.toString()); + + Cluster[] children = cluster.getChildren(); + System.out.println(CR_TAB + "Children:"); + if (children != null) + { + for (int k = 0; k < children.length; k++) + { + Cluster childCluster = children[k]; + System.out.print(TAB + TAB + "Child: " + + childCluster.getClusterId() + CR); + } + System.out.println(CR); + } + else + { + System.out.print(TAB + TAB + "None"); + } + } + + /** + * This method shows cluster statistics. + * + * @param model model being presented + * @param cluster cluster being presented + * @param indent indentation level to illustrate cluster parent-child relation + * + * @exception JDMException if failed to retrieve this cluster statistics + */ + public static void printClusterStatistics(ClusteringModel model, + Cluster cluster, int indent) + { + try + { + ModelSignature modelSignature = model.getSignature(); + + AttributeStatisticsSet attrStat = cluster.getStatistics(); + if (attrStat == null) + return; + TreeMap centroids = ((OraCluster) cluster).getCentroids(); + if (centroids == null || centroids.isEmpty()) + { + System.out.println("Error: cluster " + cluster.getClusterId() + + " does not contain statsitics"); + return; + } + Set centroidKeys = centroids.keySet(); + Iterator attributesNames = centroidKeys.iterator(); + while (attributesNames.hasNext()) + { + String attributeName = (String) attributesNames.next(); + SignatureAttribute sa = modelSignature.getAttribute(attributeName); + AttributeType aType = sa.getAttributeType(); + UnivariateStatistics stats = attrStat.getStatistics(attributeName); + double[] frequencies = stats.getProbabilities(); + System.out.println(CR_TAB + + getIndentation(indent, "Statistics for attribute: " + + attributeName)); + System.out.println(TAB + getIndentation(indent, UNDERLINE)); + if (aType.equals(AttributeType.numerical)) + { + Interval[] ranges = (Interval[]) stats.getValues(); + if (ranges != null) + { + System.out.println(TAB + TAB + + getIndentation(indent, "Bin Id" + TAB + + TAB + TAB + "Range" + TAB + + TAB + TAB + TAB + + "Frequency")); + for (int in = 0; in < ranges.length; in++) + { + Interval bin = ranges[in]; + IntervalClosure closure = bin.getIntervalClosure(); + String openParenthesis = + ((closure.equals(IntervalClosure.openClosed) || + closure.equals(IntervalClosure.openOpen))? "( ": "[ "); + String closeParenthesis = + ((closure.equals(IntervalClosure.openOpen) || + closure.equals(IntervalClosure.closedOpen))? " )": + " ]"); // bin Id + // range + //frequency + System.out.println(TAB + TAB + + getIndentation(indent, String.valueOf(in + + 1)) + + TAB + TAB + + getIndentation(indent, openParenthesis + + bin.getStartPoint() + + " - " + bin.getEndPoint() + + closeParenthesis) + TAB + + TAB + + getIndentation(indent, String.valueOf((int) frequencies[in]))); + } + } + } + else if (aType.equals(AttributeType.categorical)) + { + Object[] values = stats.getValues(); + if (values != null) + { + System.out.println(TAB + TAB + + getIndentation(indent, "Bin Id" + TAB + + "Category" + TAB + + "Frequency")); + for (int in = 0; in < values.length; in++) + { + // bin Id + //value + //frequency + System.out.println(TAB + TAB + + getIndentation(indent, String.valueOf(in + + 1)) + + TAB + TAB + values[in] + TAB + TAB + + getIndentation(indent, + String.valueOf((int) frequencies[in]))); + } + } + } + } + } + catch (Exception e) + { + System.out.println("Error printing statsitics for cluster: " + + cluster.getClusterId()); + } + } + + private static void clean() + { + //Drop the model + try + { + m_dmeConn.removeObject("kmModel_jdm", NamedObject.model); + } + catch (JDMException jdmExp) + { + } + } +} + diff --git a/dmkmdemo.sql b/dmkmdemo.sql new file mode 100644 index 0000000..02edcf6 --- /dev/null +++ b/dmkmdemo.sql @@ -0,0 +1,378 @@ +Rem +Rem $Header: dmkmdemo.sql 25-oct-2007.11:35:30 ramkrish Exp $ +Rem +Rem dmkmdemo.sql +Rem +Rem Copyright (c) 2003, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmkmdemo.sql - Sample program for the DBMS_DATA_MINING package. +Rem +Rem DESCRIPTION +Rem This script creates a clustering model +Rem using the K-Means algorithm +Rem and data in the SH (Sales History) schema in the RDBMS. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ramkrish 06/14/07 - remove commit after settings +Rem ramkrish 10/25/07 - replace deprecated get_model calls with catalog +Rem queries +Rem jiawang 08/02/06 - ENABLE ADP +Rem ktaylor 07/11/05 - Minor edits to comments +Rem jcjeon 01/18/05 - add column format +Rem mmcampos 11/09/04 - edit comments +Rem ramkrish 10/04/04 - add data analysis and comments/cleanup +Rem jiawang 07/22/04 - Add order by to fix sorting dif +Rem pstengar 10/17/03 - added denormalization of model details +Rem ramkrish 10/02/03 - Creation + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET linesize 140 +SET echo ON + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM +----------------------------------------------------------------------- +-- Segment the demographic data into 10 clusters and study the individual +-- clusters. Rank the clusters on probability. + +----------------------------------------------------------------------- +-- SET UP AND ANALYZE THE DATA +----------------------------------------------------------------------- + +-- The data for this sample is composed from base tables in SH Schema +-- (See Sample Schema Documentation) and presented through these views: +-- mining_data_build_v (build data) +-- mining_data_test_v (test data) +-- mining_data_apply_v (apply data) +-- (See dmsh.sql for view definitions). +-- + +----------- +-- ANALYSIS +----------- +-- For clustering using KM, perform the following on mining data. +-- +-- 1. Use Data Auto Preparation +-- + +----------------------------------------------------------------------- +-- BUILD THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old model with same name for repeat runs +BEGIN DBMS_DATA_MINING.DROP_MODEL('KM_SH_Clus_sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +------------------- +-- SPECIFY SETTINGS +-- +-- Cleanup old settings table for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE km_sh_sample_settings'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- K-Means is the default Clustering algorithm. For this sample, +-- we skip specification of any overrides to defaults +-- +-- Uncomment the appropriate sections of the code below for +-- changing settings values. +-- +set echo on +CREATE TABLE km_sh_sample_settings ( + setting_name VARCHAR2(30), + setting_value VARCHAR2(30)); + +BEGIN + INSERT INTO km_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.kmns_distance,dbms_data_mining.kmns_euclidean); + + INSERT INTO km_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.prep_auto,dbms_data_mining.prep_auto_on); + -- Other examples of overrides are: + -- (dbms_data_mining.kmns_iterations,3); + -- (dbms_data_mining.kmns_block_growth,2); + -- (dbms_data_mining.kmns_conv_tolerance,0.01); + -- (dbms_data_mining.kmns_split_criterion,dbms_data_mining.kmns_variance); + -- (dbms_data_mining.kmns_min_pct_attr_support,0.1); + -- (dbms_data_mining.kmns_num_bins,10); +END; +/ + +--------------------- +-- CREATE A NEW MODEL +-- +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'KM_SH_Clus_sample', + mining_function => dbms_data_mining.clustering, + data_table_name => 'mining_data_build_v', + case_id_column_name => 'cust_id', + settings_table_name => 'km_sh_sample_settings'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30 +column setting_value format a30 +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'KM_SH_CLUS_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +column attribute_name format a40 +column attribute_type format a20 +SELECT attribute_name, attribute_type + FROM user_mining_model_attributes + WHERE model_name = 'KM_SH_CLUS_SAMPLE' +ORDER BY attribute_name; + +------------------------- +-- DISPLAY MODEL METADATA +-- +column mining_function format a20 +column algorithm format a20 +SELECT mining_function, algorithm, model_size + FROM user_mining_models + WHERE model_name = 'KM_SH_CLUS_SAMPLE'; + +------------------------ +-- DISPLAY MODEL DETAILS +-- +-- Cluster details are best seen in pieces - based on the kind of +-- associations and groupings that are needed to be observed. +-- +-- CLUSTERS +-- For each cluster_id, provides the number of records in the cluster, +-- the parent cluster id, the level in the hierarchy, and dispersion - +-- which is a measure of the quality of the cluster, and computationally, +-- the sum of square errors. +-- +SELECT T.id clu_id, + T.record_count rec_cnt, + T.parent parent, + T.tree_level tree_level, + T.dispersion dispersion + FROM (SELECT * + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_KM( + 'KM_SH_Clus_sample')) + ORDER BY id) T + WHERE ROWNUM < 11; + +-- TAXONOMY +-- +SELECT clu_id, child_id + FROM (SELECT T.id clu_id, C.id child_id + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_KM( + 'KM_SH_Clus_sample')) T, + TABLE(T.child) C + ORDER BY T.id,C.id) + WHERE ROWNUM < 11; + +-- CENTROIDS FOR LEAF CLUSTERS +-- For each cluster_id, this output lists all the attributes that +-- constitute the centroid, with the mean (for numericals) or +-- mode (for categoricals), along with the variance from mean +-- +column aname format a30 +column mode_val format a60 +WITH +centroid_tab AS ( +SELECT T.id clu_id, + C.attribute_name aname, + C.mean mean_val, + C.mode_value mode_val, + C.variance variance + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_KM('KM_SH_Clus_sample')) T, + TABLE(T.centroid) C +ORDER BY T.id, C.attribute_name +) +SELECT clu_id, aname, mean_val, mode_val, variance + FROM centroid_tab + WHERE clu_id > 17 AND ROWNUM < 11; + +-- HISTOGRAM FOR TWO LEAF CLUSTERS +-- +WITH +hist_tab AS ( +SELECT T.id clu_id, + H.attribute_name aname, + H.lower_bound lower_b, + H.upper_bound upper_b, + H.count rec_cnt + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_KM('KM_SH_Clus_sample')) T, + TABLE(T.histogram) H +ORDER BY T.id, H.attribute_name, H.label +) +SELECT clu_id, aname, lower_b, upper_b, rec_cnt + FROM hist_tab + WHERE clu_id > 17 AND ROWNUM < 11; + +-- RULES FOR LEAF CLUSTERS +-- A rule_id corresponds to the associated cluster_id. The support +-- indicates the number of records (say M) that satisfies this rule. +-- This is an upper bound on the number of records that fall within +-- the bounding box defined by the rule. Each predicate in the rule +-- antecedent defines a range for an attribute, and it can be +-- interpreted as the side of a bounding box which envelops most of +-- the data in the cluster. +-- Confidence = M/N, where N is the number of records in the cluster +-- and M is the rule support defined as above. +-- +SELECT T.id rule_id, + T.rule.rule_support support, + T.rule.rule_confidence confidence + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_KM('KM_SH_Clus_sample')) T +ORDER BY T.id; + +-- RULE DETAILS FOR LEAF CLUSTERS +-- Attribute level details of each rule/cluster id. +-- For an attribute, support (say M) indicates the number of records that +-- fall in the attribute range specified in the rule antecedent where the +-- given attribute is not null. Confidence is a number between 0 and 1 +-- that indicates how relevant this attribute is in distinguishing the +-- the records in the cluster from all the records in the whole data. The +-- larger the number, more relevant the attribute. +-- +-- The query shown below reverse-transforms the data to its original +-- values, since build data was normalized. +-- +column aname format a25 +column op format a3 +column val format a60 +column support format 9999 +column confidence format 9.9999 +WITH +rule_tab AS ( +SELECT T.id rule_id, + A.attribute_name aname, + A.conditional_operator op, + NVL(A.attribute_str_value, + ROUND(A.attribute_num_value,4)) val, + A.attribute_support support, + A.attribute_confidence confidence + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_KM('KM_SH_Clus_sample')) T, + TABLE(T.rule.antecedent) A +ORDER BY T.id, A.attribute_name, support, confidence desc, val +) +SELECT rule_id, aname, op, val, support, confidence + FROM rule_tab + WHERE rule_id < 3; + +----------------------------------------------------------------------- +-- TEST THE MODEL +----------------------------------------------------------------------- + +-- There is no specific set of testing parameters for Clustering. +-- Examination and analysis of clusters is the main method to prove +-- the efficacy of a clustering model. +-- + +----------------------------------------------------------------------- +-- APPLY THE MODEL +----------------------------------------------------------------------- +-- For a descriptive mining function like Clustering, "Scoring" involves +-- providing the probability values for each cluster. + +-- Cleanup scoring data preparation objects for repeat runs + +BEGIN EXECUTE IMMEDIATE 'DROP TYPE Cattrs'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TYPE Cattr'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +------------------------------------------------- +-- SCORE NEW DATA USING SQL DATA MINING FUNCTIONS +-- +------------------ +-- BUSINESS CASE 1 +-- List the clusters into which the customers in this +-- given dataset have been grouped. +-- +SELECT CLUSTER_ID(km_sh_clus_sample USING *) AS clus, COUNT(*) AS cnt + FROM mining_data_apply_v +GROUP BY CLUSTER_ID(km_sh_clus_sample USING *) +ORDER BY cnt DESC; + +------------------ +-- BUSINESS CASE 2 +-- List ten most representative (based on likelihood) customers of cluster 2 +-- +SELECT * + FROM (SELECT cust_id, CLUSTER_PROBABILITY(km_sh_clus_sample, 2 USING *) prob + FROM mining_data_apply_v + ORDER BY prob DESC) + WHERE ROWNUM < 11; + +column prob format 9.9999 +column attr format a15 +column val format a15 +column conf format 9.9999 +------------------ +-- BUSINESS CASE 3 +-- List the most relevant attributes (with confidence > 55%) +-- of each cluster in which a given customer (id 101362) belongs +-- to with > 20% likelihood. +-- +set echo off +CREATE TYPE Cattr AS OBJECT ( + attr VARCHAR2(30), + op VARCHAR2(3), + val VARCHAR2(30), + supp NUMBER, + conf NUMBER) +/ +set echo on +CREATE TYPE Cattrs AS TABLE OF Cattr +/ + +column attr format a30 +column op format a2 +WITH +clus_tab AS ( +SELECT id, + A.attribute_name aname, + A.conditional_operator op, + NVL(A.attribute_str_value, + ROUND(A.attribute_num_value,4)) val, + A.attribute_support support, + A.attribute_confidence confidence + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_KM('km_sh_clus_sample')) T, + TABLE(T.rule.antecedent) A + WHERE A.attribute_confidence > 0.55 +), +clust AS ( +SELECT id, + CAST(COLLECT(Cattr(aname, op, TO_CHAR(val), support, confidence)) + AS Cattrs) cl_attrs + FROM clus_tab +GROUP BY id +), +custclus AS ( +SELECT T.cust_id, S.cluster_id, S.probability + FROM (SELECT cust_id, CLUSTER_SET(km_sh_clus_sample, NULL, 0.2 USING *) pset + FROM mining_data_apply_v + WHERE cust_id = 101362) T, + TABLE(T.pset) S +) +SELECT A.probability prob, A.cluster_id cl_id, + B.attr, B.op, B.val, B.supp, B.conf + FROM custclus A, + (SELECT T.id, C.* + FROM clust T, + TABLE(T.cl_attrs) C) B + WHERE A.cluster_id = B.id +ORDER BY prob DESC, cl_id ASC, conf DESC, attr ASC, val ASC; diff --git a/dmnbdemo.java b/dmnbdemo.java new file mode 100644 index 0000000..3b6bc56 --- /dev/null +++ b/dmnbdemo.java @@ -0,0 +1,1009 @@ +// Copyright (c) 2004, 2007, Oracle. All rights reserved. +// File: dmnbdemo.java + +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to solve a classification problem using the Naive Bayes(NB) algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* How to predict whether a customer responds or not to the new affinity card +* program using a classifier based on NB algorithm? +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the previous affinity card +* programs. Data exploration and preparing the data is a common step before +* doing any data mining. Here in this demo, the following views are created +* in the user schema using CUSTOMERS, COUNTRIES and SUPPLIMENTARY_DEMOGRAPHICS +* tables. +* +* MINING_DATA_BUILD_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for building the model. +* +* MINING_DATA_TEST_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for testing the model. +* +* MINING_DATA_APPLY_V: +* This view collects the prospective customers' demographics and purchasing +* details for predicting response to the new affinity card program. +* +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Prepare Data: +* For NB, binning transformation is used to reduce the carinality of +* higher cardinality attributes. The prepareData() method in this demo program +* illustrates the preparation of the build, test, and apply data. +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a classification model using the NB algorithm. +* Test Model: +* Classification model performance can be evaluated by computing test +* metrics like accuracy, confusion matrix, lift, and ROC. The testModel() or +* computeTestMetrics() method illustrates how to perform the test operation to +* compute various metrics. +* Apply Model: +* Predicting the target attribute values is the prime function of +* classification models. The applyModel() method illustrates how to +* predict the customer response for an affinity card program. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +// Generic api imports +import java.math.BigDecimal; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.Statement; + +import java.text.DecimalFormat; +import java.text.MessageFormat; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.MiningAlgorithm; +import javax.datamining.MiningFunction; +import javax.datamining.NamedObject; +import javax.datamining.algorithm.naivebayes.NaiveBayesSettings; +import javax.datamining.algorithm.naivebayes.NaiveBayesSettingsFactory; +import javax.datamining.base.AlgorithmSettings; +import javax.datamining.base.Model; +import javax.datamining.base.Task; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.CategoryProperty; +import javax.datamining.data.CategorySet; +import javax.datamining.data.CategorySetFactory; +import javax.datamining.data.ModelSignature; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.data.SignatureAttribute; +import javax.datamining.modeldetail.naivebayes.NaiveBayesModelDetail; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.supervised.classification.ClassificationApplyContent; +import javax.datamining.supervised.classification.ClassificationApplySettings; +import javax.datamining.supervised.classification.ClassificationApplySettingsFactory; +import javax.datamining.supervised.classification.ClassificationModel; +import javax.datamining.supervised.classification.ClassificationSettings; +import javax.datamining.supervised.classification.ClassificationSettingsFactory; +import javax.datamining.supervised.classification.ClassificationTestMetrics; +import javax.datamining.supervised.classification.ClassificationTestMetricsTaskFactory; +import javax.datamining.supervised.classification.ClassificationTestTask; +import javax.datamining.supervised.classification.ClassificationTestTaskFactory; +import javax.datamining.supervised.classification.ConfusionMatrix; +import javax.datamining.supervised.classification.CostMatrix; +import javax.datamining.supervised.classification.CostMatrixFactory; +import javax.datamining.supervised.classification.Lift; +import javax.datamining.supervised.classification.ReceiverOperatingCharacterics; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; +import javax.datamining.task.apply.DataSetApplyTask; +import javax.datamining.task.apply.DataSetApplyTaskFactory; + +import oracle.dmt.jdm.base.OraBuildSettings; +import oracle.dmt.jdm.base.OraModel; +import oracle.dmt.jdm.modeldetail.naivebayes.OraNaiveBayesModelDetail; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.supervised.OraTestTask; +import oracle.dmt.jdm.supervised.classification.OraClassificationApplySettings; +import oracle.dmt.jdm.supervised.classification.OraClassificationModel; +import oracle.dmt.jdm.supervised.classification.OraLift; +import oracle.dmt.jdm.task.OraBuildTask; +import oracle.dmt.jdm.transform.OraExpressionTransform; +import oracle.dmt.jdm.transform.OraTransformationFactory; +import oracle.dmt.jdm.transform.OraTransformationSequence; + +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to solve a classification problem using the Naive Bayes(NB) algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* How to predict whether a customer responds or not to the new affinity card +* program using a classifier based on NB algorithm? +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the previous affinity card +* programs. Data exploration and preparing the data is a common step before +* doing any data mining. Here in this demo, the following views are created +* in the user schema using CUSTOMERS, COUNTRIES and SUPPLIMENTARY_DEMOGRAPHICS +* tables. +* +* MINING_DATA_BUILD_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for building the model. +* +* MINING_DATA_TEST_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for testing the model. +* +* MINING_DATA_APPLY_V: +* This view collects the prospective customers' demographics and purchasing +* details for predicting response to the new affinity card program. +* +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Prepare Data: +* For NB, binning transformation is used to reduce the carinality of +* higher cardinality attributes. The prepareData() method in this demo program +* illustrates the preparation of the build, test, and apply data. +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a classification model using the NB algorithm. +* Test Model: +* Classification model performance can be evaluated by computing test +* metrics like accuracy, confusion matrix, lift, and ROC. The testModel() or +* computeTestMetrics() method illustrates how to perform the test operation to +* compute various metrics. +* Apply Model: +* Predicting the target attribute values is the prime function of +* classification models. The applyModel() method illustrates how to +* predict the customer response for an affinity card program. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +// Java Data Mining (JDM) standard imports +// Oracle Java Data Mining (JDM) implemented api imports + +public class dmnbdemo extends Object { + // Connection related data members + private static javax.datamining.resource.Connection m_dmeConn; + private static javax.datamining.resource.ConnectionFactory m_dmeConnFactory; + // Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static ClassificationSettingsFactory m_clasFactory; + private static NaiveBayesSettingsFactory m_nbFactory; + private static BuildTaskFactory m_buildFactory; + private static DataSetApplyTaskFactory m_dsApplyFactory; + private static ClassificationTestTaskFactory m_testFactory; + private static ClassificationApplySettingsFactory m_applySettingsFactory; + private static CostMatrixFactory m_costMatrixFactory; + private static CategorySetFactory m_catSetFactory; + private static ClassificationTestMetricsTaskFactory m_testMetricsTaskFactory; + private static OraTransformationFactory m_xformFactory; + // Global constants + private static DecimalFormat m_df = new DecimalFormat("##.####"); + + public static void main( String args[] ) { + try { + if (( args.length != 0 ) & ( args.length != 3 )) { + System.out.println("Usage: java dmnbdemo "); + System.out.println(" or: java dmnbdemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + // 1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@"+uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Build model with supplied prior probability + buildModel(); + // 5. Test model - To compute accuracy and confusion matrix, lift result + // and ROC for the model from a test input data. + String costMatrixName = createCostMatrix(); + //Add cost matrix to the model + OraClassificationModel.addCostMatrix(m_dmeConn, "nbModel_jdm", costMatrixName); + // Test the model with cost matrix + boolean useCostMatrix = true; + testModel("nbTestMetricsWithCost_jdm", useCostMatrix); + // Test the model without cost matrix + useCostMatrix = false; + testModel("nbTestMetrics_jdm", useCostMatrix); + //Remove cost matrix from the model after testing is done + OraClassificationModel.removeCostMatrix(m_dmeConn, "nbModel_jdm"); + // 6. Apply model + applyModel(); + // 7. Rank Apply model with cost matrix + rankApplyModel(costMatrixName); + } catch(Exception anyExp) { + anyExp.printStackTrace(System.out); + } finally { + try { + // 8. Logout from the Data Mining Engine + m_dmeConn.close(); + } catch(Exception anyExp1) { } // Ignore + } + } + + /** + * Initialize all object factories used in the demo program. + * + * @exception JDMException if factory initalization failed + */ + public static void initFactories() throws JDMException + { + m_pdsFactory = (PhysicalDataSetFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalDataSet"); + m_paFactory = (PhysicalAttributeFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalAttribute"); + m_clasFactory = (ClassificationSettingsFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationSettings"); + m_nbFactory = (NaiveBayesSettingsFactory)m_dmeConn.getFactory( + "javax.datamining.algorithm.naivebayes.NaiveBayesSettings"); + m_buildFactory = (BuildTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.BuildTask"); + m_dsApplyFactory = (DataSetApplyTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.apply.DataSetApplyTask"); + m_testFactory = (ClassificationTestTaskFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationTestTask"); + m_applySettingsFactory = (ClassificationApplySettingsFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationApplySettings"); + m_costMatrixFactory = (CostMatrixFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.CostMatrix"); + m_catSetFactory = (CategorySetFactory)m_dmeConn.getFactory( + "javax.datamining.data.CategorySet" ); + m_testMetricsTaskFactory = (ClassificationTestMetricsTaskFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationTestMetricsTask"); + m_xformFactory = (OraTransformationFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.transform.OraTransformation" ); + } + + /** + * This method illustrates how to build a mining model using + * NB_BINNED_DATA_BUILD_JDM dataset and classification settings with + * the NB algorithm. + * + * By default, the NB algorithm uses 0.01 value for both singleton threshold + * and pairwise threshold settings. + * + * @exception JDMException if model build failed + */ + public static void buildModel() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Build Model - using prior probabilities ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = m_pdsFactory.create("MINING_DATA_BUILD_V", false); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + buildData.addAttribute(pa); + m_dmeConn.saveObject("nbBuildData_jdm", buildData, true); + // 2. Create & save Mining Function Settings + // Create NB algorithm settings + NaiveBayesSettings nbAlgo = m_nbFactory.create(); + // + // Thresholding probabilities + // To increase the accuracy of its estimates, ODM can optionally eliminate + // probabilities whose estimates are based on relatively small amounts of + // data. + // + // The Singleton fraction refers to the fraction of training data in which + // a predictor, e.g., X, takes on a specific value, e.g., x1. + // + // Pairwise fraction refers to the fraction of training data in which a + // predictor, X, takes on a specific value, x1, **when** the target, T, + // takes on a specific value t1. + // + // If the singleton fraction associated with a predictor value or the + // pairwise fraction associated with a (predictor value, target value) + // pair are below certain respective thresholds, they are ignored + // in the probability calculations. + // + // Examples settings are: + // nbAlgo.setSingletonThreshold(0.01f); + // nbAlgo.setPairwiseThreshold(0.0001f); + // + // Create ClassificationSettings + ClassificationSettings buildSettings = m_clasFactory.create(); + buildSettings.setAlgorithmSettings(nbAlgo); + buildSettings.setTargetAttributeName("AFFINITY_CARD"); + ((OraBuildSettings)buildSettings).useAutomatedDataPreparations(true);//NEW 11g capability of Automated Data Preparation + // + // Set target prior probabilities. + // + // The priors represent the overall + // distribution of the target in the population. By default, the priors + // are computed from the sample (in this case, the build data). If the + // sample is known to be a distortion of the population target + // distribution (because, say, stratified sampling has been employed, or + // due to some other reason), then the user can override the default by + // providing prior probabilities as a setting for model creation. + // See Oracle Data Mining Concepts Guide for more details. + Map priorMap = new HashMap(); + priorMap.put(new Double(0), new Double(0.65)); + priorMap.put(new Double(1), new Double(0.35)); + buildSettings.setPriorProbabilitiesMap("AFFINITY_CARD", priorMap); + m_dmeConn.saveObject("nbBuildSettings_jdm", buildSettings, true); + //Turn Off ADP for CUST_GENDER attribute + //Create TransformationSequence + OraExpressionTransform exprXform = m_xformFactory.createExpressionTransform(); + //When attribute specification is set to NOPREP, ADP is truned off for that attribute. + //Here we are specifying for CUST_GENDER attribute "NOPREP" to flag ADP to be truned off + exprXform.addAttributeExpression("CUST_GENDER", null, null, "NOPREP"); + //Output view can be specified a null in this case, because we are + //not intended to create a view but embed the expression transformations + //with the model + OraTransformationSequence xformSeq = m_xformFactory.createTransformationSequence( + "MINING_DATA_BUILD_V", exprXform, null ); + m_dmeConn.saveObject("nbTSADPoff_jdm", xformSeq, true); + // 3. Create, save & execute Build Task + BuildTask buildTask = m_buildFactory.create( + "nbBuildData_jdm", //Build data specification + "nbBuildSettings_jdm", //Mining function settings name + "nbModel_jdm" //Mining model name + ); + //Specify expression transformations that are defined to specify ADP off attributes + //as an embedded transformation to the model build + ((OraBuildTask)buildTask).setTransformationSequenceName("nbTSADPoff_jdm"); + buildTask.setDescription("nbBuildTask_jdm"); + executeTask(buildTask, "nbBuildTask_jdm"); + // 4. Restore the model from the DME and explore the details of the model + ClassificationModel model = + (ClassificationModel)m_dmeConn.retrieveObject( + "nbModel_jdm", NamedObject.model); + + OraExpressionTransform autoDataPrepSQLExprs = ((OraModel)model).getModelTransformations(); + Map exprMap = autoDataPrepSQLExprs.getAttributeExpressionMap(); + + // Display model build settings + ClassificationSettings retrievedBuildSettings = + (ClassificationSettings)model.getBuildSettings(); + if(buildSettings == null) + System.out.println("Failure to restore build settings."); + else + displayBuildSettings(retrievedBuildSettings, "nbBuildSettings_jdm"); + // Display model signature + displayModelSignature((Model)model); + // Display model details + displayNBModelDetails(model); + } + + /** + * Create and save cost matrix. + * + * Consider an example where it costs $10 to mail a promotion to a + * prospective customer and if the prospect becomes a customer, the + * typical sale including the promotion, is worth $100. Then the cost + * of missing a customer (i.e. missing a $100 sale) is 10x that of + * incorrectly indicating that a person is a good prospect (spending + * $10 for the promo). In this case, all prediction errors made by + * the model are NOT equal. To act on what the model determines to + * be the most likely (probable) outcome may be a poor choice. + * + * Suppose that the probability of a BUY reponse is 10% for a given + * prospect. Then the expected revenue from the prospect is: + * .10 * $100 - .90 * $10 = $1. + * + * The optimal action, given the cost matrix, is to simply mail the + * promotion to the customer, because the action is profitable ($1). + * + * In contrast, without the cost matrix, all that can be said is + * that the most likely response is NO BUY, so don't send the + * promotion. This shows that cost matrices can be very important. + * + * The caveat in all this is that the model predicted probabilities + * may NOT be accurate. For binary targets, a systematic approach to + * this issue exists. It is ROC, illustrated below. + * + * With ROC computed on a test set, the user can see how various model + * predicted probability thresholds affect the action of mailing a promotion. + * Suppose I promote when the probability to BUY exceeds 5, 10, 15%, etc. + * what return can I expect? Note that the answer to this question does + * not rely on the predicted probabilities being accurate, only that + * they are in approximately the correct rank order. + * + * Assuming that the predicted probabilities are accurate, provide the + * cost matrix table name as input to the RANK_APPLY procedure to get + * appropriate costed scoring results to determine the most appropriate + * action. + * + * In this demo, we will create the following cost matrix + * + * ActualTarget PredictedTarget Cost + * ------------ --------------- ---- + * 0 0 0 + * 0 1 0.35 + * 1 0 0.65 + * 1 1 0 + */ + private static String createCostMatrix() throws JDMException + { + String costMatrixName = "nbCostMatrix"; + // Create categorySet + CategorySet catSet = m_catSetFactory.create(AttributeDataType.integerType); + // Add category values + catSet.addCategory(new Integer(0), CategoryProperty.valid); + catSet.addCategory(new Integer(1), CategoryProperty.valid); + // Create cost matrix + CostMatrix costMatrix = m_costMatrixFactory.create(catSet); + // ActualTarget PredictedTarget Cost + // ------------ --------------- ---- + costMatrix.setValue(new Integer(0), new Integer(0), 0); + costMatrix.setValue(new Integer(0), new Integer(1), 0.35f); + costMatrix.setValue(new Integer(1), new Integer(0), 0.65f); + costMatrix.setValue(new Integer(1), new Integer(1), 0); + //save cost matrix + m_dmeConn.saveObject(costMatrixName, costMatrix, true); + return costMatrixName; + } + + /** + * This method illustrates how to test the mining model with + * NB_BINNED_DATA_TEST_JDM dataset using classification test task. After + * completion of the task, a classification test metrics object is created + * in the DMS. The classification test metrics object encapsulates + * different metrics like accuracy, confusion matrix, lift, and ROC. + * + * @param testResultName test result name + * @param useCostMatrix flag to indicate the enabling/disabling cost matrix added to the model + * @exception JDMException if model test failed + */ + public static void testModel(String testResultName, boolean useCostMatrix) + throws JDMException + { + if (useCostMatrix) { + System.out.println("---------------------------------------------------"); + System.out.println("--- Test Model - using test input table ---"); + System.out.println("--- - using cost matrix table ---"); + System.out.println("---------------------------------------------------"); + } + else { + System.out.println("---------------------------------------------------"); + System.out.println("--- Test Model - using test input table ---"); + System.out.println("--- - using no cost matrix table ---"); + System.out.println("---------------------------------------------------"); + } + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet testData = m_pdsFactory.create( + "MINING_DATA_TEST_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + testData.addAttribute( pa ); + m_dmeConn.saveObject( "nbTestData_jdm", testData, true ); + // 2. Create, store & execute Test Task + ClassificationTestTask testTask = m_testFactory.create( + "nbTestData_jdm", "nbModel_jdm", testResultName ); + testTask.setPositiveTargetValue(new Integer(1)); + testTask.setNumberOfLiftQuantiles(10); + //Set useCost flag to indicate enabling/disabling of cost matrix in testing the model + ((OraTestTask)testTask).useCost(useCostMatrix); + // Store & execute the task + boolean isTaskSuccess = executeTask(testTask, "nbTestTask_jdm"); + if( isTaskSuccess ) { + // Restore & display test metrics + ClassificationTestMetrics testMetrics = + (ClassificationTestMetrics)m_dmeConn.retrieveObject( + testResultName, + NamedObject.testMetrics ); + displayTestMetricDetails(testMetrics); + } + } + + /** + * This method illustrates how to apply the mining model on + * NB_BINNED_DATA_APPLY_JDM dataset to predict customer + * response. After completion of the task, an apply output table with the + * predicted results is created at the user specified location. + * + * @exception JDMException if model apply failed + */ + public static void applyModel() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Apply Model ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = m_pdsFactory.create( + "MINING_DATA_APPLY_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "nbApplyData_jdm", applyData, true ); + // 2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + // Example: Add source attributes + // HashMap sourceAttrMap = new HashMap(); + // sourceAttrMap.put( "AGE", "AGE" ); + // sourceAttrMap.put( "OCCUPATION", "OCCUPATION" ); + // clasAS.setSourceDestinationMap( sourceAttrMap ); + m_dmeConn.saveObject( "nbApplySettings_jdm", clasAS, true); + // 3. Create, store & execute apply Task + DataSetApplyTask applyTask = m_dsApplyFactory.create( + "nbApplyData_jdm", "nbModel_jdm", + "nbApplySettings_jdm", "NB_APPLY_OUTPUT_JDM"); + executeTask(applyTask, "nbApplyTask_jdm"); + // 4. Display apply result -- Note that APPLY results do not need to be + // reverse transformed, as done in the case of model details. This is + // because class values of a classification target were not (required to + // be) binned or normalized. + displayTable("NB_APPLY_OUTPUT_JDM", + "where ROWNUM < 11", + "order by CUST_ID"); + } + + /** + * This method illustrates how to apply the mining model (mapped by rank) on + * NB_BINNED_DATA_APPLY_JDM dataset to predict customer + * response. After completion of the task, an apply output table with the + * predicted results is created at the user specified location. + * + * @param costMatrixName table name of the supplied cost matrix + * @exception JDMException if model apply failed + */ + public static void rankApplyModel(String costMatrixName) throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Rank Apply Model ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification -- We will use apply result + // table from applyModel() to perform rank apply here. + PhysicalDataSet applyData = m_pdsFactory.create( + "MINING_DATA_APPLY_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "nbRankApplyData_jdm", applyData, true ); + // 2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + if(costMatrixName != null ) { + OraClassificationModel.addCostMatrix(m_dmeConn, "nbModel_jdm", costMatrixName); + ((OraClassificationApplySettings)clasAS).useCostMatrixFromModel(true); + } + int topNRanks = 2; + String[] topNCategoryColNames = new String[topNRanks]; + String[] topNProbabilityColNames = new String[topNRanks]; + String[] topNCostColNames = new String[topNRanks]; + for(int i=0; i 5) + { + colContent = m_df.format(obj); + } else + { + colContent = bd.toString(); + } + } catch(Exception anyExp) { + colContent = m_df.format(obj); + } + } else + { + if(obj == null) + colContent = "NULL"; + else + colContent = obj.toString(); + } + + rowContent.append(" "+emptyCol.replace(0, colContent.length(), colContent)); + emptyCol = new StringBuffer(" "); + } + System.out.println(rowContent.toString()); + } + } catch(Exception anySqlExp) { + anySqlExp.printStackTrace(); + }//Ignore + } + + private static void clean() + { + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + Statement stmt = null; + //Drop apply output table + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP TABLE NB_APPLY_OUTPUT_JDM"); + } catch(Exception anySqlExp) {} // Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + //Drop rank apply output table + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP TABLE NB_RANK_APPLY_OUTPUT_JDM"); + } catch(Exception anySqlExp) {} // Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + //Drop the model + try { + m_dmeConn.removeObject("nbModel_jdm", NamedObject.model); + } catch(Exception jdmExp) {} + //Drop the test metrics + try { + m_dmeConn.removeObject("nbTestMetricsWithCost_jdm", NamedObject.testMetrics); + } catch(JDMException jdmExp) {} + try { + m_dmeConn.removeObject("nbTestMetrics_jdm", NamedObject.testMetrics); + } catch(JDMException jdmExp) {} + } + +} diff --git a/dmnbdemo.sql b/dmnbdemo.sql new file mode 100644 index 0000000..e42e483 --- /dev/null +++ b/dmnbdemo.sql @@ -0,0 +1,887 @@ +Rem +Rem $Header: dmnbdemo.sql 25-oct-2007.11:36:01 ramkrish Exp $ +Rem +Rem dmnbdemo.sql +Rem +Rem Copyright (c) 2003, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmnbdemo.sql - Sample program for the DBMS_DATA_MINING package. +Rem +Rem DESCRIPTION +Rem This script creates a classification model +Rem using the Naive Bayes algorithm +Rem and data in the SH (Sales History) schema in the RDBMS. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ramkrish 06/14/07 - remove commit after settings +Rem ramkrish 10/25/07 - replace deprecated get_model calls with catalog +Rem queries +Rem ktaylor 07/11/05 - Minor edits to comments +Rem ramkrish 01/28/05 - prediction column format fixes +Rem jcjeon 01/18/05 - add column format +Rem jyarmus 11/05/04 - review and update cost code +Rem ramkrish 09/21/04 - add data analysis and comments/cleanup +Rem ramkrish 10/02/03 - Creation + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET echo ON + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM +----------------------------------------------------------------------- +-- Given demographic data about a set of customers, predict the +-- customer response to an affinity card program using a classifier +-- based on the NB algorithm. + +----------------------------------------------------------------------- +-- SET UP AND ANALYZE THE DATA +----------------------------------------------------------------------- + +-- See the corresponding section in dmabdemo.sql - Classification +-- using ABN. The analysis and preparation steps are very similar. + +----------------------------------------------------------------------- +-- BUILD THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old build data preparation objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nb_sh_sample_num'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nb_sh_sample_cat'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW nb_sh_sample_build_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW nb_sh_sample_build_cat'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +-- Cleanup old model with the same name for repeat runs +BEGIN DBMS_DATA_MINING.DROP_MODEL('NB_SH_Clas_sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-------------------------------- +-- PREPARE BUILD (TRAINING) DATA +-- +-- 1. Missing Value treatment for all Predictors +-- Skipped - see dmsvcdem.sql +-- +-- 2. Outlier Treatment +-- Skipped - due to choice of quantile binning +-- +-- 3. Binning +-- +BEGIN + -- Bin categorical attributes: OCCUPATION + DBMS_DATA_MINING_TRANSFORM.CREATE_BIN_CAT ( + bin_table_name => 'nb_sh_sample_cat'); + DBMS_DATA_MINING_TRANSFORM.INSERT_BIN_CAT_FREQ ( + bin_table_name => 'nb_sh_sample_cat', + data_table_name => 'mining_data_build_v', + bin_num => 7, + exclude_list => DBMS_DATA_MINING_TRANSFORM.COLUMN_LIST ( + 'cust_gender', + 'cust_marital_status', + 'cust_income_level', + 'education', + 'household_size') + ); + + -- Bin numerical attributes: AGE + DBMS_DATA_MINING_TRANSFORM.CREATE_BIN_NUM ( + bin_table_name => 'nb_sh_sample_num'); + DBMS_DATA_MINING_TRANSFORM.INSERT_BIN_NUM_QTILE ( + bin_table_name => 'nb_sh_sample_num', + data_table_name => 'mining_data_build_v', + bin_num => 7, + exclude_list => DBMS_DATA_MINING_TRANSFORM.COLUMN_LIST ( + 'affinity_card', + 'bookkeeping_application', + 'bulk_pack_diskettes', + 'cust_id', + 'flat_panel_monitor', + 'home_theater_package', + 'os_doc_set_kanji', + 'printer_supplies', + 'y_box_games') + ); + + -- Create the transformed view + -- Execute the first transformation (categorical binning) + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_CAT ( + bin_table_name => 'nb_sh_sample_cat', + data_table_name => 'mining_data_build_v', + xform_view_name => 'nb_sh_sample_build_cat'); + + -- Provide the result (nb_sh_sample_build_cat) + -- to the next transformation (numerical binning) + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_NUM ( + bin_table_name => 'nb_sh_sample_num', + data_table_name => 'nb_sh_sample_build_cat', + xform_view_name => 'nb_sh_sample_build_prepared'); +END; +/ + +-- BUILD DATA PREPARATION OBJECTS: +-- ------------------------------ +-- 1. Categorical Bin Table: nb_sh_sample_cat +-- 2. Numerical Bin Table: nb_sh_sample_num +-- 3. Input (view) to CREATE_MODEL: nb_sh_sample_build_prepared + +------------------- +-- SPECIFY SETTINGS +-- +-- Cleanup old settings table objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nb_sh_sample_settings'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nb_sh_sample_priors'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- Algorithm setting: +-- NB is the default classifier, thus there is no need to specify +-- the algorithm in settings table when the mining_function parameter +-- of the CREATE_MODEL operation specifies classification. + +-- CREATE AND POPULATE A PRIORS TABLE +-- The priors represent the overall distribution of the target in +-- the population. By default, the priors are computed from the sample +-- (in this case, the build data). If the sample is known to be a +-- distortion of the population target distribution (because, say, +-- stratified sampling has been employed, or due to some other reason), +-- then the user can override the default by providing a priors table +-- as a setting for model creation. See Oracle Data Mining Concepts Guide +-- for more details. +-- +CREATE TABLE nb_sh_sample_priors ( + target_value NUMBER, + prior_probability NUMBER); +INSERT INTO nb_sh_sample_priors VALUES (0,0.65); +INSERT INTO nb_sh_sample_priors VALUES (1,0.35); + +-- CREATE AND POPULATE A SETTINGS TABLE +-- +-- Thresholding probabilities +-- To increase the accuracy of its estimates, ODM can optionally eliminate +-- probabilities whose estimates are based on relatively small amounts of data. +-- +-- The Singleton fraction refers to the fraction of training data in which a +-- predictor, e.g., X, takes on a specific value, e.g., x1. +-- +-- Pairwise fraction refers to the fraction of training data in which a +-- predictor, X, takes on a specific value, x1, **when** the target, T, +-- takes on a specific value t1. +-- +-- If the singleton fraction associated with a predictor value or the +-- pairwise fraction associated with a (predictor value, target value) +-- pair are below certain respective thresholds, they are ignored +-- in the probability calculations. +-- +-- Examples settings are: +--(dbms_data_mining.nabs_pairwise_threshold,'0.0001') +--(dbms_data_mining.nabs_singleton_threshold,'0.01') +-- +set echo off +CREATE TABLE nb_sh_sample_settings ( + setting_name VARCHAR2(30), + setting_value VARCHAR2(30)); +set echo on +BEGIN + INSERT INTO nb_sh_sample_settings VALUES + (dbms_data_mining.clas_priors_table_name, 'nb_sh_sample_priors'); +END; +/ + +--------------------- +-- CREATE A NEW MODEL +-- +-- Build a new NB model +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'NB_SH_Clas_sample', + mining_function => dbms_data_mining.classification, + data_table_name => 'nb_sh_sample_build_prepared', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + settings_table_name => 'nb_sh_sample_settings'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30 +column setting_value format a30 +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'NB_SH_CLAS_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +column attribute_name format a40 +column attribute_type format a20 +SELECT attribute_name, attribute_type + FROM user_mining_model_attributes + WHERE model_name = 'NB_SH_CLAS_SAMPLE' +ORDER BY attribute_name; + +------------------------ +-- DISPLAY MODEL DETAILS +-- +-- Binned data for meaningful model statistics: +-- The number of distinct values for each predictor should be limited +-- so that the probabilities estimated by the model have sufficient support +-- (i.e. number of rows) to be statistically meaningful. If the original +-- data has predictors with large numbers of values, then the data should +-- be binned into groups. This can be done either by using third-party tools +-- or the DBMS_DATA_MINING_TRANSFORM package. +-- +-- If the build data is prepared (as in this example), then the training +-- data has been encoded. For numeric data, this means that ranges of +-- values have been grouped into bins and the original value encoded by +-- the bin number. For categorical data, the k most frequent values are +-- retained and the rest are grouped into an OTHER category. +-- +-- Thus to display the model statistics in a meaningful way to the user, +-- the data must be decoded. The model statistics consist of: +-- . (unconditional) distribution of the target - the overall proportion +-- of each target value in the population (termed the prior), and +-- . the conditional probabilities of the various predictor values given +-- each specific target value. +-- +-- Using the Bayes formula and the conditional independence assumptions +-- made by Naive Bayes, the probability of each target value can be +-- computed from the prior and conditional probabilities. +-- +-- +-- The SQL query presented below does the following. +-- 1. Use the bin boundary tables to create labels +-- 2. Replace attribute values with labels +-- 3. For numeric bins, the labels are "[/(lower_boundary,upper_boundary]/)" +-- 4. For categorical bins, label matches the value it represents +-- Note that this method of categorical label representation +-- will only work for cases where one value corresponds to one bin +-- Target was not binned, hence we don't unbin the target. +-- +-- You can replace the model name in the query with your own, +-- and also adapt the query to accomodate other transforms. +-- +-- +column tname format a14 +column tval format a4 +column pname format a20 +column pval format a13 +column priorp format 9.9999 +column condp format 9.9999 +WITH +bin_label_view AS ( +SELECT col, bin, (DECODE(bin,'1','[','(') || lv || ',' || val || ']') label + FROM (SELECT col, + bin, + LAST_VALUE(val) OVER ( + PARTITION BY col ORDER BY val + ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) lv, + val + FROM nb_sh_sample_num) +UNION ALL +SELECT col, bin, val label + FROM nb_sh_sample_cat +), +model_details AS ( +SELECT T.target_attribute_name tname, + TO_CHAR( + NVL(T.target_attribute_num_value,T.target_attribute_str_value)) tval, + C.attribute_name pname, + NVL(L.label, NVL(C.attribute_str_value, C.attribute_num_value)) pval, + T.prior_probability priorp, + C.conditional_probability condp + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_NB('NB_SH_Clas_sample')) T, + TABLE(T.conditionals) C, + bin_label_view L + WHERE C.attribute_name = L.col (+) AND + (NVL(C.attribute_str_value,C.attribute_num_value) = L.bin(+)) +ORDER BY 1,2,3,4,5,6 +) +SELECT tname, tval, pname, pval, priorp, condp + FROM model_details + WHERE ROWNUM < 11; + +----------------------------------------------------------------------- +-- TEST THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old test data preparation objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP VIEW nb_sh_sample_test_targets'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW nb_sh_sample_test_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW nb_sh_sample_test_cat'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-------------------- +-- PREPARE TEST DATA +-- +-- If the data for model creation has been prepared, then the data used +-- for testing the model must be prepared in the same manner in order to +-- obtain meaningful results. +-- +-- 1. Missing value treatment - see dmsvcdem.sql for example on what +-- needs to be done with Test and Apply data input. +-- +-- 2. Outlier treatment and +-- 3. Binning -- Quantile binning handles both the outlier treatment and +-- binning in this case. +-- +-- Transform the test data mining_test_v, using the transformation tables +-- generated during the Build data preparation, to generate a view representing +-- prepared test data. +-- +-- If this model is tested in a different schema or instance, the +-- data preparation objects generated in the CREATE step must also +-- be made available in the target schema/instance. So you must export +-- those objects (i.e. the num and cat bin tables and views) along with +-- the model to the target user schema. +-- +BEGIN + -- Execute the first transform effected on training data + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_CAT ( + bin_table_name => 'nb_sh_sample_cat', + data_table_name => 'mining_data_test_v', + xform_view_name => 'nb_sh_sample_test_cat'); + + -- Provide the result to the next transform effected on training data + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_NUM ( + bin_table_name => 'nb_sh_sample_num', + data_table_name => 'nb_sh_sample_test_cat', + xform_view_name => 'nb_sh_sample_test_prepared'); +END; +/ + +-- Cleanup old test result objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nb_sh_sample_test_apply'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nb_sh_sample_confusion_matrix'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nb_sh_sample_cm_no_cost'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nb_sh_sample_lift'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nb_sh_sample_roc'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nb_alter_cost'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nb_sh_alter_confusion_matrix'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +------------------------------------ +-- COMPUTE METRICS TO TEST THE MODEL +-- +-- The COMPUTE interfaces that provide the test results require two +-- data inputs: +-- 1. A table or view of targets - i.e. one that provides only the +-- case identifier and target columns of your test data. +-- 2. The table with the results of an APPLY operation on test data. +-- + +-- CREATE TEST TARGETS VIEW +-- +CREATE VIEW nb_sh_sample_test_targets AS +SELECT cust_id, affinity_card + FROM nb_sh_sample_test_prepared; + +-- APPLY MODEL ON TEST DATA +-- +BEGIN + DBMS_DATA_MINING.APPLY( + model_name => 'NB_SH_Clas_sample', + data_table_name => 'nb_sh_sample_test_prepared', + case_id_column_name => 'cust_id', + result_table_name => 'nb_sh_sample_test_apply'); +END; +/ + +---------------------------------- +-- COMPUTE TEST METRICS, WITH COST +-- +---------------------- +-- Specify cost matrix +-- +-- Consider an example where it costs $10 to mail a promotion to a +-- prospective customer and if the prospect becomes a customer, the +-- typical sale including the promotion, is worth $100. Then the cost +-- of missing a customer (i.e. missing a $100 sale) is 10x that of +-- incorrectly indicating that a person is good prospect (spending +-- $10 for the promo). In this case, all prediction errors made by +-- the model are NOT equal. To act on what the model determines to +-- be the most likely (probable) outcome may be a poor choice. +-- +-- Suppose that the probability of a BUY reponse is 10% for a given +-- prospect. Then the expected revenue from the prospect is: +-- .10 * $100 - .90 * $10 = $1. +-- The optimal action, given the cost matrix, is to simply mail the +-- promotion to the customer, because the action is profitable ($1). +-- +-- In contrast, without the cost matrix, all that can be said is +-- that the most likely response is NO BUY, so don't send the +-- promotion. +-- +-- This shows that cost matrices can be very important. +-- +-- The caveat in all this is that the model predicted probabilities +-- may NOT be accurate. For binary targets, a systematic approach to +-- this issue exists. It is ROC, illustrated below. +-- +-- With ROC computed on a test set, the user can see how various model +-- predicted probability thresholds affect the action of mailing a promotion. +-- Suppose I promote when the probability to BUY exceeds 5, 10, 15%, etc. +-- What return can I expect? Note that the answer to this question does +-- not rely on the predicted probabilities being accurate, only that +-- they are in approximately the correct rank order. +-- +-- Assuming that the predicted probabilities are accurate, provide the +-- cost matrix table name as input to the RANK_APPLY procedure to get +-- appropriate costed scoring results to determine the most appropriate +-- action. + +-- Cleanup old cost matrix table for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nb_sh_cost'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- CREATE A COST MATRIX TABLE +-- +CREATE TABLE nb_sh_cost ( + actual_target_value NUMBER, + predicted_target_value NUMBER, + cost NUMBER); + +-- POPULATE THE COST MATRIX +-- +INSERT INTO nb_sh_cost VALUES (0,0,0); +INSERT INTO nb_sh_cost VALUES (0,1,.35); +INSERT INTO nb_sh_cost VALUES (1,0,.65); +INSERT INTO nb_sh_cost VALUES (1,1,0); + +-- Compute Test Metrics +DECLARE + v_accuracy NUMBER; + v_area_under_curve NUMBER; +BEGIN + DBMS_DATA_MINING.COMPUTE_CONFUSION_MATRIX ( + accuracy => v_accuracy, + apply_result_table_name => 'nb_sh_sample_test_apply', + target_table_name => 'nb_sh_sample_test_targets', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + confusion_matrix_table_name => 'nb_sh_sample_confusion_matrix', + score_column_name => 'PREDICTION', -- default + score_criterion_column_name => 'PROBABILITY', -- default + cost_matrix_table_name => 'nb_sh_cost'); + DBMS_OUTPUT.PUT_LINE('**** MODEL ACCURACY ****: ' || ROUND(v_accuracy,4)); + + DBMS_DATA_MINING.COMPUTE_LIFT ( + apply_result_table_name => 'nb_sh_sample_test_apply', + target_table_name => 'nb_sh_sample_test_targets', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + lift_table_name => 'nb_sh_sample_lift', + positive_target_value => '1', + num_quantiles => '10', + cost_matrix_table_name => 'nb_sh_cost'); + + DBMS_DATA_MINING.COMPUTE_ROC ( + roc_area_under_curve => v_area_under_curve, + apply_result_table_name => 'nb_sh_sample_test_apply', + target_table_name => 'nb_sh_sample_test_targets', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + roc_table_name => 'nb_sh_sample_roc', + positive_target_value => '1', + score_column_name => 'PREDICTION', + score_criterion_column_name => 'PROBABILITY'); + DBMS_OUTPUT.PUT_LINE('**** AREA UNDER ROC CURVE ****: ' || + ROUND(v_area_under_curve,4)); +END; +/ + +-- TEST RESULT OBJECTS: +-- ------------------- +-- 1. Confusion matrix Table: nb_sh_sample_confusion_matrix +-- 2. Lift Table: nb_sh_sample_lift +-- 3. ROC Table: nb_sh_sample_roc +-- + +-- DISPLAY CONFUSION MATRIX +-- +-- NOTES ON COST (contd): +-- This section illustrates the effect of the cost matrix on the per-class +-- errors in the confusion matrix. First, compute the Confusion Matrix with +-- costs. Our cost matrix assumes that ratio of the cost of an error in +-- class 1 to class 0 is 65:35 (say, where 1 => BUY and 0 => NO BUY). + +column predicted format 9; +SELECT actual_target_value as actual, + predicted_target_value as predicted, + value as count + FROM nb_sh_sample_confusion_matrix +ORDER BY actual_target_value, predicted_target_value; + +-- Compute the confusion matrix without costs for later analysis +DECLARE + v_accuracy NUMBER; + v_area_under_curve NUMBER; +BEGIN + DBMS_DATA_MINING.COMPUTE_CONFUSION_MATRIX ( + accuracy => v_accuracy, + apply_result_table_name => 'nb_sh_sample_test_apply', + target_table_name => 'nb_sh_sample_test_targets', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + confusion_matrix_table_name => 'nb_sh_sample_cm_no_cost', + score_column_name => 'PREDICTION', + score_criterion_column_name => 'PROBABILITY'); + DBMS_OUTPUT.PUT_LINE('** ACCURACY W/ NO COST **: ' || ROUND(v_accuracy,4)); +END; +/ + +-- The Cost matrix is: +-- 0 0.35 +-- 0.65 0 +-- +-- Confusion matrix with Cost: +-- 868 286 +-- 56 290 +-- 868 correct predictions, and 290 misclassifications +-- Overall Cost (286 x 0.35 + 56 x 0.65 = 136.5) +-- Per class accuracy 0: 0.752166378 +-- 1: 0.838150289 +-- Accuracy: 0.772 +-- Overall Cost can be computed using this query: +-- +SELECT (SELECT (C.cost * M.value) + FROM nb_sh_sample_confusion_matrix M, + nb_sh_cost C + WHERE C.actual_target_value = '0' AND C.predicted_target_value = '1' + AND M.actual_target_value = '0' AND M.predicted_target_value = '1') + + + (SELECT (C.cost * M.value) c2 + FROM nb_sh_sample_confusion_matrix M, + nb_sh_cost C + WHERE C.actual_target_value = '1' AND C.predicted_target_value = '0' + AND M.actual_target_value = '1' AND M.predicted_target_value = '0') + cost +FROM DUAL; + +-- Confusion matrix without Cost: +-- +column predicted format 9; +SELECT actual_target_value as actual, + predicted_target_value as predicted, + value as count + FROM nb_sh_sample_cm_no_cost +ORDER BY actual_target_value, predicted_target_value; + +-- Confusion matrix with Cost: +-- 901 253 +-- 65 281 +-- 901 correct predictions, and 281 misclassifications +-- Overall Cost (253 x 0.35 + 65 x 0.65) = 130.8 +-- Per class accuracy 0: 0.780762565 +-- 1: 0.812138728 +-- Accuracy: 0.78 +-- +-- Several points are illustrated here: +-- 1. The cost matrix causes an increase in the class 1 accuracy +-- (0.83 vs 0.81) at the expense of the class 0 accuracy (0.75 vs 0.78). +-- 2. The overall accuracy is down (0.772 vs 0.78) +-- 3. The predicted probabilities are NOT accurate enough to minimize cost. +-- Note that the cost is lower for no cost matrix model (136.5 vs 130)! +-- +-- Hence, the decision model is likely to benefit from an ROC analysis. + +-- DISPLAY ROC - TOP 10 PROBABILITIES +-- +column prob format .9999 +column tp format 9999 +column fn format 9999 +column fp format 9999 +column tn format 9999 +column tpf format 9.9999 +column fpf format 9.9999 +column nb_cost format 9999.99 +SELECT * + FROM (SELECT * + FROM (SELECT ROUND(probability,4) prob, + true_positives tp, + false_negatives fn, + false_positives fp, + true_negatives tn, + ROUND(true_positive_fraction,4) tpf, + ROUND(false_positive_fraction,4) fpf, + .35 * false_positives + .65 * false_negatives nb_cost + FROM nb_sh_sample_roc) + ORDER BY nb_cost) + WHERE ROWNUM < 11; + +-- Here we see 10 different probability thresholds resulting in +-- confusion matrices with a lower overall cost (< 130) than a +-- straight-forward apply with or without a cost matrix. +-- +-- Now, let us create a cost matrix from the optimal threshold, i.e., +-- one whose action is to most closely mimic the user cost matrix. +-- Let Poptimal = Probability corresponding to the minimum cost +-- computed from the ROC table above +-- +-- Find the ratio of costs that causes breakeven expected cost at +-- at the optimal probability threshold: +-- +-- Cost(misclassify 1) = (1 - Poptimal)/Poptimal +-- Cost(misclassify 0) = 1.0 +-- +-- The following query constructs the alternative cost matrix +-- based on the above rationale. +-- +CREATE TABLE nb_alter_cost AS +WITH +cost_q AS ( +SELECT probability, + (.35 * false_positives + .65 * false_negatives) nb_cost + FROM nb_sh_sample_roc +), +min_cost AS ( +SELECT MIN(nb_cost) mincost + FROM cost_q +), +prob_q AS ( +SELECT min(probability) prob + FROM cost_q, min_cost + WHERE nb_cost = mincost +) +SELECT 1 actual_target_value, + 0 predicted_target_value, + (1.0 - prob)/prob cost + FROM prob_q +UNION ALL +SELECT 0 actual_target_value, + 1 predicted_target_value, + 1 cost + FROM dual +UNION ALL +SELECT 0 actual_target_value, + 0 predicted_target_value, + 0 cost + FROM dual +UNION ALL +SELECT 1 actual_target_value, + 1 predicted_target_value, + 0 cost + FROM dual; + +SELECT * + FROM nb_alter_cost; + +-- Now, use this new cost matrix to compute the confusion matrix +-- +DECLARE + v_accuracy NUMBER; + v_area_under_curve NUMBER; +BEGIN + DBMS_DATA_MINING.COMPUTE_CONFUSION_MATRIX ( + accuracy => v_accuracy, + apply_result_table_name => 'nb_sh_sample_test_apply', + target_table_name => 'nb_sh_sample_test_targets', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + confusion_matrix_table_name => 'nb_sh_alter_confusion_matrix', + score_column_name => 'PREDICTION', -- default + score_criterion_column_name => 'PROBABILITY', -- default + cost_matrix_table_name => 'nb_alter_cost'); + DBMS_OUTPUT.PUT_LINE('**** MODEL ACCURACY ****: ' || ROUND(v_accuracy,4)); +END; +/ + +SELECT actual_target_value as actual, + predicted_target_value as predicted, + value as count + FROM nb_sh_alter_confusion_matrix + ORDER BY actual_target_value, predicted_target_value; + +-- DISPLAY LIFT RESULTS +-- +-- See dmabdemo.sql for example on generating a .CSV file +-- for charting using Excel +-- +SELECT quantile_number qtl, + lift_cumulative lcume, + percentage_records_cumulative prcume, + targets_cumulative tcume, + target_density_cumulative tdcume +-- Other info in Lift results +-- quantile_total_count, +-- non_targets_cumulative, +-- lift_quantile, +-- target_density + FROM nb_sh_sample_lift +ORDER BY quantile_number; + +----------------------------------------------------------------------- +-- APPLY THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old scoring data preparation objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP VIEW nb_sh_sample_apply_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW nb_sh_sample_apply_cat'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +----------------------- +-- PREPARE SCORING DATA +-- +-- If the data for model creation has been prepared, then the data +-- to be scored using the model must be prepared to the same scale +-- in order to obtain meaningful results. +-- +-- 1. Missing value treatment - see dmsvcdem.sql for example of what +-- needs to be done with Test and Apply data input. +-- 2. Outlier treatment and +-- 3. Binning +-- Quantile binning handles both the outlier treatment and binning in +-- this case. Transform the test data mining_test_v, using the transformation +-- tables generated during the Build data preparation, to generate a view +-- representing prepared test data. +-- +-- If this model is applied in a different schema or instance, the +-- data preparation objects generated in the CREATE step must also +-- be made available in the target schema/instance. So you must export +-- those objects (i.e. the num and cat bin tables and views) along with +-- the model to the target user schema. +-- +BEGIN + -- Execute the first transform effected on training data + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_CAT ( + bin_table_name => 'nb_sh_sample_cat', + data_table_name => 'mining_data_apply_v', + xform_view_name => 'nb_sh_sample_apply_cat'); + + -- Provide the result to the next transform effected on training data + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_NUM ( + bin_table_name => 'nb_sh_sample_num', + data_table_name => 'nb_sh_sample_apply_cat', + xform_view_name => 'nb_sh_sample_apply_prepared'); +END; +/ + +-- Cleanup old scoring result objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nb_sh_sample_apply_result'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nb_sh_sample_apply_ranked'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +------------------ +-- APPLY THE MODEL +-- +BEGIN + DBMS_DATA_MINING.APPLY( + model_name => 'NB_SH_Clas_sample', + data_table_name => 'nb_sh_sample_apply_prepared', + case_id_column_name => 'cust_id', + result_table_name => 'nb_sh_sample_apply_result'); +END; +/ + +-- APPLY RESULT OBJECTS: nb_sh_sample_apply_result + +------------------------ +-- DISPLAY APPLY RESULTS +-- +-- 1. The results table contains a prediction set - i.e. ALL the predictions +-- for a given case id, with their corresponding probability values. +-- 2. In this example, note that APPLY results do not need to be reverse +-- transformed, as done in the case of model details. This is because +-- class values of a classification target were not (required to be) +-- binned or normalized. +-- 3. Only the first 10 rows of the table are displayed here. +-- +column probability format 9.99999 +column prediction format 9 +SELECT cust_id, prediction, probability + FROM (SELECT cust_id, prediction, ROUND(probability,4) probability + FROM nb_sh_sample_apply_result + ORDER BY cust_id, prediction, probability) + WHERE ROWNUM < 11 +ORDER BY cust_id; + +----------------------------------------------------------- +-- GENERATE RANKED APPLY RESULTS (OPTIONALLY BASED ON COST) +-- +-- ALTER APPLY RESULTS TABLE (just for demo purposes) +-- +-- The RANK_APPLY and COMPUTE() procedures do not necessarily have +-- to work on the result table generated from DBMS_DATA_MINING.APPLY +-- alone. They can work on any table with similar schema and content +-- that matches the APPLY result table. An example will be a table +-- generated from some other tool, scoring engine or a generated result. +-- +-- To demonstrate this, we will make a simply change the column names in +-- the APPLY results schema table, and supply the new table as input to +-- RANK_APPLY. The only requirement is that the new column names have to be +-- reflected in the RANK_APPLY procedure. The table containing the ranked +-- results will reflect these new column names. +-- +ALTER TABLE nb_sh_sample_apply_result RENAME COLUMN cust_id TO customer_id; +ALTER TABLE nb_sh_sample_apply_result RENAME COLUMN prediction TO score; +ALTER TABLE nb_sh_sample_apply_result RENAME COLUMN probability TO chance; + +-- RANK APPLY RESULTS (WITH COST MATRIX INPUT) +-- +BEGIN + DBMS_DATA_MINING.RANK_APPLY ( + apply_result_table_name => 'nb_sh_sample_apply_result', + case_id_column_name => 'customer_id', + score_column_name => 'score', + score_criterion_column_name => 'chance', + ranked_apply_table_name => 'nb_sh_sample_apply_ranked', + top_n => 2, + cost_matrix_table_name => 'nb_alter_cost'); +END; +/ + +-- RANK_APPLY RESULT OBJECTS: smvc_sh_sample_apply_ranked + +------------------------------- +-- DISPLAY RANKED APPLY RESULTS +-- using altered cost matrix +column chance format 9.99 +column cost format 9.99 +SELECT customer_id, score, chance, cost, rank + FROM (SELECT customer_id, score, ROUND(chance,4) chance, + ROUND(cost,4) cost, rank + FROM nb_sh_sample_apply_ranked + ORDER BY customer_id, rank) + WHERE ROWNUM < 11 +ORDER BY customer_id; diff --git a/dmnmdemo.java b/dmnmdemo.java new file mode 100644 index 0000000..71f5fd0 --- /dev/null +++ b/dmnmdemo.java @@ -0,0 +1,618 @@ +// Copyright (c) 2001, 2006, Oracle. All rights reserved. +// File: dmnmdemo.java + +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to build and apply a feature extraction model using the Non-negative Matrix +* Factorization (NMF) algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* Given demographic data about a set of customers, extract features +* from the given dataset. +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the previous affinity card +* programs. Data exploration and preparing the data is a common step before +* doing data mining. Here in this demo, the following views are created +* in the user schema using CUSTOMERS, COUNTRIES and SUPPLIMENTARY_DEMOGRAPHICS +* tables. +* +* MINING_DATA_BUILD_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for building the model. +* +* MINING_DATA_APPLY_V: +* This view collects the prospective customers' demographics and purchasing +* details for scoring against the clustering model. +* +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a feature extraction model using the NMF algorithm. +* Apply Model: +* For a descriptive mining function like feature extraction, "Scoring" +* involves providing the probability values for each feature. +* During model apply, an NMF model maps the original data into the +* new set of attributes (features) discovered by the model. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +// Generic api imports +import java.math.BigDecimal; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; +import java.text.DecimalFormat; +import java.text.MessageFormat; +import java.util.Collection; +import java.util.Iterator; +// Java Data Mining (JDM) standard imports +import java.util.Map; +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.MiningAlgorithm; +import javax.datamining.MiningFunction; +import javax.datamining.NamedObject; +import javax.datamining.base.AlgorithmSettings; +import javax.datamining.base.Model; +import javax.datamining.base.Task; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.ModelSignature; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.data.SignatureAttribute; +import javax.datamining.resource.Connection; +import javax.datamining.resource.ConnectionFactory; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; +import javax.datamining.task.apply.DataSetApplyTask; +import javax.datamining.task.apply.DataSetApplyTaskFactory; +// Oracle Java Data Mining (JDM) implemented api imports +import oracle.dmt.jdm.algorithm.nmf.OraNMFAlgorithmSettingsFactory; +import oracle.dmt.jdm.algorithm.nmf.OraNMFAlgorithmSettings; +import oracle.dmt.jdm.base.OraBuildSettings; +import oracle.dmt.jdm.featureextraction.OraFeature; +import oracle.dmt.jdm.featureextraction.OraFeatureExtractionApplySettings; +import oracle.dmt.jdm.featureextraction.OraFeatureExtractionApplySettingsFactory; +import oracle.dmt.jdm.featureextraction.OraFeatureExtractionModel; +import oracle.dmt.jdm.featureextraction.OraFeatureExtractionSettings; +import oracle.dmt.jdm.featureextraction.OraFeatureExtractionSettingsFactory; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.task.OraTransformationTask; +import oracle.dmt.jdm.task.OraTransformationTaskFactory; +import oracle.dmt.jdm.transform.normalize.OraNormalizeTransformFactory; +import oracle.dmt.jdm.transform.normalize.OraNormalizeTransformImpl; + +public class dmnmdemo extends Object{ + //Connection related data members + private static Connection m_dmeConn; + private static ConnectionFactory m_dmeConnFactory; + //Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static OraFeatureExtractionSettingsFactory m_feSettingFactory; + private static OraNMFAlgorithmSettingsFactory m_feAlgFactory; + private static BuildTaskFactory m_buildFactory; + private static DataSetApplyTaskFactory m_dsApplyFactory; + private static OraFeatureExtractionApplySettingsFactory m_applySettingsFactory; + // Global constants used for formatting output + private static String UNDERLINE = "*************************************"; + private static String TAB = " "; + private static char SPACE = ' '; + private static int SECOND_COLUMN = 40; + private static int THIRD_COLUMN = 70; + // Global constants + private static DecimalFormat m_df = new DecimalFormat("##.####"); + + public static void main( String args[] ) { + try { + if (( args.length != 0 ) & ( args.length != 3 )) { + System.out.println("Usage: java dmnmdemo "); + System.out.println(" or: java dmnmdemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + //1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@"+uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Build a model + buildModel(); + // 5. Apply the model + applyModel(); + } catch(Exception anyExp) { + anyExp.printStackTrace(System.out); + } finally { + try { + // 7. Logout from the Data Mining Engine + m_dmeConn.close(); + } catch(Exception anyExp1) { }//Ignore + } + } + + /** + * Initialize all object factories used in the demo program. + * + * @exception JDMException if factory initalization failed + */ + public static void initFactories() throws JDMException + { + m_pdsFactory = (PhysicalDataSetFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalDataSet"); + m_paFactory = (PhysicalAttributeFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalAttribute"); + m_feSettingFactory = (OraFeatureExtractionSettingsFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.featureextraction.OraFeatureExtractionSettings"); + m_feAlgFactory = (OraNMFAlgorithmSettingsFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.algorithm.nmf.OraNMFAlgorithmSettings"); + m_buildFactory = (BuildTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.BuildTask"); + m_dsApplyFactory = (DataSetApplyTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.apply.DataSetApplyTask"); + m_applySettingsFactory = (OraFeatureExtractionApplySettingsFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.featureextraction.OraFeatureExtractionApplySettings"); + } + + /** + * This method illustrates how to build a mining model using the + * "MINING_DATA_BUILD_V" dataset with the nmf algorithm. + * + * After completing the build task, a model named "nmModel_jdm" will + * be created. + * + * @exception JDMException if model build failed + */ + public static void buildModel() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Build Model ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = m_pdsFactory.create("MINING_DATA_BUILD_V", false); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + buildData.addAttribute(pa); + m_dmeConn.saveObject("nmfBuildData_jdm", buildData, true); + // 2. Create & save Mining Function Settings + // Create NMF algorithm settings + OraNMFAlgorithmSettings nmfAlgo = (OraNMFAlgorithmSettings)m_feAlgFactory.create(); + // Examples settings are: + // nmfAlgo.setMaxNumberOfIterations(10); + // nmfAlgo.setMinConvergenceTolerance(0.05); + // nmfAlgo.setSeedValue(-1); + // Create OraFeatureExtractionSettings + OraFeatureExtractionSettings buildSettings = m_feSettingFactory.create(); + buildSettings.setAlgorithmSettings(nmfAlgo); + //Set auto data preparation on + buildSettings.useAutomatedDataPreparations(true); + + m_dmeConn.saveObject("nmfBuildSettings_jdm", buildSettings, true); + //3. Create, save & execute Build Task + BuildTask buildTask = m_buildFactory.create( + "nmfBuildData_jdm", //Build data specification + "nmfBuildSettings_jdm", //Mining function settings name + "nmfModel_jdm" //Mining model name + ); + buildTask.setDescription("nmfBuildTask_jdm"); + executeTask(buildTask, "nmfBuildTask_jdm"); + //4. Restore the model from the DME and explore the details of the model + OraFeatureExtractionModel model = (OraFeatureExtractionModel) + m_dmeConn.retrieveObject("nmfModel_jdm", NamedObject.model); + // Display model build settings + OraFeatureExtractionSettings retrievedBuildSettings = + (OraFeatureExtractionSettings)model.getBuildSettings(); + if(buildSettings == null) + System.out.println("Failure to restore build settings."); + else + displayBuildSettings(retrievedBuildSettings, "nmfBuildSettings_jdm"); + // Display model signature + displayModelSignature((Model)model); + // Display model details + displayFEModelDetails(model); + } + + /** + * Apply operation is performed by a task that requires the location of + * the dataset, the model name, the output specification, and the location + * of the output. + * + * The output table "nmf_apply_output_jdm" is specified by a MiningApplyOutput + * object to contain the feature identifier and the match quality for feature + * extraction models. + * + * In this example, the NMF model is applied with the + * "NMF_LIN_NORM_DATA_APPLY_JDM" prepared dataset to obtain the feature + * identifier and the match quality. + * + * @exception JDMException if model apply failed + */ + public static void applyModel() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Apply Model ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = m_pdsFactory.create( + "MINING_DATA_APPLY_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "nmfNMFData_jdm", applyData, true ); + // 2. Create & save FeatureExtractionApplySettings + OraFeatureExtractionApplySettings feAS = m_applySettingsFactory.create(); + m_dmeConn.saveObject( "nmfApplySettings_jdm", feAS, true); + // 3. Create, store & execute apply Task + DataSetApplyTask applyTask = m_dsApplyFactory.create( + "nmfNMFData_jdm", "nmfModel_jdm", "nmfApplySettings_jdm", + "NMF_APPLY_OUTPUT_JDM"); + executeTask(applyTask, "nmfApplyTask_jdm"); + // 4. Display apply result -- the first 10 rows + displayTable("NMF_APPLY_OUTPUT_JDM", + "where ROWNUM < 11", + "order by CUST_ID"); + } + /** + * This method stores the given task with the specified name in the DMS + * and submits the task for asynchronous execution in the DMS. After + * completing the task successfully it returns true. If there is a task + * failure, then it prints the error description and returns false. + * + * @param taskObj task object + * @param taskName name of the task + * + * @return boolean returns true when the task is successful + * @exception JDMException if task execution failed + */ + public static boolean executeTask(Task taskObj, String taskName) throws JDMException + { + boolean isTaskSuccess = false; + m_dmeConn.saveObject(taskName, taskObj, true); + ExecutionHandle execHandle = m_dmeConn.execute(taskName); + System.out.print(taskName + " is started, please wait. "); + //Wait for completion of the task + ExecutionStatus status = execHandle.waitForCompletion(Integer.MAX_VALUE); + //Check the status of the task after completion + isTaskSuccess = status.getState().equals(ExecutionState.success); + if( isTaskSuccess ) { + //Task completed successfully + System.out.println(taskName + " is successful."); + } else {//Task failed + System.out.println(taskName + " is failed.\nFailure Description: " + + status.getDescription() ); + } + return isTaskSuccess; + } + + private static void displayBuildSettings( + OraFeatureExtractionSettings featureSettings, String buildSettingsName) + { + // Display build settings table + System.out.println("BuildSettings Details from the " + + buildSettingsName + " table:"); + displayTable(buildSettingsName, "", "order by SETTING_NAME"); + // Display build settings object obtained from the model + System.out.println("BuildSettings Details from the " + + buildSettingsName + " model build settings object:"); + String objName = featureSettings.getName(); + if(objName != null) + System.out.println("Name = " + objName); + String objDescription = featureSettings.getDescription(); + if(objDescription != null) + System.out.println("Description = " + objDescription); + java.util.Date creationDate = featureSettings.getCreationDate(); + String creator = featureSettings.getCreatorInfo(); + AlgorithmSettings algoSettings = featureSettings.getAlgorithmSettings(); + if(algoSettings == null) + System.out.println("Failure: featureSettings.getAlgorithmSettings() returns null"); + MiningAlgorithm algo = algoSettings.getMiningAlgorithm(); + if(algo == null) System.out.println("Failure: algoSettings.getMiningAlgorithm() returns null"); + System.out.println("Algorithm Name: " + algo.name()); + MiningFunction function = featureSettings.getMiningFunction(); + if(function == null) System.out.println("Failure: featureSettings.getMiningFunction() returns null"); + System.out.println("Function Name: " + function.name()); + // List of NMF algorithm settings + long intValue = ((OraNMFAlgorithmSettings)algoSettings).getMaxNumberOfIterations(); + System.out.println("Max Number Of Iterations: " + intValue); + double doubleValue = ((OraNMFAlgorithmSettings)algoSettings).getMinConvergenceTolerance(); + System.out.println("Min Convergence Tolerance: " + m_df.format(doubleValue)); + intValue = ((OraNMFAlgorithmSettings)algoSettings).getSeedValue(); + System.out.println("Seed Value: " + intValue); + intValue = featureSettings.getNumberOfFeatures(); + System.out.println("Number Of Features: " + intValue); + } + + /** + * This method displayes the NMF model signature. + * + * @param model model object + * @exception JDMException + */ + public static void displayModelSignature(Model model) throws JDMException + { + String modelName = model.getName(); + System.out.println("Model Name: " + modelName); + // Display the first 10 rows only + ModelSignature modelSignature = model.getSignature(); + System.out.println("Model Signature: ( Attribute Name, Attribute Type )"); + MessageFormat mfSign = new MessageFormat(" ( {0}, {1} )"); + String[] vals = new String[2]; + Collection sortedSet = modelSignature.getAttributes(); + Iterator attrIterator = sortedSet.iterator(); + while(attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute)attrIterator.next(); + vals[0] = attr.getName(); + vals[1] = attr.getDataType().name(); + System.out.println( mfSign.format(vals) ); + } + } + + private static void displayTable(String tableName, String whereCause, String orderByColumn) + { + StringBuffer emptyCol = new StringBuffer(" "); + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + PreparedStatement pStmt = null; + ResultSet rs = null; + try + { + pStmt = dbConn.prepareStatement("SELECT * FROM " + tableName + " " + whereCause + " " + orderByColumn); + rs = pStmt.executeQuery(); + ResultSetMetaData rsMeta = rs.getMetaData(); + int colCount = rsMeta.getColumnCount(); + StringBuffer header = new StringBuffer(); + System.out.println("Table : " + tableName); + // Build table header + for(int iCol=1; iCol<=colCount; iCol++) + { + String colName = rsMeta.getColumnName(iCol); + header.append(emptyCol.replace(0, colName.length(), colName)); + emptyCol = new StringBuffer(" "); + } + System.out.println(header.toString()); + // Write table data + while(rs.next()) + { + StringBuffer rowContent = new StringBuffer(); + for(int iCol=1; iCol<=colCount; iCol++) + { + int sqlType = rsMeta.getColumnType(iCol); + Object obj = rs.getObject(iCol); + String colContent = null; + + if(obj instanceof java.lang.Number) + { + try + { + BigDecimal bd = (BigDecimal)obj; + if(bd.scale() > 5) + { + colContent = m_df.format(obj); + } else + { + colContent = bd.toString(); + } + } catch(Exception anyExp) { + colContent = m_df.format(obj); + } + } else + { + if(obj == null) + colContent = "NULL"; + else + colContent = obj.toString(); + } + rowContent.append(" "+emptyCol.replace(0, colContent.length(), colContent)); + emptyCol = new StringBuffer(" "); + } + System.out.println(rowContent.toString()); + } + } catch(Exception anySqlExp) { + anySqlExp.printStackTrace(); + } // Ignore + } + + /** + * Each feature is a linear combination of the original attribute set; + * the coefficients of these linear combinations are non-negative. + * The model details return for each feature the coefficients + * associated with each one of the original attributes. Categorical + * attributes are described by (attribute_name, attribute_value) pairs. + * That is, for a given feature, each distinct value of a categorical + * attribute has its own coefficient. + * + * @param model model to be presented + * @exception JDMException if failed to retrieve model details + */ + public static void displayFEModelDetails(OraFeatureExtractionModel model) + throws JDMException + { + System.out.println(UNDERLINE+"\n"+"NMF model details"+"\n"+UNDERLINE+"\n"); + System.out.println("\n"+TAB+"Listing all features:\n"+UNDERLINE); + Collection features = model.getFeatures(); + if ( features == null ){ + System.out.println(TAB+TAB+"Error printing features."); + return; + } + + OraFeature sampleFeature = null; + Iterator it = features.iterator(); + while ( it.hasNext() ){ + OraFeature feature = (OraFeature)it.next(); + printFeature(feature); + if ( sampleFeature == null ) + sampleFeature = feature; + } + + System.out.println("\n"+TAB+"Listing Top 3 features:\n"+UNDERLINE); + Collection topNfeatures = model.getFeatures(3); + if ( topNfeatures == null ){ + System.out.println(TAB+TAB+"Error printing Top N features."); + return; + } + + Iterator itTopN = topNfeatures.iterator(); + while ( itTopN.hasNext() ){ + OraFeature feature = (OraFeature)itTopN.next(); + printFeature(feature); + } + + if ( sampleFeature != null ){ + System.out.println(TAB+"Listing all attribute names for the feature:" + sampleFeature.getFeatureIdentifier()); + System.out.println(TAB+"____________________________________________"); + String[] attrNames = sampleFeature.getAttributeNames(); + for ( int ni = 0 ; ni < attrNames.length ; ni++ ) { + Map attrValCoefficientMap = sampleFeature.getAttributeCoefficients(attrNames[ni]); + System.out.println("\n"+TAB+TAB+"Attribute Name:" + attrNames[ni] ); + printCoefficients(attrNames[ni], attrValCoefficientMap, false); + } + } + } + + /** + * Display a single feature + * + * @param feature specific feature to be displayed + * @exception JDMException if failed to retrieve the feature details + */ + public static void printFeature(OraFeature feature) throws JDMException + { + if ( feature == null ){ + System.out.println("Error: feature is null"); + return; + } + + System.out.println("\n" + TAB+TAB+"Feature : " + feature.getFeatureIdentifier() ); + String[] featureAttrNames = feature.getAttributeNames(); + //Print attributes coefficient details for each attribute + if(featureAttrNames != null) { + for(int iAttr=0; iAttr < featureAttrNames.length; iAttr++) + { + Map attrValCoefficientMap = feature.getAttributeCoefficients(featureAttrNames[iAttr]); + printCoefficients(featureAttrNames[iAttr], attrValCoefficientMap, true); + } + } + + } + + private static void printCoefficients (String attrName, Map attrValCoefficientMap, boolean printAttrName) + throws JDMException + { + if ( attrValCoefficientMap == null ){ + System.out.println("Error printing coefficients for this feature."); + return; + } + + if ( printAttrName == true ) + print3Columns(new String[]{"Attribute","Value","Coefficient"} ); + else + print3Columns(new String[]{"","Value","Coefficient"} ); + + System.out.println(TAB+TAB+TAB +"____________________________________________________________________________" ); + Object[] attrVals = attrValCoefficientMap.keySet().toArray(); + if(attrVals != null) { + for(int iAttr=0; iAttr < attrVals.length; iAttr++) + { + print3Columns ( new String[]{ + ( printAttrName == true ? attrName : "" ) , + (( attrVals[iAttr] == null ? "" : attrVals[iAttr] )).toString(), + String.valueOf(m_df.format((Number)attrValCoefficientMap.get(attrVals[iAttr]))) + } + ); + } + } + + } + + + private static void print3Columns(String[] names){ + if ( names == null || names.length != 3 ) + return; + + StringBuffer sbOut = new StringBuffer(TAB+TAB+TAB); + sbOut.append(names[0]); + + int padLength = Math.max ( SECOND_COLUMN - sbOut.length(), 0 ); + for ( int ni = 0 ; ni < padLength; ni++) + sbOut.append(SPACE); + + sbOut.append(names[1]); + padLength = Math.max ( THIRD_COLUMN - sbOut.length(), 0 ); + for ( int ni = 0 ; ni < padLength; ni++) + sbOut.append(SPACE); + + sbOut.append(names[2]); + System.out.println(sbOut.toString()); + } + + private static void clean() + { + try { + m_dmeConn.removeObject("nmfModel_jdm", NamedObject.model); + } catch(JDMException jdmExp) {} + //Drop apply output table + java.sql.Connection dbConn = + ((OraConnection) m_dmeConn).getDatabaseConnection(); + Statement stmt = null; + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP VIEW NMF_LIN_NORM_DATA_BUILD_JDM"); + } catch(SQLException anySqlExp) {}//Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP VIEW NMF_LIN_NORM_DATA_APPLY_JDM"); + } catch(SQLException anySqlExp) {}//Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP TABLE NMF_APPLY_OUTPUT_JDM"); + } catch(SQLException anySqlExp) {}//Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + } +} \ No newline at end of file diff --git a/dmnmdemo.sql b/dmnmdemo.sql new file mode 100644 index 0000000..f26b511 --- /dev/null +++ b/dmnmdemo.sql @@ -0,0 +1,329 @@ +Rem +Rem $Header: dmnmdemo.sql 17-jan-2008.13:35:55 jiawang Exp $ +Rem +Rem dmnmdemo.sql +Rem +Rem Copyright (c) 2003, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmnmdemo.sql - Sample program for the DBMS_DATA_MINING package. +Rem +Rem DESCRIPTION +Rem This script creates a feature extraction model +Rem using the NMF algorithm +Rem and data in the SH (Sales History) schema in the RDBMS. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ramkrish 06/14/07 - remove commit after settings +Rem jiawang 01/17/08 - Correct comments +Rem ramkrish 10/25/07 - replace deprecated get_model calls with catalog +Rem queries +Rem jiawang 03/06/07 - Add order by to fix bug5381396 +Rem xbarr 02/22/07 - add force drop for type objects +Rem amozes 05/09/06 - repeatable ordering +Rem ktaylor 07/11/05 - Minor edits to comments +Rem ramkrish 02/01/05 - remove rownum clause in model signature +Rem jcjeon 01/18/05 - add column format +Rem ramkrish 10/27/04 - add data analysis and comments/cleanup +Rem jiawang 07/22/04 - Add order by to fix sorting dif +Rem xbarr 06/25/04 - xbarr_dm_rdbms_migration +Rem ramkrish 10/20/03 - ramkrish_txn109085 +Rem pstengar 10/17/03 - added denormalization of model details +Rem cbhagwat 10/17/03 - feature_extraction +Rem ramkrish 10/02/03 - Creation + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET linesize 100 +SET echo ON + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM +----------------------------------------------------------------------- +-- Given demographic data about a set of customers, extract features +-- from the given dataset. +-- + +----------------------------------------------------------------------- +-- SET UP AND ANALYZE THE DATA +----------------------------------------------------------------------- + +-- See the corresponding section in dmsvcdem.sql +-- + +----------------------------------------------------------------------- +-- BUILD THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old build data preparation objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nmf_sh_sample_norm'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW nmf_sh_sample_build_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +-- Cleanup old model with same name for repeat runs +BEGIN DBMS_DATA_MINING.DROP_MODEL('NMF_SH_sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-------------------------------- +-- PREPARE BUILD (TRAINING) DATA +-- +-- This step is required only if the data is not prepared/transformed +-- to enable creation of an efficient model using the NMF algorithm. +-- In this case, the data for attribute 'age' requires preparation. +-- +BEGIN + -- Normalize numerical attributes: age + DBMS_DATA_MINING_TRANSFORM.CREATE_NORM_LIN( + norm_table_name => 'nmf_sh_sample_norm'); + + DBMS_DATA_MINING_TRANSFORM.INSERT_NORM_LIN_MINMAX ( + norm_table_name => 'nmf_sh_sample_norm', + data_table_name => 'mining_data_build_v', + exclude_list => dbms_data_mining_transform.column_list ( + 'yrs_residence', + 'affinity_card', + 'bulk_pack_diskettes', + 'flat_panel_monitor', + 'home_theater_package', + 'bookkeeping_application', + 'printer_supplies', + 'y_box_games', + 'os_doc_set_kanji', + 'cust_id') + ); + + -- Create the transformed view + DBMS_DATA_MINING_TRANSFORM.XFORM_NORM_LIN ( + norm_table_name => 'nmf_sh_sample_norm', + data_table_name => 'mining_data_build_v', + xform_view_name => 'nmf_sh_sample_build_prepared'); +END; +/ + +-- BUILD DATA PREPARATION OBJECTS: +-- ------------------------------ +-- 1. Missing Value Treatment for all predictors +-- skipped. See dmsvcdem.sql for an example. +-- 2. Normalization Table: nmf_sh_sample_norm +-- 3. Input (view) to CREATE_MODEL: nmf_sh_sample_build_prepared + +------------------- +-- SPECIFY SETTINGS +-- +-- Cleanup old settings table objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nmf_sh_sample_settings'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- CREATE A SETTINGS TABLE +-- +-- NMF is the default Feature Extraction algorithm. For this sample, +-- we skip specification of any overrides to defaults +-- +-- Uncomment the appropriate sections of the code below if you +-- want to override any defaults. +-- +set echo off +-- CREATE TABLE nmf_sh_sample_settings ( +-- setting_name VARCHAR2(30), +-- setting_value VARCHAR2(30)); +set echo on + +-- BEGIN + -- Populate settings table + -- INSERT INTO nmf_sh_sample_settings (setting_name, setting_value) VALUES + -- Examples of possible overrides are: + -- (dbms_data_mining.feat_num_features, 10); + -- (dbms_data_mining.nmfs_conv_tolerance,0.05); + -- (dbms_data_mining.nmfs_num_iterations,50); + -- (dbms_data_mining.nmfs_random_seed,-1); +-- END; +-- / + +--------------------- +-- CREATE A NEW MODEL +-- +-- Build NMF model +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'NMF_SH_sample', + mining_function => dbms_data_mining.feature_extraction, + data_table_name => 'nmf_sh_sample_build_prepared', + case_id_column_name => 'cust_id'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30 +column setting_value format a30 +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'NMF_SH_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +column attribute_name format a40 +column attribute_type format a20 +SELECT attribute_name, attribute_type + FROM user_mining_model_attributes + WHERE model_name = 'NMF_SH_SAMPLE' +ORDER BY attribute_name; + +------------------------ +-- DISPLAY MODEL DETAILS +-- +-- Each feature is a linear combination of the original attribute set; +-- the coefficients of these linear combinations are non-negative. +-- The model details return for each feature the coefficients +-- associated with each one of the original attributes. Categorical +-- attributes are described by (attribute_name, attribute_value) pairs. +-- That is, for a given feature, each distinct value of a categorical +-- attribute has its own coefficient. +-- +column attribute_name format a40; +column attribute_value format a20; +SELECT * FROM ( +SELECT F.feature_id, + A.attribute_name, + A.attribute_value, + A.coefficient + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_NMF('NMF_SH_Sample')) F, + TABLE(F.attribute_set) A +ORDER BY feature_id,attribute_name,attribute_value +) WHERE ROWNUM < 11; + +----------------------------------------------------------------------- +-- TEST THE MODEL +----------------------------------------------------------------------- +-- There is no specific set of testing parameters for feature extraction. +-- Examination and analysis of features is the main method to prove +-- the efficacy of an NMF model. +-- + +----------------------------------------------------------------------- +-- APPLY THE MODEL +----------------------------------------------------------------------- +-- +-- For a descriptive mining function like feature extraction, "Scoring" +-- involves providing the probability values for each feature. +-- During model apply, an NMF model maps the original data into the +-- new set of attributes (features) discovered by the model. +-- +-- Cleanup scoring data preparation objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP VIEW nmf_sh_sample_apply_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TYPE Featattrs FORCE'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TYPE Featattr FORCE'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +----------------------- +-- PREPARE SCORING DATA +-- +-- 1. Missing Value Treatment for all predictors +-- skipped. See dmsvcdem.sql for an example. +-- +-- 2. Outlier Treatment +-- Skipped. See dmsvcdem.sql for an example. +-- +-- 3. Normalization +-- +BEGIN + DBMS_DATA_MINING_TRANSFORM.XFORM_NORM_LIN ( + norm_table_name => 'nmf_sh_sample_norm', + data_table_name => 'mining_data_apply_v', + xform_view_name => 'nmf_sh_sample_apply_prepared'); +END; +/ + +------------------------------------------------- +-- SCORE NEW DATA USING SQL DATA MINING FUNCTIONS +-- +------------------ +-- BUSINESS CASE 1 +-- List the features that correspond to customers in this dataset. +-- +SELECT FEATURE_ID(nmf_sh_sample USING *) AS feat, COUNT(*) AS cnt + FROM nmf_sh_sample_apply_prepared +GROUP BY FEATURE_ID(nmf_sh_sample USING *) +ORDER BY cnt DESC,FEAT DESC; + +------------------ +-- BUSINESS CASE 2 +-- List customers that correspond to feature 3 ordered by match quality +-- +SELECT * + FROM (SELECT cust_id, FEATURE_VALUE(nmf_sh_sample, 3 USING *) match_quality + FROM nmf_sh_sample_apply_prepared + ORDER BY match_quality DESC) + WHERE ROWNUM < 11; + +column value format 99.9999 +column fid format 999 +column attr format a25 +column val format a20 +column coeff format 9.9999 + +------------------ +-- BUSINESS CASE 3 +-- List top 10 features corresponding to a given customer +-- record (based on match_quality), and find out the top +-- attributes for each feature (based on coefficient > 0.25) +-- +set echo off +CREATE TYPE Featattr AS OBJECT ( + attr VARCHAR2(30), + val VARCHAR2(30), + coeff NUMBER) +/ +set echo on +CREATE TYPE Featattrs AS TABLE OF Featattr +/ + +column val format a50 +WITH +feat_tab AS ( +SELECT F.feature_id fid, + A.attribute_name attr, + TO_CHAR(A.attribute_value) val, + A.coefficient coeff + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_NMF('nmf_sh_sample')) F, + TABLE(F.attribute_set) A + WHERE A.coefficient > 0.25 +), +feat AS ( +SELECT fid, + CAST(COLLECT(Featattr(attr, val, coeff)) + AS Featattrs) f_attrs + FROM feat_tab +GROUP BY fid +), +cust_10_features AS ( +SELECT T.cust_id, S.feature_id, S.value + FROM (SELECT cust_id, FEATURE_SET(nmf_sh_sample, 10 USING *) pset + FROM nmf_sh_sample_apply_prepared + WHERE cust_id = 100002) T, + TABLE(T.pset) S +) +SELECT A.value, A.feature_id fid, + B.attr, B.val, B.coeff + FROM cust_10_features A, + (SELECT T.fid, F.* + FROM feat T, + TABLE(T.f_attrs) F) B + WHERE A.feature_id = B.fid +ORDER BY A.value DESC, A.feature_id ASC, coeff DESC, attr ASC, val ASC; diff --git a/dmocdemo.java b/dmocdemo.java new file mode 100644 index 0000000..aac40ca --- /dev/null +++ b/dmocdemo.java @@ -0,0 +1,899 @@ +// Copyright (c) 2001, 2006, Oracle. All rights reserved. +// File: dmocdemo.java + +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to cluster data records based on Orthogonal Clustering. +* The o-Cluster (OC) clustering model provides the user with insight about the +* discovered groups. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* Segment the demographic data into 10 clusters and study the individual +* clusters. Apply clustering model to new data and rank the clusters on probability. +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the previous affinity card +* programs. Data exploration and preparing the data is a common step before +* doing data mining. Here in this demo, the following views are created +* in the user schema using CUSTOMERS, COUNTRIES and SUPPLIMENTARY_DEMOGRAPHICS +* tables. +* +* MINING_DATA_BUILD_STR_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for building the model. +* +* MINING_DATA_APPLY_STR_V: +* This view collects the prospective customers' demographics and purchasing +* details for scoring against the clustering model. +* +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Prepare Data: +* OC is not a distance based algorithm like K-Means, and instead works on +* histograms. Therefore binning is the preferred transformation for high +* cardinality data. OC uses a special binning procedure that automatically +* determines the number of bins based on data statistics. The +* prepareData() method illustrates the binning of the build and apply +* data. +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a clustering model using the OC algorithm. +* Apply Model: +* The results of an APPLY operation will contain a list of the cluster +* identifiers for each case, and the associated probabilities. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +// Generic api imports +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Collection; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.Set; +import java.util.TreeMap; +import java.util.Hashtable; +// Java Data Mining (JDM) standard imports +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.NamedObject; +import javax.datamining.base.Task; +import javax.datamining.clustering.Cluster; +import javax.datamining.clustering.ClusteringApplySettings; +import javax.datamining.clustering.ClusteringApplySettingsFactory; +import javax.datamining.clustering.ClusteringModel; +import javax.datamining.clustering.ClusteringSettings; +import javax.datamining.clustering.ClusteringSettingsFactory; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.AttributeType; +import javax.datamining.data.Interval; +import javax.datamining.data.IntervalClosure; +import javax.datamining.data.ModelSignature; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.data.SignatureAttribute; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.rule.CompoundPredicate; +import javax.datamining.rule.Predicate; +import javax.datamining.rule.Rule; +import javax.datamining.rule.SimplePredicate; +import javax.datamining.statistics.AttributeStatisticsSet; +import javax.datamining.statistics.UnivariateStatistics; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; +import javax.datamining.task.apply.DataSetApplyTask; +import javax.datamining.task.apply.DataSetApplyTaskFactory; +// Oracle Java Data Mining (JDM) implemented api imports +import oracle.dmt.jdm.OraPLSQLMappings; +import oracle.dmt.jdm.algorithm.ocluster.OraOClusterSettings; +import oracle.dmt.jdm.algorithm.ocluster.OraOClusterSettingsFactory; +import oracle.dmt.jdm.clustering.OraCluster; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.rule.OraSimplePredicate; +import oracle.dmt.jdm.task.OraTransformationTask; +import oracle.dmt.jdm.task.OraTransformationTaskFactory; +import oracle.dmt.jdm.transform.binning.OraBinningTransformFactory; +import oracle.dmt.jdm.transform.binning.OraBinningTransformImpl; +import oracle.dmt.jdm.transform.binning.OraCategoricalBinningType; +import oracle.dmt.jdm.transform.binning.OraNumericalBinningType; + +public class dmocdemo extends Object{ + //Connection related data members + private static javax.datamining.resource.Connection m_dmeConn; + private static javax.datamining.resource.ConnectionFactory m_dmeConnFactory; + //Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static ClusteringSettingsFactory m_clusFactory; + private static OraOClusterSettingsFactory m_oclusterFactory; + private static BuildTaskFactory m_buildFactory; + private static DataSetApplyTaskFactory m_dsApplyFactory; + private static ClusteringApplySettingsFactory m_applySettingsFactory; + private static OraBinningTransformFactory m_binningXformFactory; + private static OraTransformationTaskFactory m_xformTaskFactory; + // Global constants used for formatting output + private static String TAB = " "; + private static String CR = "\n"; + private static String CR_TAB = "\n "; + private static String HORZ_LINE = "----"; + private static String UNDERLINE = "*************************************"; + private static String LEAF_CLUSTERS_HEADER = "* Leaf clusters *"; + private static String RULES_CLUSTERS_HEADER = "* Rules *"; + private static String RULES_CLUSTERS_HIERARCHY_HEADER = "* Printing clusters hierarchy *"; + + public static void main( String args[] ) { + try { + if (( args.length != 0 ) & ( args.length != 3 )) { + System.out.println("Usage: java dmocdemo "); + System.out.println(" or: java dmocdemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + //1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@"+uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Prepare data + prepareData(); + // 5. Build a model + buildModel(); + // 6. Apply the model + applyModel(); + } catch(Exception anyExp) { + anyExp.printStackTrace(System.out); + } finally { + try { + // 7. Logout from the Data Mining Engine + m_dmeConn.close(); + } catch(Exception anyExp1) { }//Ignore + } + } + + /** + * Initialize all object factories used in the demo program. + * + * @exception JDMException if factory initalization failed + */ + public static void initFactories() throws JDMException + { + m_pdsFactory = (PhysicalDataSetFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalDataSet"); + m_paFactory = (PhysicalAttributeFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalAttribute"); + m_clusFactory = (ClusteringSettingsFactory)m_dmeConn.getFactory( + "javax.datamining.clustering.ClusteringSettings"); + m_oclusterFactory = (OraOClusterSettingsFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.algorithm.ocluster.OraOClusterSettings"); + m_buildFactory = (BuildTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.BuildTask"); + m_dsApplyFactory = (DataSetApplyTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.apply.DataSetApplyTask"); + m_applySettingsFactory = (ClusteringApplySettingsFactory)m_dmeConn.getFactory( + "javax.datamining.clustering.ClusteringApplySettings"); + m_binningXformFactory = (OraBinningTransformFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.transform.binning.OraBinningTransform"); + m_xformTaskFactory = (OraTransformationTaskFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.task.OraTransformationTask"); + } + + /** + * This method illustrates preparation of the data for build and apply + * operations by using binning transformation. + * + * Here all numerical attributes except CUST_ID are prepared using + * auto equal width binning. Categorical attributes are not binned. + * For more details about the binning please refer to + * Oracle Data Mining Concepts Guide. + * + * The case id and any attribute with <= 2 distinct values should be excluded + * from the binning process. + * + * The following table illustrates customer attributes available for building + * the mining model and data characteristics and type of binning used + * for each attribute and number of bins used. + * + * COLUMN_NAME DATA_TYPE DISTINCT EXCLUDED BIN TYPE BIN # + * ------------------ --------- -------- -------- ----------- ----- + * CUST_ID NUMBER 1500 YES + * AGE NUMBER 66 NO AUTOEQWIDTH 10 + * YRS_RESIDENCE NUMBER 15 NO AUTOEQWIDTH 10 + * + * Build data binnning transformation produces numerical and categorical + * bin boundary tables. These tables must be specified for apply data + * to bin the data consistent with the build data. + * Following binned tables are created after the execution of this method. + * + * Unprepared Data ---> Prepared(Binned) Data + * --------------------- --------------------------- + * MINING_DATA_BUILD_STR_V OC_BINNED_DATA_BUILD_JDM + * MINING_DATA_APPLY_STR_V OC_BINNED_DATA_APPLY_JDM + */ + public static void prepareData() throws JDMException + { + boolean isOutputAsView = false; + String inputDataURI = null; + String outputDataURI = null; + String categoricalBinTable = null; + String numericalBinTable = null; + OraTransformationTask xformTask = null; + + // Prepare build data + isOutputAsView = true; + inputDataURI = "MINING_DATA_BUILD_STR_V"; + outputDataURI = "OC_BINNED_DATA_BUILD_JDM"; + // Create boundaries for all numeric attributes + OraBinningTransformImpl buildDataXform = + (OraBinningTransformImpl)m_binningXformFactory.create( + inputDataURI, outputDataURI, isOutputAsView ); + buildDataXform.setLiteralFlag(true); + String[] excludeColumnList = {"CUST_ID"}; + buildDataXform.setExcludeColumnList(excludeColumnList); + buildDataXform.setNumberOfBinsForNumerical(10); + buildDataXform.setNumericalBinningType(OraNumericalBinningType.auto_equi_width); + buildDataXform.setCategoricalBinningType(OraCategoricalBinningType.systemDefault); + xformTask = m_xformTaskFactory.create(buildDataXform); + executeTask(xformTask, "ocPrepareBuildTask_jdm"); + + // Prepare apply data + isOutputAsView = true; + inputDataURI = "MINING_DATA_APPLY_STR_V"; + outputDataURI = "OC_BINNED_DATA_APPLY_JDM"; + categoricalBinTable = buildDataXform.getCategoricalBinTable(); + numericalBinTable = buildDataXform.getNumericalBinTable(); + OraBinningTransformImpl applyDataXform = + (OraBinningTransformImpl)m_binningXformFactory.create( + inputDataURI, outputDataURI, isOutputAsView, + categoricalBinTable, numericalBinTable); + applyDataXform.setLiteralFlag(true); + xformTask = m_xformTaskFactory.create(applyDataXform); + executeTask(xformTask, "ocPrepareApplyTask_jdm"); + } + + /** + * This method illustrates how to build a mining model using the + * "OC_BINNED_DATA_BUILD_JDM" dataset with the OC algorithm. + * + * After completing the build task, the model named "ocModel_jdm" will + * be created. + * + * @exception JDMException if model build failed + */ + public static void buildModel() throws JDMException + { + //1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = m_pdsFactory.create("OC_BINNED_DATA_BUILD_JDM", false); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + buildData.addAttribute(pa); + m_dmeConn.saveObject("ocBuildData_jdm", buildData, true); + //2. Create & save Mining Function Settings + //Create oClusetr algorithm settings + OraOClusterSettings ocAlgo = (OraOClusterSettings)m_oclusterFactory.create(); + ocAlgo.setBufferSize(30000); + //ocAlgo.setSensitivity(0.5); + + //Create ClusteringSettings + ClusteringSettings buildSettings = m_clusFactory.create(); + buildSettings.setAlgorithmSettings(ocAlgo); + buildSettings.setMaxNumberOfClusters(10); + m_dmeConn.saveObject("ocBuildSettings_jdm", buildSettings, true); + //3. Create, save & execute Build Task + BuildTask buildTask = m_buildFactory.create( + "ocBuildData_jdm", //Build data specification + "ocBuildSettings_jdm", //Mining function settings name + "ocModel_jdm" //Mining model name + ); + buildTask.setDescription("ocBuildTask_jdm"); + executeTask(buildTask, "ocBuildTask_jdm"); + //4. Restore the model from the DME and explore the details of the model + ClusteringModel model = (ClusteringModel) + m_dmeConn.retrieveObject("ocModel_jdm", NamedObject.model); + displayOCModelDetails(model); + } + + /** + * For a descriptive mining function like Clustering, "Scoring" involves + * assigning the probability with which a given case belongs to a given + * cluster. + * + * After completing the apply task, an apply output table + * "oc_apply_output_jdm" will be created at the user specfied location. + * + * @exception JDMException if model apply failed + */ + public static void applyModel() throws JDMException + { + //1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = m_pdsFactory.create( + "OC_BINNED_DATA_APPLY_JDM", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "ocApplyData_jdm", applyData, true ); + //2. Create & save ClassificationApplySettings + ClusteringApplySettings clusAS = m_applySettingsFactory.create(); + m_dmeConn.saveObject( "ocApplySettings_jdm", clusAS, true); + + //3. Create, store & execute apply Task + DataSetApplyTask applyTask = m_dsApplyFactory.create( + "ocApplyData_jdm", + "ocModel_jdm", + "ocApplySettings_jdm", "oc_apply_output_jdm"); + executeTask(applyTask, "ocApplyTask_jdm"); + //4. Display results + displayScoringResults(); + } + + /** + * Shows scoring results. Lists the clusters into which the customers in this + * dataset have been grouped. + */ + public static void displayScoringResults() + { + String sqlResults = + "SELECT clus, COUNT(*) AS CNT FROM " + + " (SELECT cluster_id CLUS, " + + " ROW_NUMBER() OVER " + + " (PARTITION BY CUST_ID ORDER BY PROBABILITY DESC) CLUS_RNK " + + " FROM oc_apply_output_jdm) " + + "WHERE CLUS_RNK = 1 " + + "GROUP BY CLUS ORDER BY CNT DESC"; + + + Statement stmt = null; + ResultSet rs = null; + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + try { + stmt = dbConn.createStatement(); + rs = stmt.executeQuery(sqlResults); + System.out.println("Cluster ID Count"); + System.out.println("----------------------------"); + while ( rs.next() ) { + int clus = rs.getInt(1); + int cnt = rs.getInt(2); + System.out.println(TAB + clus + TAB + TAB + cnt); + } + } catch(SQLException anySqlExp) { + System.out.println(anySqlExp); + } + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + } + + /** + * This method stores the given task with the specified name in the DMS + * and submits the task for asynchronous execution in the DMS. After + * completing the task successfully it returns true. If there is a task + * failure, then it prints error description and returns false. + * + * @param taskObj task object + * @param taskName name of the task + * + * @return boolean returns true when the task is successful + * @exception JDMException if task execution failed + */ + public static boolean executeTask(Task taskObj, String taskName) + throws JDMException { + boolean isTaskSuccess = false; + m_dmeConn.saveObject(taskName, taskObj, true); + ExecutionHandle execHandle = m_dmeConn.execute(taskName); + System.out.print(taskName + " is started, please wait. "); + //Wait for completion of the task + ExecutionStatus status = execHandle.waitForCompletion(Integer.MAX_VALUE); + //Check the status of the task after completion + isTaskSuccess = status.getState().equals(ExecutionState.success); + if( isTaskSuccess ) { + //Task completed successfully + System.out.println(taskName + " is successful."); + } else {//Task failed + System.out.println(taskName + " is failed.\nFailure Description: " + + status.getDescription() ); + } + return isTaskSuccess; + } + + private static void clean() + { + //Drop prepared views + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + Statement stmt = null; + //Drop the model + try { + m_dmeConn.removeObject("ocModel_jdm", NamedObject.model); + } catch(JDMException jdmExp) {} + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP VIEW OC_BINNED_DATA_BUILD_JDM"); + } catch(SQLException anySqlExp) {}//Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP VIEW OC_BINNED_DATA_APPLY_JDM"); + } catch(SQLException anySqlExp) {}//Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + //Drop apply output table + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP TABLE OC_APPLY_OUTPUT"); + } catch(SQLException anySqlExp) {}//Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + } + + /** + * This method displayes OC model details. + * + * @param model to be presented + * + * @exception JDMException if failed to retrieve model details + */ + public static void displayOCModelDetails(ClusteringModel model) throws JDMException{ + String modelName = model.getName(); + System.out.println("Model Name: " + modelName); + System.out.println("Clustering model details:"); + System.out.println(TAB+"Number of clusters: "+ model.getNumberOfClusters()); + System.out.println(TAB+"Number of tree levels: "+ model.getNumberOfLevels()); + Collection clusters = model.getClusters(); + if ( clusters == null || clusters.isEmpty() == true ){ + System.out.println("Unable to retrieve clusters."); + return; + } + + // Display root cluster(s) + Collection vRootClusters = model.getRootClusters(); + Cluster[] rootCluster = null; + if ( vRootClusters != null && vRootClusters.isEmpty() == false ){ + rootCluster =(Cluster[])vRootClusters.toArray(new Cluster[vRootClusters.size()]); + if ( rootCluster != null ){ + System.out.println(TAB+"Root Cluster Id: " + rootCluster[0].getClusterId()); + } + } + + // Display leaf clusters + Collection vLeafClusters = model.getLeafClusters(); + if ( vLeafClusters != null && vLeafClusters.isEmpty() == false ){ + Cluster[] leafClusters =(Cluster[])vLeafClusters.toArray(new Cluster[vLeafClusters.size()]); + System.out.println(UNDERLINE); + System.out.println(LEAF_CLUSTERS_HEADER); + System.out.println(UNDERLINE); + for ( int ni = 0; ni < leafClusters.length ; ni++ ) { + printSingleClusterDetails(leafClusters[ni]); + if ( ni == 0 ){ + // display first leaf cluster statistics + printClusterStatistics(model, leafClusters[ni], 1); + } + } + } + + // Display all model rules + Collection vRules = model.getRules(); + if ( vRules != null && vRules.isEmpty() == false ){ + Rule[] rules =(Rule[])vRules.toArray(new Rule[vRules.size()]); + System.out.println(CR+CR+UNDERLINE); + System.out.println(RULES_CLUSTERS_HEADER); + System.out.println(UNDERLINE); + for ( int rl = 0; rl < rules.length ; rl++ ) { + printRuleNoDetails(rules[rl], 0); + } + } + + if ( rootCluster != null ){ + // print hierarchy + System.out.println(CR+CR+UNDERLINE); + System.out.println(RULES_CLUSTERS_HIERARCHY_HEADER); + System.out.println(UNDERLINE); + // 1.print root + printRootClusterDetails(rootCluster[0]); + // 1.print children + Cluster[] children = rootCluster[0].getChildren(); + int indent = 0; + if ( children != null ){ + for (int k=0 ; kSimplePredicate information. + * + * @param predicate SimplePredicate being presented + * + * @exception JDMException if failed to retrieve SimplePredicate details + */ + public static StringBuffer printSimplePredicate(SimplePredicate predicate) throws JDMException{ + StringBuffer sb = new StringBuffer(); + if(predicate == null){ + sb.append(" "); + return sb; + } + if ( predicate.isNumericalValue() ){ + sb.append( + predicate.getAttributeName() + " " + + //((OraSimplePredicate)predicate).getComparisonOperatorValue() + " " + + OraPLSQLMappings.getComparisonOperatorValue_tree(((OraSimplePredicate)predicate).getComparisonOperator()) + " " + + predicate.getNumericalValue() + ); + } + else{ + sb = new StringBuffer( + predicate.getAttributeName() + " " + + //((OraSimplePredicate)predicate).getComparisonOperatorValue() + " " + OraPLSQLMappings.getComparisonOperatorValue_tree(((OraSimplePredicate)predicate).getComparisonOperator()) + " " + ); + Object[] inValues = predicate.getCategoryValues(); + if ( inValues != null ){ + for (int i=0 ; i < inValues.length; i++ ) { + sb.append(inValues[i] ); + if ( i != inValues.length - 1) + sb.append(","); + } + } + } + return sb; + } + + /** + * This method shows details of the root cluster. + * + * @param cluster root cluster + * + * @exception JDMException if failed to retrieve root cluster details + */ + public static void printRootClusterDetails(Cluster cluster) throws JDMException{ + CompoundPredicate cp = (CompoundPredicate)cluster.getSplitPredicate(); + Predicate[] predicates = cp.getPredicates(); + for ( int ni = 0; ni < predicates.length; ni++) { + StringBuffer sb = printSimplePredicate((SimplePredicate)predicates[ni]); + System.out.println(CR+"Root Cluster Id: " + cluster.getClusterId() + + CR_TAB + "Case Count: " + cluster.getCaseCount() + + CR_TAB + "Tree Level: " + cluster.getLevel() + + CR_TAB + "Dispersion: " + ((OraCluster)cluster).getDispersion() + + CR_TAB + "Split predicate: " + sb.toString() + + CR_TAB + "Children:" + ); + } + } + + /** + * This method shows details of any cluster. + * + * @param cluster cluster being presented + * + * @exception JDMException if failed to retrieve this cluster details + */ + public static void printSingleClusterDetails(Cluster cluster) throws JDMException{ + System.out.println(CR+"Cluster Id: " + cluster.getClusterId() + + CR_TAB+"Case Count: " + cluster.getCaseCount() + + CR_TAB+"Tree Level: " + cluster.getLevel() + + CR_TAB+"Dispersion: " + ((OraCluster)cluster).getDispersion() + + CR_TAB+"Parent's id: " + ( cluster.getParent() != null ? + String.valueOf(cluster.getParent().getClusterId()) : "") + + CR_TAB + "Is root Cluster: " + cluster.isRoot() + + CR_TAB + "Is leaf Cluster: " + cluster.isLeaf() + ); + + Cluster[] ancestors = cluster.getAncestors(); + StringBuffer sbTab = new StringBuffer(TAB+"Anchestors "); + if ( ancestors != null ){ + for (int j=0 ; j 'oc_sh_sample_num'); + + DBMS_DATA_MINING_TRANSFORM.INSERT_AUTOBIN_NUM_EQWIDTH( + bin_table_name => 'oc_sh_sample_num', + data_table_name => 'mining_data_build_str_v', + -- categoricals are automatically excluded by this procedure + exclude_list => DBMS_DATA_MINING_TRANSFORM.COLUMN_LIST ( + 'cust_id'), + sample_size => 30000 -- same as OCLT_MAX_BUFFER setting below + ); + + -- Create the transformed view + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_NUM( + bin_table_name => 'oc_sh_sample_num', + data_table_name => 'mining_data_build_str_v', + xform_view_name => 'oc_sh_sample_build_prepared', + -- see dbmsdmxf.sql for explanation of literal flag + literal_flag => TRUE); +END; +/ + +-- DATA PREPARATION OBJECTS: +-- ------------------------ +-- 1. Bin boundary Table: oc_sh_sample_num +-- 2. Input (view) to CREATE_MODEL: oc_sh_sample_build_prepared + +------------------- +-- SPECIFY SETTINGS +-- +-- Cleanup old settings table for repeat runs +-- +BEGIN EXECUTE IMMEDIATE 'DROP TABLE oc_sh_sample_settings'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- K-Means is the default clustering algorithm. Override the +-- default to set the algorithm to O-Cluster using a settings table. +-- +-- CREATE AND POPULATE A SETTINGS TABLE +-- +set echo off +CREATE TABLE oc_sh_sample_settings ( + setting_name VARCHAR2(30), + setting_value VARCHAR2(30)); +set echo on +BEGIN + INSERT INTO oc_sh_sample_settings VALUES + (dbms_data_mining.algo_name, dbms_data_mining.algo_ocluster); + INSERT INTO oc_sh_sample_settings VALUES + (dbms_data_mining.clus_num_clusters, 10); + INSERT INTO oc_sh_sample_settings VALUES + (dbms_data_mining.oclt_max_buffer, 30000); + + -- Other possible settings are: + -- (dbms_data_mining.oclt_sensitivity, 0.5); +END; +/ + +--------------------- +-- CREATE A NEW MODEL +-- +-- Build a new OC model +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'OC_SH_Clus_sample', + mining_function => dbms_data_mining.clustering, + data_table_name => 'oc_sh_sample_build_prepared', + case_id_column_name => 'cust_id', + settings_table_name => 'oc_sh_sample_settings'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30 +column setting_value format a30 +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'OC_SH_CLUS_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +column attribute_name format a40 +column attribute_type format a20 +SELECT attribute_name, attribute_type + FROM user_mining_model_attributes + WHERE model_name = 'OC_SH_CLUS_SAMPLE' +ORDER BY attribute_name; + +------------------------ +-- DISPLAY MODEL DETAILS +-- +-- Cluster details are best seen in pieces - based on the kind of +-- associations and groupings that are needed to be observed. +-- + +-- CLUSTERS +-- For each cluster_id, provides the number of records in the cluster, +-- the parent cluster id, and the level in the hierarchy. +-- NOTE: Unlike K-means, O-Cluster does not return a value for the +-- dispersion associated with a cluster. +-- +SELECT T.id clu_id, + T.record_count rec_cnt, + T.parent parent, + T.tree_level tree_level + FROM (SELECT * + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_OC( + 'OC_SH_Clus_sample')) + ORDER BY id) T + WHERE ROWNUM < 11; + +-- TAXONOMY +-- +SELECT clu_id, child_id + FROM (SELECT T.id clu_id, C.id child_id + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_OC( + 'OC_SH_Clus_sample')) T, + TABLE(T.child) C + ORDER BY T.id,C.id) + WHERE ROWNUM < 11; + +-- SPLIT PREDICATES +-- For each cluster, the split predicate indicates the attribute +-- and the condition used to assign records to the cluster's children +-- during model build. It provides an important piece of information +-- on how the population within a cluster can be divided up into +-- two smaller clusters. +-- +column attribute_name format a20 +column op format a2 +column s_value format a50 +SELECT clu_id, attribute_name, op, s_value + FROM (SELECT a.id clu_id, sp.attribute_name, sp.conditional_operator op, + sp.attribute_str_value s_value + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_OC( + 'OC_SH_Clus_sample')) a, + TABLE(a.split_predicate) sp + ORDER BY a.id, op, s_value) + WHERE ROWNUM < 11; + +-- CENTROIDS FOR LEAF CLUSTERS +-- For each cluster_id, this output lists all the attributes that +-- constitute the centroid, with the mean (for numericals) or +-- mode (for categoricals). Unlike K-Means, O-Cluster does not return +-- the variance for numeric attributes. +-- +column mode_val format a60 +SELECT clu_id, attribute_name, mean, mode_val + FROM (SELECT a.id clu_id, c.attribute_name, c.mean, c.mode_value mode_val + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_OC( + 'OC_SH_Clus_sample')) a, + TABLE(a.centroid) c + ORDER BY a.id, c.attribute_name) + WHERE ROWNUM < 11; + +-- HISTOGRAM FOR LEAF CLUSTERS +-- Histogram count is represented in frequency, rather than actual count. +column count format 9999.99 +column bin_id format 9999999 +column clu_id format 99999999 +column label format a15; +SELECT clu_id, bin_id, attribute_name, label, cnt + FROM (SELECT a.id clu_id, h.bin_id, h.attribute_name, h.label, h.count cnt + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_OC( + 'OC_SH_Clus_sample')) a, + TABLE(a.histogram) h + ORDER BY a.id, h.attribute_name, h.bin_id) + WHERE ROWNUM < 11; + +-- RULES FOR LEAF CLUSTERS +-- See dmkmdemo.sql for explanation on output columns. +column confidence format 999999.99 +SELECT * + FROM (SELECT T.id rule_id, + T.rule.rule_support support, + T.rule.rule_confidence confidence + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_OC( + 'OC_SH_Clus_sample')) T + ORDER BY confidence DESC, support DESC) + WHERE confidence > 0.5; + +-- RULE DETAILS FOR LEAF CLUSTERS +-- +-- The build data is prepared in this example, so reverse transform +-- the model contents to corresponding bin boundary labels. Translation +-- back to the exact value is not possible. +-- +-- See dmkmdemo.sql for explanation on output columns. +column val format a60; +WITH +mod_dtls AS ( +SELECT * + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_OC('OC_SH_Clus_sample')) +), +bin_labels AS ( +SELECT col, bin, (DECODE(bin,'1','[','(') || lv || ',' || val || ']') label + FROM (SELECT col, + bin, + LAST_VALUE(val) OVER ( + PARTITION BY col ORDER BY val + ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) lv, + val + FROM oc_sh_sample_num) +) +SELECT R.id rule_id, + A.attribute_name attribute_name, + A.conditional_operator op, + NVL(L.label, NVL(A.attribute_str_value,A.attribute_num_value)) val, + A.attribute_support support, + A.attribute_confidence confidence + FROM mod_dtls R, + TABLE(R.rule.antecedent) A, + bin_labels L + WHERE A.attribute_name = L.col (+) AND + (NVL(A.attribute_str_value,A.attribute_num_value) = L.bin(+)) AND + A.attribute_confidence > 0.5 +ORDER BY confidence DESC, support DESC, rule_id, attribute_name, val; + +-- 0.5 is used as the threshold just to show some numerical attributes +-- that have been decoded back to their original ranges. +-- The ORDER BYs are there just to enable repeatable output; they are +-- not a mandatory part of the query. + +----------------------------------------------------------------------- +-- TEST THE MODEL +----------------------------------------------------------------------- + +-- There is no specific set of testing parameters for Clustering. +-- Examination and analysis of clusters is the main method to prove +-- the efficacy of a clustering model. +-- + +----------------------------------------------------------------------- +-- APPLY THE MODEL +----------------------------------------------------------------------- +-- For a descriptive mining function like Clustering, "Scoring" involves +-- assigning the probability with which a given case belongs to a given +-- cluster. + +-- Cleanup scoring data preparation objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP VIEW oc_sh_sample_apply_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +----------------------- +-- PREPARE SCORING DATA +-- +-- 1. Outlier Treatment +-- Skipped. See dmsvcdem.sql for an example. +-- +-- 2. Binning +-- Use the Bin Boundary Table obtained earlier to bin the apply data. +-- +BEGIN + DBMS_DATA_MINING_TRANSFORM.XFORM_BIN_NUM( + bin_table_name => 'oc_sh_sample_num', + data_table_name => 'mining_data_apply_str_v', + xform_view_name => 'oc_sh_sample_apply_prepared', + literal_flag => TRUE); +END; +/ + +-- Cleanup scoring result objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE oc_sh_sample_apply_result'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE oc_sh_sample_apply_ranked'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +------------------------------------------------- +-- SCORE NEW DATA USING SQL DATA MINING FUNCTIONS +-- +------------------ +-- BUSINESS CASE 1 +-- List the clusters into which the customers in this +-- given dataset have been grouped. +-- +SELECT CLUSTER_ID(oc_sh_clus_sample USING *) AS clus, COUNT(*) AS cnt + FROM oc_sh_sample_apply_prepared +GROUP BY CLUSTER_ID(oc_sh_clus_sample USING *) +ORDER BY cnt DESC; + +-- See dmkmdemo.sql for more examples diff --git a/dmpademo.java b/dmpademo.java new file mode 100644 index 0000000..bc53b61 --- /dev/null +++ b/dmpademo.java @@ -0,0 +1,235 @@ +// Copyright (c) 2004, 2006, Oracle. All rights reserved. +// File: dmpademo.java +// Generic api imports +import java.sql.Statement; +// Java Data Mining (JDM) standard imports +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.NamedObject; +import javax.datamining.base.Task; +import javax.datamining.resource.Connection; +import javax.datamining.resource.ConnectionFactory; +import javax.datamining.resource.ConnectionSpec; +// Oracle Java Data Mining (JDM) implemented api imports +import oracle.dmt.jdm.base.OraTask; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.task.OraExplainTask; +import oracle.dmt.jdm.task.OraExplainTaskFactory; +import oracle.dmt.jdm.task.OraPredictTask; +import oracle.dmt.jdm.task.OraPredictTaskFactory; +import oracle.dmt.jdm.task.OraPredictiveAnalyticsTaskFactory; +import oracle.dmt.jdm.task.OraProfileTask; + +/** +* Predictive Analytics Demo. This demo runs the predict, explain and profile +* tasks. +* +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +public class + +dmpademo + extends Object +{ + + //Connection related data members + private static Connection m_dmeConn = null; + private static ConnectionFactory m_dmeConnFactory = null; + //Object factories used in this demo program + private static OraPredictiveAnalyticsTaskFactory m_paFactory = null; + + public static void main(String[] args) + { + try + { + if (args.length != 3) + { + System.out.println("Usage: java dmpademo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + // 1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@" + uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Initialize factories for mining objects + initFactories(); + // 3. Predict + predict(); + // 4. Explain + explain(); + // 5. Profile + profile(); + } + catch (Exception anyExp) + { + anyExp.printStackTrace(System.out); + } + finally + { + try + { + // 6. Logout from the Data Mining Engine + m_dmeConn.close(); + } + catch (Exception anyExp1) + { + } //Ignore + } + } + + public static void initFactories() + throws JDMException + { + m_paFactory = + (OraPredictiveAnalyticsTaskFactory) m_dmeConn.getFactory("oracle.dmt.jdm.task.OraPredictiveAnalyticsTask"); + } + + /** + * This method builds a mining model. The build operation requires the training + * dataset location details and the mining function settings. + * In this example, we will use the original unprepared dataset + * "MINING_DATA_BUILD_V" as an input. The predictTask will automatically + * prepare the dataset and create a new prepared dataset called + * "JDM_PRED_MINING_DATA_BUILD". Then, we will build a classification model + * using the prepared build dataset in the user schema, with the NaiveBayes + * algorithm. This model can be used to predict which customer would respond + * to a promotion campaign. + */ + public static void predict() + throws JDMException + { + //1. Create, save & execute predict Task + OraPredictTask predictTask = + m_paFactory.createPredictTask("MINING_DATA_BUILD_V", "cust_id", + "affinity_card", + "JDM_PRED_MINING_DATA_BUILD"); + predictTask.setDescription("PredictTask_jdm"); + ((OraTask)predictTask).overwriteOutput(true); + executeTask(predictTask, "PredictTask_jdm"); + //Retrieve task & see the details of the task (Note:Remove this from demo program) + try + { + predictTask = + (OraPredictTask) m_dmeConn.retrieveObject("PredictTask_jdm", + NamedObject.task); + predictTask.getInputData(); + predictTask.getOutputData(); + predictTask.getTargetAttributeName(); + } + catch (Exception anyExp) + { + anyExp.printStackTrace(); + } + } + + public static void explain() + throws JDMException + { + //1. Create, save & execute predict Task + OraExplainTask explainTask = + m_paFactory.createExplainTask("MINING_DATA_BUILD_V", "affinity_card", + "JDM_EXPL_MINING_DATA_BUILD"); + explainTask.setDescription("ExplainTask_jdm"); + ((OraTask)explainTask).overwriteOutput(true); + executeTask(explainTask, "ExplainTask_jdm"); + try + { + explainTask = + (OraExplainTask) m_dmeConn.retrieveObject("ExplainTask_jdm", + NamedObject.task); + explainTask.getInputData(); + explainTask.getOutputData(); + explainTask.getExplainAttributeName(); + } + catch (Exception anyExp) + { + anyExp.printStackTrace(); + } + } + + /** + * This method builds a mining model. The build operation requires the training + * dataset location details and the mining function settings. + * In this example, we will use the original unprepared dataset + * "MINING_DATA_BUILD_V" as an input. The predictTask will automatically + * prepare the dataset and create a new prepared dataset called + * "JDM_PRED_MINING_DATA_BUILD". Then, we will build a classification model + * using the prepared build dataset in the user schema, with the NaiveBayes + * algorithm. This model can be used to predict which customer would respond + * to a promotion campaign. + */ + public static void profile() + throws JDMException + { + //1. Create, save & execute predict Task + OraProfileTask profileTask = + m_paFactory.createProfileTask("MINING_DATA_BUILD_V", "affinity_card", + "JDM_PROFILE_RESULTS"); + profileTask.setDescription("ProfileTask_jdm"); + ((OraTask)profileTask).overwriteOutput(true); + executeTask(profileTask, "ProfileTask_jdm"); + //Retrieve task & see the details of the task (Note:Remove this from demo program) + try + { + profileTask = + (OraProfileTask) m_dmeConn.retrieveObject("ProfileTask_jdm", + NamedObject.task); + profileTask.getInputData(); + profileTask.getTargetAttributeName(); + } + catch (Exception anyExp) + { + anyExp.printStackTrace(); + } + } + + + /** + * This method stores the given task with the specified name in the DMS + * and submits the task for asynchronous execution in the DMS. After + * completing the task successfully it returns true. If there is a task + * failure, then it prints the error description and returns false. + * + * @param taskObj task object + * @param taskName name of the task + * + * @return boolean returns true when the task is successful + */ + public static boolean executeTask(Task taskObj, String taskName) + throws JDMException + { + boolean isTaskSuccess = false; + m_dmeConn.saveObject(taskName, taskObj, true); + ExecutionHandle execHandle = m_dmeConn.execute(taskName); + System.out.print(taskName + " is started, please wait. "); + //Wait for completion of the task + ExecutionStatus status = + execHandle.waitForCompletion(Integer.MAX_VALUE); + //Check the status of the task after completion + isTaskSuccess = status.getState().equals(ExecutionState.success); + if (isTaskSuccess) + { + //Task completed successfully + System.out.println(taskName + " is successful."); + } + else + { //Task failed + System.out.println(taskName + " is failed.\nFailure Description: " + + status.getDescription()); + } + return isTaskSuccess; + } +} diff --git a/dmsh.sql b/dmsh.sql new file mode 100644 index 0000000..5678615 --- /dev/null +++ b/dmsh.sql @@ -0,0 +1,593 @@ +-------------------------------------------------------------------------------- +-- +-- $Header: dmsh.sql 11-jul-2005.15:09:03 ktaylor Exp $ +-- +-- dmsh.sql +-- +-- Copyright (c) 2001, 2005, Oracle. All rights reserved. +-- +-- NAME +-- dmsh.sql +-- +-- DESCRIPTION +-- This script creates views and tables using SH data +-- in the schema of the data mining user. These tables/views +-- are the datasets used by the Oracle Data Mining demo programs. +-- This script also creates an index and index preference for +-- text mining. +-- NOTES +-- The script assumes that the full SH schema is already created and the +-- necessary SELECTs have been granted (See dmshgrants.sql). This script runs in +-- the schema of the data mining user. +-- mining_data_*_str_v views : Used for OC +-- mining_data_*_v views : Used for mining (no text) +-- market_basket_v view : Used for association rules +-- mining_*_text tables: Used for Text mining in ODM Java API +-- mining_*_nested_text tables: Used for Text mining in DBMS_DATA_MINING API +-- +-- MODIFIED (MM/DD/YY) +-- ktaylor 07/11/05 - minor edits to comments +-- xbarr 03/14/05 - add purge for object drop +-- cbhagwat 11/09/04 - Using collect +-- bmilenov 10/20/04 - Add one-class demo view +-- cbhagwat 09/17/04 - Bug 3881118 +-- xbarr 08/17/04 - create view for OC +-- xbarr 06/25/04 - xbarr_dm_rdbms_migration +-- cbhagwat 11/11/03 - Text NMF_CLUSTERING => SVM_CLASSIFIER +-- cbhagwat 10/10/03 - Remove DROPs +-- cbhagwat 10/10/03 - Remove Sh grants +-- cbhagwat 10/09/03 - Add nested table creatin using Text tf +-- cbhagwat 10/08/03 - cbhagwat_txn109150 +-- cbhagwat 10/08/03 - creation +-- +-------------------------------------------------------------------------------- +-- +-- Creates data mining views on SH data +-- +-- Build, apply views for OC +CREATE VIEW mining_data_apply_str_v( +CUST_ID, +CUST_GENDER, +AGE, +CUST_MARITAL_STATUS, +COUNTRY_NAME, +CUST_INCOME_LEVEL, +EDUCATION, +OCCUPATION, +HOUSEHOLD_SIZE, +YRS_RESIDENCE, +AFFINITY_CARD, +BULK_PACK_DISKETTES, +FLAT_PANEL_MONITOR, +HOME_THEATER_PACKAGE, +BOOKKEEPING_APPLICATION, +PRINTER_SUPPLIES, +Y_BOX_GAMES, +OS_DOC_SET_KANJI) +AS SELECT + a.CUST_ID, + a.CUST_GENDER, + 2003-a.CUST_YEAR_OF_BIRTH AGE, + a.CUST_MARITAL_STATUS, + c.COUNTRY_NAME, + a.CUST_INCOME_LEVEL, + b.EDUCATION, + b.OCCUPATION, + b.HOUSEHOLD_SIZE, + b.YRS_RESIDENCE, + SUBSTR(TO_CHAR(b.AFFINITY_CARD),1,1), + SUBSTR(TO_CHAR(b.BULK_PACK_DISKETTES),1,1), + SUBSTR(TO_CHAR(b.FLAT_PANEL_MONITOR),1,1), + SUBSTR(TO_CHAR(b.HOME_THEATER_PACKAGE),1,1), + SUBSTR(TO_CHAR(b.BOOKKEEPING_APPLICATION),1,1), + SUBSTR(TO_CHAR(b.PRINTER_SUPPLIES),1,1), + SUBSTR(TO_CHAR(b.Y_BOX_GAMES),1,1), + SUBSTR(TO_CHAR(b.OS_DOC_SET_KANJI),1,1) +FROM + sh.customers a, + sh.supplementary_demographics b, + sh.countries c +WHERE + a.CUST_ID = b.CUST_ID + AND a.country_id = c.country_id + AND a.cust_id between 100001 and 101500; + +CREATE VIEW mining_data_build_str_v( +CUST_ID, +CUST_GENDER, +AGE, +CUST_MARITAL_STATUS, +COUNTRY_NAME, +CUST_INCOME_LEVEL, +EDUCATION, +OCCUPATION, +HOUSEHOLD_SIZE, +YRS_RESIDENCE, +AFFINITY_CARD, +BULK_PACK_DISKETTES, +FLAT_PANEL_MONITOR, +HOME_THEATER_PACKAGE, +BOOKKEEPING_APPLICATION, +PRINTER_SUPPLIES, +Y_BOX_GAMES, +OS_DOC_SET_KANJI) +AS SELECT + a.CUST_ID, + a.CUST_GENDER, + 2003-a.CUST_YEAR_OF_BIRTH AGE, + a.CUST_MARITAL_STATUS, + c.COUNTRY_NAME, + a.CUST_INCOME_LEVEL, + b.EDUCATION, + b.OCCUPATION, + b.HOUSEHOLD_SIZE, + b.YRS_RESIDENCE, + SUBSTR(TO_CHAR(b.AFFINITY_CARD),1,1), + SUBSTR(TO_CHAR(b.BULK_PACK_DISKETTES),1,1), + SUBSTR(TO_CHAR(b.FLAT_PANEL_MONITOR),1,1), + SUBSTR(TO_CHAR(b.HOME_THEATER_PACKAGE),1,1), + SUBSTR(TO_CHAR(b.BOOKKEEPING_APPLICATION),1,1), + SUBSTR(TO_CHAR(b.PRINTER_SUPPLIES),1,1), + SUBSTR(TO_CHAR(b.Y_BOX_GAMES),1,1), + SUBSTR(TO_CHAR(b.OS_DOC_SET_KANJI),1,1) +FROM + sh.customers a, + sh.supplementary_demographics b, + sh.countries c +WHERE + a.CUST_ID = b.CUST_ID + AND a.country_id = c.country_id + AND a.cust_id between 101501 and 103000; + +-- Build , test and apply views, no text +CREATE VIEW mining_data_apply_v AS +SELECT + a.CUST_ID, + a.CUST_GENDER, + 2003-a.CUST_YEAR_OF_BIRTH AGE, + a.CUST_MARITAL_STATUS, + c.COUNTRY_NAME, + a.CUST_INCOME_LEVEL, + b.EDUCATION, + b.OCCUPATION, + b.HOUSEHOLD_SIZE, + b.YRS_RESIDENCE, + b.AFFINITY_CARD, + b.BULK_PACK_DISKETTES, + b.FLAT_PANEL_MONITOR, + b.HOME_THEATER_PACKAGE, + b.BOOKKEEPING_APPLICATION, + b.PRINTER_SUPPLIES, + b.Y_BOX_GAMES, + b.OS_DOC_SET_KANJI +FROM + sh.customers a, + sh.supplementary_demographics b, + sh.countries c +WHERE + a.CUST_ID = b.CUST_ID + AND a.country_id = c.country_id + AND a.cust_id between 100001 and 101500; + +CREATE VIEW mining_data_build_v AS +SELECT + a.CUST_ID, + a.CUST_GENDER, + 2003-a.CUST_YEAR_OF_BIRTH AGE, + a.CUST_MARITAL_STATUS, + c.COUNTRY_NAME, + a.CUST_INCOME_LEVEL, + b.EDUCATION, + b.OCCUPATION, + b.HOUSEHOLD_SIZE, + b.YRS_RESIDENCE, + b.AFFINITY_CARD, + b.BULK_PACK_DISKETTES, + b.FLAT_PANEL_MONITOR, + b.HOME_THEATER_PACKAGE, + b.BOOKKEEPING_APPLICATION, + b.PRINTER_SUPPLIES, + b.Y_BOX_GAMES, + b.OS_DOC_SET_KANJI +FROM + sh.customers a, + sh.supplementary_demographics b, + sh.countries c +WHERE + a.CUST_ID = b.CUST_ID + AND a.country_id = c.country_id + AND a.cust_id between 101501 and 103000; + +CREATE VIEW mining_data_test_v AS +SELECT + a.CUST_ID, + a.CUST_GENDER, + 2003-a.CUST_YEAR_OF_BIRTH AGE, + a.CUST_MARITAL_STATUS, + c.COUNTRY_NAME, + a.CUST_INCOME_LEVEL, + b.EDUCATION, + b.OCCUPATION, + b.HOUSEHOLD_SIZE, + b.YRS_RESIDENCE, + b.AFFINITY_CARD, + b.BULK_PACK_DISKETTES, + b.FLAT_PANEL_MONITOR, + b.HOME_THEATER_PACKAGE, + b.BOOKKEEPING_APPLICATION, + b.PRINTER_SUPPLIES, + b.Y_BOX_GAMES, + b.OS_DOC_SET_KANJI +FROM + sh.customers a, + sh.supplementary_demographics b, + sh.countries c +WHERE + a.CUST_ID = b.CUST_ID + AND a.country_id = c.country_id + AND a.cust_id between 103001 and 104500; + +CREATE VIEW market_basket_v AS +SELECT a.cust_id, + MAX((CASE WHEN b.PROD_NAME = + 'Extension Cable' THEN a.QUANTITY_SOLD else null end)) EXTENSION_CABLE, + MAX((CASE WHEN b.PROD_NAME = + '18" Flat Panel Graphics Monitor' THEN a.QUANTITY_SOLD else NULL END)) + FLAT_PANEL_MONITOR , + MAX((CASE WHEN b.PROD_NAME = + 'CD-RW, High Speed Pack of 5' THEN a.QUANTITY_SOLD else NULL END)) + CD_RW_HIGH_SPEED_5_PACK, + MAX((CASE WHEN b.PROD_NAME = + 'Envoy 256MB - 40GB' THEN a.QUANTITY_SOLD else NULL END)) + ENVOY_256MB_40GB, + MAX((CASE WHEN b.PROD_NAME = + 'Envoy Ambassador' THEN a.QUANTITY_SOLD else NULL END)) + ENVOY_AMBASSADOR, + MAX((CASE WHEN b.PROD_NAME = + 'External 8X CD-ROM' THEN a.QUANTITY_SOLD else NULL END)) + EXTERNAL_8X_CD_ROM, + MAX((CASE WHEN b.PROD_NAME = + 'Keyboard Wrist Rest' THEN a.QUANTITY_SOLD else NULL END)) + KEYBOARD_WRIST_REST, + MAX((CASE WHEN b.PROD_NAME = + 'Model SM26273 Black Ink Cartridge' THEN a.QUANTITY_SOLD else NULL END)) + SM26273_BLACK_INK_CARTRIDGE, + MAX((CASE WHEN b.PROD_NAME = + 'Mouse Pad' THEN a.QUANTITY_SOLD else NULL END)) + MOUSE_PAD, + MAX((CASE WHEN b.PROD_NAME = + 'Multimedia speakers- 3" cones' THEN a.QUANTITY_SOLD else NULL END)) + MULTIMEDIA_SPEAKERS_3INCH, + MAX((CASE WHEN b.PROD_NAME = + 'O/S Documentation Set - English' THEN a.QUANTITY_SOLD else NULL END)) + OS_DOC_SET_ENGLISH, + MAX((CASE WHEN b.PROD_NAME = + 'SIMM- 16MB PCMCIAII card' THEN a.QUANTITY_SOLD else NULL END)) + SIMM_16MB_PCMCIAII_CARD, + MAX((CASE WHEN b.PROD_NAME = + 'Standard Mouse' THEN a.QUANTITY_SOLD else NULL END)) + STANDARD_MOUSE +FROM sh.sales a, + sh.products b + where a.prod_id = b.prod_id + AND a.cust_id BETWEEN 100001 AND 104500 + group by cust_id; + +-- Build, test and apply views with Text + +CREATE TABLE mining_apply_text AS +SELECT + a.CUST_ID, + a.CUST_GENDER, + 2003-a.CUST_YEAR_OF_BIRTH AGE, + a.CUST_MARITAL_STATUS, + c.COUNTRY_NAME, + a.CUST_INCOME_LEVEL, + b.EDUCATION, + b.OCCUPATION, + b.HOUSEHOLD_SIZE, + b.YRS_RESIDENCE, + b.AFFINITY_CARD, + b.BULK_PACK_DISKETTES, + b.FLAT_PANEL_MONITOR, + b.HOME_THEATER_PACKAGE, + b.BOOKKEEPING_APPLICATION, + b.PRINTER_SUPPLIES, + b.Y_BOX_GAMES, + b.os_doc_set_kanji, + b.comments +FROM + sh.customers a, + sh.supplementary_demographics b, + sh.countries c +WHERE + a.CUST_ID = b.CUST_ID + AND a.country_id = c.country_id + AND a.cust_id between 100001 and 101500; + +-- CREATE TEXT INDEX +CREATE INDEX apply_text_idx ON mining_apply_text(comments) + INDEXTYPE IS ctxsys.context PARAMETERS('nopopulate') +/ + +CREATE TABLE mining_build_text AS +SELECT + a.CUST_ID, + a.CUST_GENDER, + 2003-a.CUST_YEAR_OF_BIRTH AGE, + a.CUST_MARITAL_STATUS, + c.COUNTRY_NAME, + a.CUST_INCOME_LEVEL, + b.EDUCATION, + b.OCCUPATION, + b.HOUSEHOLD_SIZE, + b.YRS_RESIDENCE, + b.AFFINITY_CARD, + b.BULK_PACK_DISKETTES, + b.FLAT_PANEL_MONITOR, + b.HOME_THEATER_PACKAGE, + b.BOOKKEEPING_APPLICATION, + b.PRINTER_SUPPLIES, + b.Y_BOX_GAMES, + b.os_doc_set_kanji, + b.comments +FROM + sh.customers a, + sh.supplementary_demographics b, + sh.countries c +WHERE + a.CUST_ID = b.CUST_ID + AND a.country_id = c.country_id + AND a.cust_id between 101501 and 103000; + +-- CREATE TEXT INDEX +CREATE INDEX build_text_idx ON mining_build_text(comments) + INDEXTYPE IS ctxsys.context PARAMETERS('nopopulate') +/ + +CREATE TABLE mining_test_text AS +SELECT + a.CUST_ID, + a.CUST_GENDER, + 2003-a.CUST_YEAR_OF_BIRTH AGE, + a.CUST_MARITAL_STATUS, + c.COUNTRY_NAME, + a.CUST_INCOME_LEVEL, + b.EDUCATION, + b.OCCUPATION, + b.HOUSEHOLD_SIZE, + b.YRS_RESIDENCE, + b.AFFINITY_CARD, + b.BULK_PACK_DISKETTES, + b.FLAT_PANEL_MONITOR, + b.HOME_THEATER_PACKAGE, + b.BOOKKEEPING_APPLICATION, + b.PRINTER_SUPPLIES, + b.Y_BOX_GAMES, + b.os_doc_set_kanji, + b.comments +FROM + sh.customers a, + sh.supplementary_demographics b, + sh.countries c +WHERE + a.CUST_ID = b.CUST_ID + AND a.country_id = c.country_id + AND a.cust_id between 103001 and 104500; + +-- CREATE TEXT INDEX +CREATE INDEX test_text_idx ON mining_test_text(comments) + INDEXTYPE IS ctxsys.context PARAMETERS('nopopulate') +/ + +-- +-- Use the text table functions to create nested data +-- Using dm$ to avoid conflicts with user tables +EXECUTE ctx_ddl.create_preference('dm$temp_text_pref','SVM_CLASSIFIER'); + +-- SVM_CLASSIFIER needs a table +CREATE TABLE + dm$temp_text_pref_cat ( + id NUMBER, + cat NUMBER) +/ + +-- Extract features from the build table +CREATE TABLE dm$build_tf_out AS +SELECT * + FROM + TABLE(ctxsys.drvodm.feature_prep + ('BUILD_TEXT_IDX', -- Text index name + 'CUST_ID', -- case-id + 'dm$temp_text_pref_cat', + 'id', + 'cat', + 'dm$build_prep_features', -- Features table + 'dm$temp_text_pref')) -- Text preference name +/ +CREATE TABLE dm$build_explain_out AS +SELECT a.sequence_id, + b.text, + a.value + FROM dm$build_tf_out a, + TABLE(ctxsys.drvodm.feature_explain('dm$build_prep_features')) b + WHERE a.attribute_id = b.id +/ +CREATE TABLE mining_build_nested_text + NESTED TABLE comments store AS build_comments + AS +SELECT non_text.cust_id, + non_text.cust_gender, + non_text.age, + non_text.cust_marital_status, + non_text.country_name, + non_text.cust_income_level, + non_text.education, + non_text.occupation, + non_text.household_size, + non_text.yrs_residence, + non_text.affinity_card, + non_text.bulk_pack_diskettes, + non_text.flat_panel_monitor, + non_text.home_theater_package, + non_text.bookkeeping_application, + non_text.printer_supplies, + non_text.y_box_games, + non_text.os_doc_set_kanji, + txt.comments + FROM + mining_build_text non_text, + ( SELECT features.sequence_id, + cast(COLLECT(dm_nested_numerical(features.text,features.value)) + as dm_nested_numericals) comments + FROM dm$build_explain_out features + group by features.sequence_id) txt + WHERE non_text.cust_id = txt.sequence_id(+) +/ + +DROP TABLE dm$build_tf_out purge; +DROP TABLE dm$build_explain_out purge; + +-- +-- Extract features, Cast into dm_nested_numericals +-- Make a TEST view with non-text and text data +-- Use featres table from build data +CREATE TABLE dm$test_tf_out AS +SELECT * + FROM + TABLE(ctxsys.drvodm.feature_prep + ('TEST_TEXT_IDX', -- Text index name + 'CUST_ID', -- case-id + 'dm$build_prep_features')) -- restab +/ +CREATE TABLE dm$test_explain_out AS +SELECT a.sequence_id, + b.text, + a.value + FROM dm$test_tf_out a, + TABLE(ctxsys.drvodm.feature_explain('dm$build_prep_features')) b + WHERE a.attribute_id = b.id +/ +CREATE TABLE mining_test_nested_text + NESTED TABLE comments store AS test_comments AS +SELECT non_text.cust_id, + non_text.cust_gender, + non_text.age, + non_text.cust_marital_status, + non_text.country_name, + non_text.cust_income_level, + non_text.education, + non_text.occupation, + non_text.household_size, + non_text.yrs_residence, + non_text.affinity_card, + non_text.bulk_pack_diskettes, + non_text.flat_panel_monitor, + non_text.home_theater_package, + non_text.bookkeeping_application, + non_text.printer_supplies, + non_text.y_box_games, + non_text.os_doc_set_kanji, + txt.comments + FROM + mining_test_text non_text, + ( SELECT features.sequence_id, + cast(COLLECT(dm_nested_numerical(features.text,features.value)) + as dm_nested_numericals) comments + FROM dm$test_explain_out features + group by features.sequence_id) txt + WHERE non_text.cust_id = txt.sequence_id(+) +/ + +DROP TABLE dm$test_tf_out purge; +DROP TABLE dm$test_explain_out purge; + + +-- Extract features from the build table +-- Use features from build data +CREATE TABLE dm$apply_tf_out AS +SELECT * + FROM + TABLE(ctxsys.drvodm.feature_prep + ('APPLY_TEXT_IDX', -- Text index name + 'CUST_ID', -- case-id + 'dm$build_prep_features')) -- restab +/ +CREATE TABLE dm$apply_explain_out AS +SELECT a.sequence_id, + b.text, + a.value + FROM dm$apply_tf_out a, + TABLE(ctxsys.drvodm.feature_explain('dm$build_prep_features')) b + WHERE a.attribute_id = b.id +/ + +CREATE TABLE mining_apply_nested_text + NESTED TABLE comments store AS apply_comments AS +SELECT non_text.cust_id, + non_text.cust_gender, + non_text.age, + non_text.cust_marital_status, + non_text.country_name, + non_text.cust_income_level, + non_text.education, + non_text.occupation, + non_text.household_size, + non_text.yrs_residence, + non_text.affinity_card, + non_text.bulk_pack_diskettes, + non_text.flat_panel_monitor, + non_text.home_theater_package, + non_text.bookkeeping_application, + non_text.printer_supplies, + non_text.y_box_games, + non_text.os_doc_set_kanji, + txt.comments + FROM + mining_apply_text non_text, + ( SELECT features.sequence_id, + cast(COLLECT(dm_nested_numerical(features.text,features.value)) + as dm_nested_numericals) comments + FROM dm$apply_explain_out features + group by features.sequence_id) txt + WHERE non_text.cust_id = txt.sequence_id(+) +/ + +CREATE VIEW mining_data_one_class_v AS +SELECT + a.CUST_ID, + a.CUST_GENDER, + 2003-a.CUST_YEAR_OF_BIRTH AGE, + a.CUST_MARITAL_STATUS, + c.COUNTRY_NAME, + a.CUST_INCOME_LEVEL, + b.EDUCATION, + b.OCCUPATION, + b.HOUSEHOLD_SIZE, + b.YRS_RESIDENCE +FROM + sh.customers a, + sh.supplementary_demographics b, + sh.countries c +WHERE + a.CUST_ID = b.CUST_ID + AND a.country_id = c.country_id + AND a.cust_id between 101501 and 103000 + AND affinity_card=1; + +DROP TABLE dm$build_prep_features purge; +DROP TABLE dm$apply_tf_out purge; +DROP TABLE dm$apply_explain_out purge; +-- Clean up the temp preference +EXECUTE ctx_ddl.drop_preference('dm$temp_text_pref'); +-- Clean up temp cat table created +DROP TABLE dm$temp_text_pref_cat purge; + + + + + + + + + diff --git a/dmshgrants.sql b/dmshgrants.sql new file mode 100644 index 0000000..c9cdcbf --- /dev/null +++ b/dmshgrants.sql @@ -0,0 +1,61 @@ +-------------------------------------------------------------------------------- +-- +-- $Header: dmshgrants.sql 28-aug-2007.07:35:51 xbarr Exp $ +-- +-- dmshgrants.sql +-- +-- Copyright (c) 2001, 2005, Oracle. All rights reserved. +-- +-- NAME +-- dmshgrants.sql +-- +-- DESCRIPTION +-- This script grants SELECT on SH tables and SYS privileges +-- required to run the Oracle Data Mining demo programs +-- +-- The script is to be run in SYS account +-- +-- NOTES +-- &&1 Name of the DM user +-- +-- MODIFIED (MM/DD/YY) +-- xbarr 08/28/07 - fix security bug 6367775 +-- pstengar 07/05/06 - add create mining model privilege +-- ktaylor 07/11/05 - Minor edits to comments +-- xbarr 12/20/04 - add privileges required by DM demo +-- cbhagwat 10/10/03 - creation +-- +-------------------------------------------------------------------------------- +DEFINE DMUSER = &&1 + +GRANT create procedure to &DMUSER +/ +grant create session to &DMUSER +/ +grant create table to &DMUSER +/ +grant create sequence to &DMUSER +/ +grant create view to &DMUSER +/ +grant create job to &DMUSER +/ +grant create type to &DMUSER +/ +grant create synonym to &DMUSER +/ +grant create mining model to &DMUSER +/ +grant execute on ctxsys.ctx_ddl to &DMUSER +/ + +GRANT SELECT ON sh.customers TO &DMUSER +/ +GRANT SELECT ON sh.sales TO &DMUSER +/ +GRANT SELECT ON sh.products TO &DMUSER +/ +GRANT SELECT ON sh.supplementary_demographics TO &DMUSER +/ +GRANT SELECT ON sh.countries TO &DMUSER +/ diff --git a/dmsvcdem.sql b/dmsvcdem.sql new file mode 100644 index 0000000..d64e207 --- /dev/null +++ b/dmsvcdem.sql @@ -0,0 +1,746 @@ +Rem +Rem $Header: dmsvcdem.sql 24-mar-2008.12:41:40 ramkrish Exp $ +Rem +Rem dmsvcdem.sql +Rem +Rem Copyright (c) 2003, 2008, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmsvcdem.sql - Sample program for the DBMS_DATA_MINING package. +Rem +Rem DESCRIPTION +Rem This script creates a classification model +Rem using the SVM algorithm +Rem and data in the SH (Sales History) schema in the RDBMS. +Rem +Rem NOTES +Rem This script demonstrates the use of the new Oracle10gR2 +Rem SQL functions for scoring models against new data, and +Rem the computation of various test metrics based on these +Rem new SQL functions. +Rem +Rem MODIFIED (MM/DD/YY) +Rem ramkrish 03/06/08 - bug 6820838 - clas_weights instead of priors +Rem ramkrish 06/14/07 - remove commit after settings +Rem ramkrish 10/25/07 - replace deprecated get_model calls with catalog +Rem queries +Rem jyarmus 10/18/06 - reduce precision of accuracy and AUC +Rem ktaylor 07/11/05 - minor edits to comments +Rem jcjeon 01/18/05 - add column format +Rem dmukhin 01/12/05 - bug 4053211: missing value treatment +Rem dmukhin 12/07/04 - 4053822 - lift and roc computation +Rem bmilenov 11/04/04 - Edit comments, add priors, remove costs +Rem ramkrish 09/27/04 - add data analysis and comments/cleanup +Rem bmilenov 05/18/04 - Change zscore to minmax normalization +Rem ramkrish 10/02/03 - Creation + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET echo ON + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM +----------------------------------------------------------------------- +-- Given demographic and purchase data about a set of customers, predict +-- customer's response to an affinity card program using an SVM classifier. +-- + +----------------------------------------------------------------------- +-- SET UP AND ANALYZE THE DATA +----------------------------------------------------------------------- + +------- +-- DATA +------- +-- The data for this sample is composed from base tables in SH Schema +-- (See Sample Schema Documentation) and presented through these views: +-- mining_data_build_v (build data) +-- mining_data_test_v (test data) +-- mining_data_apply_v (apply data) +-- (See dmsh.sql for view definitions). +-- + +----------- +-- ANALYSIS +----------- + +-- For classification using SVM, perform the following on mining data. +-- +-- 1. Missing Value treatment for Predictors in Build, Test and Apply data +-- +-- "Missing Value" here implies "Missing at Random" values, that is, +-- there is no pattern to the missing data, a NULL value does not have a +-- special meaning, and there is no correlation either direct or indirect +-- with the target or other predictor values. +-- +-- Missing value imputation is recommended when the fraction of missing +-- at random values is high compared to the overall attribute value set. +-- +-- Contrast this with a "sparse" dataset - where a NULL value for +-- an attribute encodes a zero/non-present. Typical examples of domains +-- with sparse data are market basket and text mining. Missing value +-- imputation should not be used on sparse data. By default, SVM +-- interprets all NULL values for a given attribute as "sparse". +-- +-- Based on the business problem, one should designate the NULL value +-- for a given attribute to be "missing at random" or "sparse". For +-- example, a NULL value for AGE in demographic data can be missing +-- at random if omitting this information is a random occurrence. +-- In contrast, a shopping cart record with NULL values for certain +-- items is usually considered sparse - because a customer cannot +-- buy the entire inventory of items in a store. +-- +-- +-- +-- Here we are showing a simple approach to missing value treatment: +-- +-- 1.1. Compute the mean for numerical attributes, and mode for +-- categoricals. Store them away in a table for use with +-- Test and Apply data. +-- +-- 1.2. Replace the NULLs in the build, test, and apply data +-- with the computed mean (for numerical), mode (for categorical). +-- +-- +-- 2. Outlier Treatment for Predictors for Build data +-- +-- For SVM, we recommended that the data be normalized (individual +-- attributes need to be on a similar scale) to achieve faster +-- convergence of model builds and more accurate models. Large outliers +-- in individual attributes can result in sub-optimal normalization +-- output and sub-optimal models. Note that outlier treatment would be also +-- beneficial for algorithms that use equi-width-binning (e.g., O-Cluster) +-- since outliers in the data would produce sub-optimal bin boundaries. +-- +-- Here we winsorize the tail (see documentation on DBMS_DATA_MINING_TRANSFORM +-- for details) elements of the data as a preparatory step to normalization. +-- We recommend the use of winsorizing to reduce the influence of outliers on +-- the normalization computation. The normalization parameters are computed +-- on the winsorized data. Once the normalization parameters are computed, +-- they can be used directly on the original data. Winsorizing is not needed +-- at test and apply time - it only affects the specification of the +-- normalization parameters. +-- +-- 3. Normalize Predictors in Build, Test, and Apply data +-- +-- NOTE: that unlike Regression using SVM, the target attribute is +-- NOT normalized. + + +----------------------------------------------------------------------- +-- BUILD THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old build data preparation objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE svmc_sh_sample_miss_num'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE svmc_sh_sample_miss_cat'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE svmc_sh_sample_clip'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE svmc_sh_sample_norm'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW mining_data_build_miss'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW mining_data_build'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW svmc_sh_sample_winsor'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW svmc_sh_sample_build_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +-- Cleanup old model with the same name for repeat runs +BEGIN DBMS_DATA_MINING.DROP_MODEL('SVMC_SH_Clas_sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-------------------------------- +-- PREPARE BUILD (TRAINING) DATA +-- + +-- 1. Missing Value treatment for all Predictors and +-- 2. Outlier Treatment and +-- 3. Normalization are performed below. +-- NOTE: that unlike SVM regression, the classification target is NOT +-- normalized here. +-- NOTE: AGE is the only predictor with continuous values in this dataset. +-- +BEGIN + -- Perform missing value treatment for all predictors + -- create miss tables + DBMS_DATA_MINING_TRANSFORM.CREATE_MISS_NUM ( + miss_table_name => 'svmc_sh_sample_miss_num'); + DBMS_DATA_MINING_TRANSFORM.CREATE_MISS_CAT ( + miss_table_name => 'svmc_sh_sample_miss_cat'); + + -- populate miss tables + DBMS_DATA_MINING_TRANSFORM.INSERT_MISS_NUM_MEAN ( + miss_table_name => 'svmc_sh_sample_miss_num', + data_table_name => 'mining_data_build_v', + exclude_list => DBMS_DATA_MINING_TRANSFORM.COLUMN_LIST ( + 'affinity_card', + 'cust_id')); + DBMS_DATA_MINING_TRANSFORM.INSERT_MISS_CAT_MODE ( + miss_table_name => 'svmc_sh_sample_miss_cat', + data_table_name => 'mining_data_build_v', + exclude_list => DBMS_DATA_MINING_TRANSFORM.COLUMN_LIST ( + 'affinity_card', + 'cust_id')); + + -- xform input data to replace missing values + DBMS_DATA_MINING_TRANSFORM.XFORM_MISS_NUM( + miss_table_name => 'svmc_sh_sample_miss_num', + data_table_name => 'mining_data_build_v', + xform_view_name => 'mining_data_build_miss'); + DBMS_DATA_MINING_TRANSFORM.XFORM_MISS_CAT( + miss_table_name => 'svmc_sh_sample_miss_cat', + data_table_name => 'mining_data_build_miss', + xform_view_name => 'mining_data_build'); + + -- Perform outlier treatment for: AGE + -- create clip table + DBMS_DATA_MINING_TRANSFORM.CREATE_CLIP ( + clip_table_name => 'svmc_sh_sample_clip'); + + -- populate clip table + DBMS_DATA_MINING_TRANSFORM.INSERT_CLIP_WINSOR_TAIL ( + clip_table_name => 'svmc_sh_sample_clip', + data_table_name => 'mining_data_build', + tail_frac => 0.025, + exclude_list => DBMS_DATA_MINING_TRANSFORM.COLUMN_LIST ( + 'affinity_card', + 'bookkeeping_application', + 'bulk_pack_diskettes', + 'cust_id', + 'flat_panel_monitor', + 'home_theater_package', + 'os_doc_set_kanji', + 'printer_supplies', + 'y_box_games')); + + -- xform input data to winsorized data + DBMS_DATA_MINING_TRANSFORM.XFORM_CLIP( + clip_table_name => 'svmc_sh_sample_clip', + data_table_name => 'mining_data_build', + xform_view_name => 'svmc_sh_sample_winsor'); + + -- normalize numerical attributes: AGE + -- create normalization table + DBMS_DATA_MINING_TRANSFORM.CREATE_NORM_LIN ( + norm_table_name => 'svmc_sh_sample_norm'); + + -- populate normalization table based on winsorized data + DBMS_DATA_MINING_TRANSFORM.INSERT_NORM_LIN_MINMAX ( + norm_table_name => 'svmc_sh_sample_norm', + data_table_name => 'svmc_sh_sample_winsor', + exclude_list => DBMS_DATA_MINING_TRANSFORM.COLUMN_LIST ( + 'affinity_card', + 'bookkeeping_application', + 'bulk_pack_diskettes', + 'cust_id', + 'flat_panel_monitor', + 'home_theater_package', + 'os_doc_set_kanji', + 'printer_supplies', + 'y_box_games')); + + -- normalize the original data + DBMS_DATA_MINING_TRANSFORM.XFORM_NORM_LIN ( + norm_table_name => 'svmc_sh_sample_norm', + data_table_name => 'mining_data_build', + xform_view_name => 'svmc_sh_sample_build_prepared'); +END; +/ + +-- BUILD DATA PREPARATION OBJECTS: +-- ------------------------------ +-- 1. Numerical Missing Value Table: svmc_sh_sample_miss_num +-- 2. Categorical Missing Value Table: svmc_sh_sample_miss_cat +-- 3. Winsorize Clip Table: svmc_sh_sample_clip +-- 4. MinMax Normalization Table: svmc_sh_sample_norm +-- 5. Input (view) to CREATE_MODEL: svmc_sh_sample_build_prepared + +------------------ +-- SPECIFY SETTINGS +-- +-- Cleanup old settings table for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE svmc_sh_sample_settings'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE svmc_sh_sample_class_wt'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- CREATE AND POPULATE A CLASS WEIGHTS TABLE +-- +-- A class weights table is used to influence the weighting of target classes +-- during model creation. For example, weights of (0.9, 0.1) for a binary +-- problem specify that an error in the first class has significantly +-- higher penalty that an error in the second class. Weights of (0.5, 0.5) +-- do not introduce a differential weight and would produce the same +-- model as when no weights are provided. +-- +CREATE TABLE svmc_sh_sample_class_wt ( + target_value NUMBER, + class_weight NUMBER); +INSERT INTO svmc_sh_sample_class_wt VALUES (0,0.35); +INSERT INTO svmc_sh_sample_class_wt VALUES (1,0.65); +COMMIT; + +-- CREATE AND POPULATE A SETTINGS TABLE +-- +set echo off +CREATE TABLE svmc_sh_sample_settings ( + setting_name VARCHAR2(30), + setting_value VARCHAR2(30)); +set echo on + +-- The default classification algorithm is Naive Bayes. So override +-- this choice to SVM using a settings table. +-- SVM chooses a kernel type automatically. This choice can be overriden +-- by the user. Linear kernel is preferred high dimensional data, and +-- Gaussian kernel for low dimensional data. Here we use linear kernel +-- to demonstrate the get_model_details_svm() API, which applies only for +-- models. +-- +BEGIN +-- Populate settings table + INSERT INTO svmc_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.algo_name, dbms_data_mining.algo_support_vector_machines); + INSERT INTO svmc_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.svms_kernel_function, dbms_data_mining.svms_linear); + INSERT INTO svmc_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.clas_weights_table_name, 'svmc_sh_sample_class_wt'); + -- Examples of other possible overrides are: + --(dbms_data_mining.svms_kernel_function, dbms_data_mining.svms_gaussian); + --(dbms_data_mining.svms_kernel_function, dbms_data_mining.svms_complexity_factor); + --(dbms_data_mining.svms_kernel_cache_size,100000000); +END; +/ + +--------------------- +-- CREATE A NEW MODEL +-- +-- Build a new SVM Model +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'SVMC_SH_Clas_sample', + mining_function => dbms_data_mining.classification, + data_table_name => 'svmc_sh_sample_build_prepared', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + settings_table_name => 'svmc_sh_sample_settings'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30 +column setting_value format a30 +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'SVMC_SH_CLAS_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +column attribute_name format a40 +column attribute_type format a20 +SELECT attribute_name, attribute_type + FROM user_mining_model_attributes + WHERE model_name = 'SVMC_SH_CLAS_SAMPLE' +ORDER BY attribute_name; + +------------------------ +-- DISPLAY MODEL DETAILS +-- +-- The coefficient indicates the relative influence of a given +-- (attribute, value) pair on the target value. A negative +-- coefficient value indicates a negative influence. +-- +-- NOTE: The FIRST row in the SVM model details output shows the +-- value for SVM bias under the COEFFICIENT column. +-- +SET line 120 +column class format a10 +column aname format a25 +column aval format a25 +column coeff format 9.99 + +WITH +mod_dtls AS ( +SELECT * + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_SVM('SVMC_SH_Clas_sample')) +), +model_details AS ( +SELECT D.class, A.attribute_name, A.attribute_value, A.coefficient + FROM mod_dtls D, + TABLE(D.attribute_set) A +ORDER BY D.class, ABS(A.coefficient) DESC +) +SELECT class, attribute_name aname, attribute_value aval, coefficient coeff + FROM model_details + WHERE ROWNUM < 11; + +----------------------------------------------------------------------- +-- TEST THE MODEL +----------------------------------------------------------------------- + +BEGIN EXECUTE IMMEDIATE 'DROP VIEW mining_data_test_miss'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW mining_data_test'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW svmc_sh_sample_test_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-------------------- +-- PREPARE TEST DATA +-- +-- If the data for model creation has been prepared, then the data used +-- for testing the model must be prepared in the same manner in order to +-- obtain meaningful results. +-- +-- 1. Missing Value treatment for all Predictors and +-- 2. Normalization +-- No outlier treatment will be performed during test and apply. The +-- normalization step is sufficient, since the normalization parameters +-- already capture the effects of outlier treatment done with build data. +-- +BEGIN + -- Xform Test data to replace missing values + DBMS_DATA_MINING_TRANSFORM.XFORM_MISS_NUM( + miss_table_name => 'svmc_sh_sample_miss_num', + data_table_name => 'mining_data_test_v', + xform_view_name => 'mining_data_test_miss'); + DBMS_DATA_MINING_TRANSFORM.XFORM_MISS_CAT( + miss_table_name => 'svmc_sh_sample_miss_cat', + data_table_name => 'mining_data_test_miss', + xform_view_name => 'mining_data_test'); + + -- Normalize Test data + DBMS_DATA_MINING_TRANSFORM.XFORM_NORM_LIN ( + norm_table_name => 'svmc_sh_sample_norm', + data_table_name => 'mining_data_test', + xform_view_name => 'svmc_sh_sample_test_prepared'); +END; +/ + +-- Cost matrix - not used here +-- It is possible to use a cost matrix on the apply results (see Naive +-- Bayes demo). However, for SVM we recommend that any known costs +-- be provided to the algorithm during build via the prior mechanism. +-- See discussion above on class weights table usage with SVM. +-- + +------------------------------------ +-- COMPUTE METRICS TO TEST THE MODEL +-- +-- The queries shown below demonstrate the use of new SQL data mining functions +-- along with analytic functions to compute various test metrics. In these +-- queries: +-- +-- Modelname: svmc_sh_clas_sample +-- # of Lift Quantiles: 10 +-- Target attribute: affinity_card +-- Positive target value: 1 +-- (Change these as appropriate for a different example) + +-- Compute CONFUSION MATRIX +-- +-- This query demonstates how to generate a confusion matrix using the new +-- SQL prediction functions for scoring. The returned columns match the +-- schema of the table generated by COMPUTE_CONFUSION_MATRIX procedure. +-- +SELECT affinity_card AS actual_target_value, + PREDICTION(svmc_sh_clas_sample USING *) AS predicted_target_value, + COUNT(*) AS value + FROM svmc_sh_sample_test_prepared + GROUP BY affinity_card, PREDICTION(svmc_sh_clas_sample USING *) + ORDER BY 1, 2; + +-- Compute ACCURACY +-- +column accuracy format 9.99 + +SELECT SUM(correct)/COUNT(*) AS accuracy + FROM (SELECT DECODE(affinity_card, + PREDICTION(svmc_sh_clas_sample USING *), 1, 0) AS correct + FROM svmc_sh_sample_test_prepared); + +-- Compute CUMULATIVE LIFT, GAIN Charts. +-- +-- The cumulative gain chart is a popular version of the lift chart, and +-- it maps cumulative gain (Y axis) against the cumulative records (X axis). +-- +-- The cumulative lift chart is another popular representation of lift, and +-- it maps cumulative lift (Y axis) against the cumulative records (X axis). +-- +-- The query also returns the probability associated with each quantile, so +-- that when the cut-off point for Lift is selected, you can correlate it +-- with a probability value (say P_cutoff). You can then use this value of +-- P_cutoff in a prediction query as follows: +-- +-- SELECT * +-- FROM records_to_be_scored +-- WHERE PREDICTION_PROBABILITY(svmc_sh_clas_sample, 1 USING *) > P_cutoff; +-- +-- In the query below +-- +-- q_num - Quantile Number +-- pos_cnt - # of records that predict the positive target +-- pos_prob - the probability associated with predicting a positive target +-- value for a given new record +-- cume_recs - % Cumulative Records upto quantile +-- cume_gain - % Cumulative Gain +-- cume_lift - Cumulative Lift +-- +WITH +pos_prob_and_counts AS ( +SELECT PREDICTION_PROBABILITY(svmc_sh_clas_sample, 1 USING *) pos_prob, + -- hit count for positive target value + DECODE(affinity_card, 1, 1, 0) pos_cnt + FROM svmc_sh_sample_test_prepared +), +qtile_and_smear AS ( +SELECT NTILE(10) OVER (ORDER BY pos_prob DESC) q_num, + pos_prob, + -- smear the counts across records with the same probability to + -- eliminate potential biased distribution across qtl boundaries + AVG(pos_cnt) OVER (PARTITION BY pos_prob) pos_cnt + FROM pos_prob_and_counts +), +cume_and_total_counts AS ( +SELECT q_num, + -- inner sum for counts within q_num groups, + -- outer sum for cume counts + MIN(pos_prob) pos_prob, + SUM(COUNT(*)) OVER (ORDER BY q_num) cume_recs, + SUM(SUM(pos_cnt)) OVER (ORDER BY q_num) cume_pos_cnt, + SUM(COUNT(*)) OVER () total_recs, + SUM(SUM(pos_cnt)) OVER () total_pos_cnt + FROM qtile_and_smear + GROUP BY q_num +) +SELECT pos_prob, + 100*(cume_recs/total_recs) cume_recs, + 100*(cume_pos_cnt/total_pos_cnt) cume_gain, + (cume_pos_cnt/total_pos_cnt)/(cume_recs/total_recs) cume_lift + FROM cume_and_total_counts + ORDER BY pos_prob DESC; + +-- Compute ROC CURVE +-- +-- This can be used to find the operating point for classification. +-- +-- The ROC curve plots true positive fraction - TPF (Y axis) against +-- false positive fraction - FPF (X axis). Note that the query picks +-- only the corner points (top tpf switch points for a given fpf) and +-- the last point. It should be noted that the query does not generate +-- the first point, i.e (tpf, fpf) = (0, 0). All of the remaining points +-- are computed, but are then filtered based on the criterion above. For +-- example, the query picks points a,b,c,d and not points o,e,f,g,h,i,j. +-- +-- The Area Under the Curve (next query) is computed using the trapezoid +-- rule applied to all tpf change points (i.e. summing up the areas of +-- the trapezoids formed by the points for each segment along the X axis; +-- (recall that trapezoid Area = 0.5h (A+B); h=> hieght, A, B are sides). +-- In the example, this means the curve covering the area would trace +-- points o,e,a,g,b,c,d. +-- +-- | +-- | .c .j .d +-- | .b .h .i +-- | .g +-- .a .f +-- .e +-- .__.__.__.__.__.__ +-- o +-- +column prob format 9.9999 +column fpf format 9.9999 +column tpf format 9.9999 + +WITH +pos_prob_and_counts AS ( +SELECT PREDICTION_PROBABILITY(svmc_sh_clas_sample, 1 USING *) pos_prob, + -- hit count for positive target value + DECODE(affinity_card, 1, 1, 0) pos_cnt + FROM svmc_sh_sample_test_prepared +), +cume_and_total_counts AS ( +SELECT pos_prob, + pos_cnt, + SUM(pos_cnt) OVER (ORDER BY pos_prob DESC) cume_pos_cnt, + SUM(pos_cnt) OVER () tot_pos_cnt, + SUM(1 - pos_cnt) OVER (ORDER BY pos_prob DESC) cume_neg_cnt, + SUM(1 - pos_cnt) OVER () tot_neg_cnt + FROM pos_prob_and_counts +), +roc_corners AS ( +SELECT MIN(pos_prob) pos_prob, + MAX(cume_pos_cnt) cume_pos_cnt, cume_neg_cnt, + MAX(tot_pos_cnt) tot_pos_cnt, MAX(tot_neg_cnt) tot_neg_cnt + FROM cume_and_total_counts + WHERE pos_cnt = 1 -- tpf switch points + OR (cume_pos_cnt = tot_pos_cnt AND -- top-right point + cume_neg_cnt = tot_neg_cnt) + GROUP BY cume_neg_cnt +) +SELECT pos_prob prob, + cume_pos_cnt/tot_pos_cnt tpf, + cume_neg_cnt/tot_neg_cnt fpf, + cume_pos_cnt tp, + tot_pos_cnt - cume_pos_cnt fn, + cume_neg_cnt fp, + tot_neg_cnt - cume_neg_cnt tn + FROM roc_corners + ORDER BY fpf; + +-- Compute AUC (Area Under the roc Curve) +-- +-- See notes on ROC Curve and AUC computation above +-- +column auc format 9.99 + +WITH +pos_prob_and_counts AS ( +SELECT PREDICTION_PROBABILITY(svmc_sh_clas_sample, 1 USING *) pos_prob, + DECODE(affinity_card, 1, 1, 0) pos_cnt + FROM svmc_sh_sample_test_prepared +), +tpf_fpf AS ( +SELECT pos_cnt, + SUM(pos_cnt) OVER (ORDER BY pos_prob DESC) / + SUM(pos_cnt) OVER () tpf, + SUM(1 - pos_cnt) OVER (ORDER BY pos_prob DESC) / + SUM(1 - pos_cnt) OVER () fpf + FROM pos_prob_and_counts +), +trapezoid_areas AS ( +SELECT 0.5 * (fpf - LAG(fpf, 1, 0) OVER (ORDER BY fpf, tpf)) * + (tpf + LAG(tpf, 1, 0) OVER (ORDER BY fpf, tpf)) area + FROM tpf_fpf + WHERE pos_cnt = 1 + OR (tpf = 1 AND fpf = 1) +) +SELECT SUM(area) auc + FROM trapezoid_areas; + +----------------------------------------------------------------------- +-- APPLY THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old scoring data preparation objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP VIEW mining_data_apply_miss'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW mining_data_apply'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW svmc_sh_sample_apply_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +----------------------- +-- PREPARE SCORING DATA +-- +-- If the data for model creation has been prepared, then the data +-- to be scored using the model must be prepared in the same manner +-- in order to obtain meaningful results. +-- +-- 1. Missing Value treatment for all Predictors and +-- 2. Normalization +-- No outlier treatment will be performed during test and apply. The +-- normalization step is sufficient, since the normalization parameters +-- already capture the effects of outlier treatment done with build data. +-- +BEGIN + -- Xform Test data to replace missing values + DBMS_DATA_MINING_TRANSFORM.XFORM_MISS_NUM( + miss_table_name => 'svmc_sh_sample_miss_num', + data_table_name => 'mining_data_apply_v', + xform_view_name => 'mining_data_apply_miss'); + DBMS_DATA_MINING_TRANSFORM.XFORM_MISS_CAT( + miss_table_name => 'svmc_sh_sample_miss_cat', + data_table_name => 'mining_data_apply_miss', + xform_view_name => 'mining_data_apply'); + + -- Normalize the data to be scored + DBMS_DATA_MINING_TRANSFORM.XFORM_NORM_LIN ( + norm_table_name => 'svmc_sh_sample_norm', + data_table_name => 'mining_data_apply', + xform_view_name => 'svmc_sh_sample_apply_prepared'); +END; +/ + +------------------------------------------------- +-- SCORE NEW DATA USING SQL DATA MINING FUNCTIONS +-- +-- Note that APPLY results do not need to be reverse transformed, as done +-- in the case of model details. This is because class values of a +-- classification target were not (required to be) binned or normalized. +-- +------------------ +-- BUSINESS CASE 1 +-- Find the 10 customers who live in Italy that are most likely +-- to use an affinity card. +-- +SELECT cust_id + FROM (SELECT cust_id + FROM svmc_sh_sample_apply_prepared + WHERE country_name = 'Italy' + ORDER BY PREDICTION_PROBABILITY(svmc_sh_clas_sample, 1 USING *) DESC, 1) +WHERE ROWNUM < 11; + +------------------ +-- BUSINESS CASE 2 +-- Find the average age of customers who are likely to use an +-- affinity card. Break out the results by gender. +-- +SELECT cust_gender, + COUNT(*) AS cnt, + ROUND(AVG(age)) AS avg_age + FROM svmc_sh_sample_apply_prepared + WHERE PREDICTION(svmc_sh_clas_sample USING *) = 1 +GROUP BY cust_gender +ORDER BY cust_gender; + +------------------ +-- BUSINESS CASE 3 +-- List ten customers (ordered by their id) along with their likelihood to +-- use or reject the affinity card (Note: while this example has a +-- binary target, such a query is useful in multi-class classification - +-- Low, Med, High for example). +-- +SELECT T.cust_id, S.prediction, S.probability + FROM (SELECT cust_id, + PREDICTION_SET(svmc_sh_clas_sample USING *) pset + FROM svmc_sh_sample_apply_prepared + WHERE cust_id < 100011) T, + TABLE(T.pset) S +ORDER BY cust_id, S.prediction; + +------------------ +-- BUSINESS CASE 4 +-- Find customers whose profession is Tech Support +-- with > 75% likelihood of using the affinity card +-- +SELECT cust_id + FROM svmc_sh_sample_apply_prepared + WHERE PREDICTION_PROBABILITY(svmc_sh_clas_sample, 1 USING *) > 0.75 + AND occupation = 'TechSup' +ORDER BY cust_id; + diff --git a/dmsvcdemo.java b/dmsvcdemo.java new file mode 100644 index 0000000..4ec2c4c --- /dev/null +++ b/dmsvcdemo.java @@ -0,0 +1,770 @@ +// Copyright (c) 2004, 2008, Oracle. All rights reserved. +// File: dmsvcdemo.java +import java.math.BigDecimal; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.Statement; + +import java.text.DecimalFormat; +import java.text.MessageFormat; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.MiningAlgorithm; +import javax.datamining.MiningFunction; +import javax.datamining.NamedObject; +import javax.datamining.algorithm.svm.KernelFunction; +import javax.datamining.algorithm.svm.classification.SVMClassificationSettings; +import javax.datamining.algorithm.svm.classification.SVMClassificationSettingsFactory; +import javax.datamining.base.AlgorithmSettings; +import javax.datamining.base.Model; +import javax.datamining.base.Task; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.CategorySet; +import javax.datamining.data.ModelSignature; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.data.SignatureAttribute; +import javax.datamining.modeldetail.svm.SVMClassificationModelDetail; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.supervised.classification.ClassificationApplySettings; +import javax.datamining.supervised.classification.ClassificationApplySettingsFactory; +import javax.datamining.supervised.classification.ClassificationModel; +import javax.datamining.supervised.classification.ClassificationSettings; +import javax.datamining.supervised.classification.ClassificationSettingsFactory; +import javax.datamining.supervised.classification.ClassificationTestMetrics; +import javax.datamining.supervised.classification.ClassificationTestTask; +import javax.datamining.supervised.classification.ClassificationTestTaskFactory; +import javax.datamining.supervised.classification.ConfusionMatrix; +import javax.datamining.supervised.classification.Lift; +import javax.datamining.supervised.classification.ReceiverOperatingCharacterics; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; +import javax.datamining.task.apply.DataSetApplyTask; +import javax.datamining.task.apply.DataSetApplyTaskFactory; + +import oracle.dmt.jdm.algorithm.svm.classification.OraSVMClassificationSettings; +import oracle.dmt.jdm.base.OraBuildSettings; +import oracle.dmt.jdm.base.OraTask; +import oracle.dmt.jdm.modeldetail.svm.OraSVMClassificationModelDetail; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.supervised.classification.OraClassificationModel; +import oracle.dmt.jdm.supervised.classification.OraLift; + +/** + * This demo program describes how to use the Oracle Data Mining (ODM) Java API + * to solve a classification problem using Support Vector Machines (SVM) + * algorithm. + * ------------------------------------------------------------------------------ + * PROBLEM DEFINITION + * ------------------------------------------------------------------------------ + * How to predict whether a customer responds or not to the new affinity card + * program using a classifier based on SVM algorithm? + * ------------------------------------------------------------------------------ + * DATA DESCRIPTION + * ------------------------------------------------------------------------------ + * Data for this demo is composed from base tables in the Sales History (SH) + * Schema. The SH schema is an Oracle Database Sample Schema that has the customer + * demographics, purchasing, and response details for the previous affinity card + * programs. Data exploration and preparing the data is a common step before + * doing data mining. Here in this demo, the following views are created in the user + * schema using CUSTOMERS, COUNTRIES, and SUPPLIMENTARY_DEMOGRAPHICS tables. + * + * MINING_DATA_BUILD_V: + * This view collects the previous customers' demographics, purchasing, and affinity + * card response details for building the model. + * + * MINING_DATA_TEST_V: + * This view collects the previous customers' demographics, purchasing, and affinity + * card response details for testing the model. + * + * MINING_DATA_APPLY_V: + * This view collects the prospective customers' demographics and purchasing + * details for predicting response for the new affinity card program. + * + * ------------------------------------------------------------------------------ + * DATA MINING PROCESS + * ------------------------------------------------------------------------------ + * Build Model: + * Mining Model is the prime object in data mining. The buildModel() method + * illustrates how to build a classification model using SVM algorithm. + * + * Test Model: + * Classification models' performance can be evaluated by computing test + * metrics like accuracy, confusion matrix, lift and ROC. The testModel() or + * computeTestMetrics() method illustrates how to perform a test operation to + * compute various metrics. + * + * Apply Model: + * Predicting the target attribute values is the prime function of + * classification models. The applyModel() method illustrates how to + * predict the customer response for an affinity card program. + * ------------------------------------------------------------------------------ + * EXECUTING DEMO PROGRAM + * ------------------------------------------------------------------------------ + * Refer to Oracle Data Mining Administrator's Guide + * for guidelines for executing this demo program. + */ + +public class dmsvcdemo extends Object { + // Connection related data members + private static javax.datamining.resource.Connection m_dmeConn; + private static javax.datamining.resource.ConnectionFactory m_dmeConnFactory; + // Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static ClassificationSettingsFactory m_clasFactory; + private static SVMClassificationSettingsFactory m_svmcFactory; + private static BuildTaskFactory m_buildFactory; + private static DataSetApplyTaskFactory m_dsApplyFactory; + private static ClassificationTestTaskFactory m_testFactory; + private static ClassificationApplySettingsFactory m_applySettingsFactory; + // Global constants + private static DecimalFormat m_df = new DecimalFormat("##.####"); + private static boolean displayModelDeatils = false;//By default it is set to false. To view the details of the model this flag can be enabled + + + public static void main( String args[] ) { + try { + if (( args.length != 0 ) & ( args.length != 3 )) { + System.out.println("Usage: java dmsvcdemo "); + System.out.println(" or: java dmsvcdemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + // 1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@"+uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Build a model with supplied prior probability + buildModel(); + // 5. Test model - To compute accuracy and confusion matrix, lift result + // and ROC for the model. + testModel(); + // 6. Apply the model + applyModel(); + // 7. Start execution of the first task in the sequnece + m_dmeConn.execute("svmcBuildTask_jdm"); + // 8. Monitor and display results (if any) + monitorTaskExecutionProcess(); + + } catch(Exception anyExp) { + anyExp.printStackTrace(System.out); + } finally { + try { + // 8. Logout from the Data Mining Engine + m_dmeConn.close(); + } catch(Exception anyExp1) { } // Ignore + } + } + + /** + * Initialize all object factories used in the demo program. + * + * @exception JDMException if factory initalization failed + */ + public static void initFactories() throws JDMException + { + m_pdsFactory = (PhysicalDataSetFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalDataSet"); + m_paFactory = (PhysicalAttributeFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalAttribute"); + m_clasFactory = (ClassificationSettingsFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationSettings"); + m_svmcFactory = (SVMClassificationSettingsFactory)m_dmeConn.getFactory( + "javax.datamining.algorithm.svm.classification.SVMClassificationSettings"); + m_buildFactory = (BuildTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.BuildTask"); + m_testFactory = (ClassificationTestTaskFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationTestTask"); + m_dsApplyFactory = (DataSetApplyTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.apply.DataSetApplyTask"); + m_applySettingsFactory = (ClassificationApplySettingsFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationApplySettings"); + } + + /** + * This method illustrates how to build mining model using + * MINING_DATA_BUILD_V dataset and classification settings with + * SVM algorithm. + * + * By default SVM algorithm chooses an kernel type automatically. This + * choice can be overriden by the user. Linear kernel is preferred high + * dimensional data, and Gaussian kernel for low dimensional data. Here we use + * linear kernel to demonstrate the getModelDetail() API, which applies only + * for models. + * + * @exception JDMException if model build failed + */ + public static void buildModel() throws JDMException + { + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = + m_pdsFactory.create("MINING_DATA_BUILD_V", false); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + buildData.addAttribute(pa); + m_dmeConn.saveObject("svmcBuildData_jdm", buildData, true); + // 2. Create & save Mining Function Settings + // Create SVMC algorithm settings + SVMClassificationSettings svmcAlgo = m_svmcFactory.create(); + svmcAlgo.setKernelFunction(KernelFunction.kLinear); + // Examples settings are: + // svmcAlgo.setKernelFunction(KernelFunction.kGaussian); + // svmcAlgo.setComplexityFactor(0.01f); + // svmcAlgo.setTolerance(0.01f); + // + //Create ClassificationSettings + ClassificationSettings buildSettings = m_clasFactory.create(); + buildSettings.setAlgorithmSettings(svmcAlgo); + buildSettings.setTargetAttributeName("AFFINITY_CARD"); + // + // Set target prior probabilities. + // + // A priors table is used to influence the weighting of target classes + // during model creation. SVM's usage of priors is different from the + // priors interpretation in probabilistic models. In probabilistic models, + // priors can be used to correct for biased sampling procedures. Instead, + // in SVM priors act as a weight vector that biases optimization and favors + // one class over the other. For example, priors of (0.9, 0.1) for a binary + // problem specify that an error in the first class has significantly + // higher penalty that an error in the second class. Priors of (0.5, 0.5) + // do not introduce a differential weight and would produce the same + // model as when no priors are provided. + Map priorMap = new HashMap(); + priorMap.put(new Double(0), new Double(0.35)); + priorMap.put(new Double(1), new Double(0.65)); + buildSettings.setPriorProbabilitiesMap("AFFINITY_CARD", priorMap); + //Set auto data preparation on + ((OraBuildSettings)buildSettings).useAutomatedDataPreparations(true); + m_dmeConn.saveObject("svmcBuildSettings_jdm", buildSettings, true); + // 3. Create, save & execute Build Task + BuildTask buildTask = m_buildFactory.create( + "svmcBuildData_jdm", //Build data specification + "svmcBuildSettings_jdm", //Mining function settings name + "svmcModel_jdm" //Mining model name + ); + buildTask.setDescription("svmcBuildTask_jdm"); + saveTask(buildTask, "svmcBuildTask_jdm", null); + } + + + /** + * This method illustrates how to compute test metrics using + * MINING_DATA_TEST_V dataset and ClassificationTestTask. + * @exception JDMException if model test failed + */ + public static void testModel() throws JDMException + { + // 1. Do the apply on test data to create an apply output table + // Create & save PhysicalDataSpecification + PhysicalDataSet applyData = m_pdsFactory.create( + "MINING_DATA_TEST_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "svmcTestData_jdm", applyData, true ); + + // 5. Create a ClassificationTestTask + ClassificationTestTask testTask = m_testFactory.create( + "svmcTestData_jdm", "svmcModel_jdm", "svcTestMetrics_jdm" ); + testTask.setPositiveTargetValue(new Integer(1)); + testTask.setNumberOfLiftQuantiles(10); + // 6. Store & execute the task + saveTask(testTask, "svmcTestTask_jdm", "svmcBuildTask_jdm"); + } + + /** + * This method illustrates how to apply the mining model on the + * MINING_DATA_APPLY_V dataset to predict customer + * response. After completion of the task, the apply output table with the + * predicted results is created at the user specified location. + * + * @exception JDMException if model apply failed + */ + public static void applyModel() throws JDMException + { + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = m_pdsFactory.create( + "MINING_DATA_APPLY_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "svmcApplyData_jdm", applyData, true ); + // 2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + m_dmeConn.saveObject( "svmcApplySettings_jdm", clasAS, true); + // 3. Create, store & execute apply Task + DataSetApplyTask applyTask = m_dsApplyFactory.create( + "svmcApplyData_jdm", "svmcModel_jdm", + "svmcApplySettings_jdm", "SVMC_APPLY_OUTPUT_JDM"); + saveTask(applyTask, "svmcApplyTask_jdm", "svmcBuildTask_jdm" ); + } + + /** + * This method saves the given task with the specified task name and task + * dependency (parent task) in the DME. + * + * @param taskObj task object + * @param taskName name of the task + * @param parentTaskName name of the parent task + * + * @return boolean returns true when the task is successful + * @exception JDMException if task execution failed + */ + public static void saveTask(Task taskObj, String taskName, + String parentTaskName) + throws JDMException + { + if (parentTaskName != null) + ((OraTask) taskObj).addDependency(parentTaskName); //Since OJDM 11.1 + ((OraTask) taskObj).overwriteOutput(true); //Since OJDM 11.1 + m_dmeConn.saveObject(taskName, taskObj, true); + } + + /** + * This method monitor task execution initiated by the first task + * in the sequence of dependent tasks. In addition, this method displays + * task output results (if any). + * @throws JDMException + */ + public static void monitorTaskExecutionProcess() + throws JDMException + { + //BuildTask + System.out.println("---------------------------------------------------"); + System.out.println("--- Build Model ---"); + System.out.println("---------------------------------------------------"); + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of svmcBuildTask_jdm. "); + ExecutionStatus buildTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("svmcBuildTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(buildTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + // 3. Restore the model from the data mining server + ClassificationModel model = + (ClassificationModel) m_dmeConn.retrieveObject("svmcModel_jdm", + NamedObject.model); + // 4. Explore the details of the restored model + // Display model build settings + ClassificationSettings retrievedBuildSettings = + (ClassificationSettings) model.getBuildSettings(); + if (retrievedBuildSettings == null) + System.out.println("Failure to restore build settings."); + else + displayBuildSettings(retrievedBuildSettings, + "svmcBuildSettings_jdm"); + // Display model signature + displayModelSignature((Model)model); + if(displayModelDeatils) + displaySVMCModelDetails((Model)model); + + System.out.println("---------------------------------------------------"); + System.out.println("--- Test Model ---"); + System.out.println("---------------------------------------------------"); + + //If model build is successful, then do testData ApplyTask + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of svmcTestTask_jdm. "); + ExecutionStatus testTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("svmcTestTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(testTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + // Restore & display test metrics + ClassificationTestMetrics testMetrics = + (ClassificationTestMetrics) m_dmeConn.retrieveObject("svcTestMetrics_jdm", + NamedObject.testMetrics); + // Display classification test metrics + displayTestMetricDetails(testMetrics); + } + else + { + System.out.println("It is at state:" + + testTaskCompletionStatus.getState().name() + + ((testTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + testTaskCompletionStatus.getDescription())); + } + //ApplyTask(s) + //Waiting for apply task to complete + System.out.println("---------------------------------------------------"); + System.out.println("--- Apply Model ---"); + System.out.println("---------------------------------------------------"); + + ExecutionStatus applyTaskStatus = + m_dmeConn.getLastExecutionHandle("svmcApplyTask_jdm").waitForCompletion(Integer.MAX_VALUE); + if (ExecutionState.success.equals(applyTaskStatus.getState())) + { + // Display apply result -- Note that APPLY results do not need to be + // reverse transformed, as done in the case of model details. This is + // because class values of a classification target were not (required to + // be) binned or normalized. + displayTable("SVMC_APPLY_OUTPUT_JDM", "where ROWNUM < 11", + "order by CUST_ID"); + } + else + { + System.out.println("svmcApplyTask_jdm is at state:" + + applyTaskStatus.getState().name() + + ((applyTaskStatus.getDescription() == null)? + "": + "State Description:" + applyTaskStatus.getDescription())); + } + } + else + { + System.out.println("It is at state:" + + buildTaskCompletionStatus.getState().name() + + ((buildTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + buildTaskCompletionStatus.getDescription())); + } + + } + + private static void displayBuildSettings( + ClassificationSettings clasSettings, String buildSettingsName) + { + // Display build settings table + System.out.println("BuildSettings Details from the " + + buildSettingsName + " table:"); + displayTable(buildSettingsName, "", "order by SETTING_NAME"); + // Display build settings object obtained from the model + System.out.println("BuildSettings Details from the " + + buildSettingsName + " model build settings object:"); + String objName = clasSettings.getName(); + if(objName != null) + System.out.println("Name = " + objName); + String objDescription = clasSettings.getDescription(); + if(objDescription != null) + System.out.println("Description = " + objDescription); + java.util.Date creationDate = clasSettings.getCreationDate(); + String creator = clasSettings.getCreatorInfo(); + String targetAttrName = clasSettings.getTargetAttributeName(); + System.out.println("Target attribute name = " + targetAttrName); + AlgorithmSettings algoSettings = clasSettings.getAlgorithmSettings(); + if(algoSettings == null) + System.out.println("Failure: clasSettings.getAlgorithmSettings() returns null"); + MiningAlgorithm algo = algoSettings.getMiningAlgorithm(); + if(algo == null) System.out.println("Failure: algoSettings.getMiningAlgorithm() returns null"); + System.out.println("Algorithm Name: " + algo.name()); + MiningFunction function = clasSettings.getMiningFunction(); + if(function == null) System.out.println("Failure: clasSettings.getMiningFunction() returns null"); + System.out.println("Function Name: " + function.name()); + try { + Map map = clasSettings.getPriorProbabilitiesMap(targetAttrName); + if(map != null) System.out.println("Priors Map: " + map.toString()); + } catch(Exception jdmExp) + { + System.out.println("Failure: clasSettings.getPriorProbabilitiesMap(targetAttrName)throws exception"); + jdmExp.printStackTrace(); + } + // List of SVM algorithm settings availabe in linear kernel + KernelFunction kernelFunction = ((OraSVMClassificationSettings)algoSettings).getKernelFunction(); + System.out.println("Kernel Function: " + kernelFunction.name()); + double doubleValue = ((OraSVMClassificationSettings)algoSettings).getComplexityFactor(); + System.out.println("Complexity Factor: " + m_df.format(doubleValue)); + doubleValue = ((OraSVMClassificationSettings)algoSettings).getTolerance(); + System.out.println("Tolerance: " + m_df.format(doubleValue)); + boolean enable = ((OraSVMClassificationSettings)algoSettings).getActiveLearning(); + System.out.println("Is Active Learning enabled? " + enable); + } + + /** + * This method displayes SVMC model signature. + * + * @param model model object + * @exception JDMException if failed to retrieve model signature + */ + public static void displayModelSignature(Model model) throws JDMException + { + String modelName = model.getName(); + System.out.println("Model Name: " + modelName); + ModelSignature modelSignature = model.getSignature(); + System.out.println("Model Signature: ( Attribute Name, Attribute Type )"); + MessageFormat mfSign = new MessageFormat(" ( {0}, {1} )"); + String[] vals = new String[2]; + Collection sortedSet = modelSignature.getAttributes(); + Iterator attrIterator = sortedSet.iterator(); + while(attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute)attrIterator.next(); + vals[0] = attr.getName(); + vals[1] = attr.getDataType().name(); + System.out.println( mfSign.format(vals) ); + } + } + + /** + * This method displayes SVMC model details. The coefficient indicates the + * relative influence of a given (attribute, value) pair on the target value. + * A negative coefficient value indicates a negative influence. + * + * @param svmcModelDetails svm classification model details object + * @exception JDMException if failed to retrieve model details + */ + public static void displaySVMCModelDetails( + Model model) throws JDMException + { + // Obtains model details + SVMClassificationModelDetail svmcModelDetails = + (SVMClassificationModelDetail)model.getModelDetail(); + // Is linear model? + System.out.println("Is linear model? " + svmcModelDetails.isLinearSVMModel() ); + // Available targets + CategorySet targetSet = ((OraClassificationModel)model).getTargetCategorySet(); + Object[] targets = targetSet.getValues(); + // Attribute coefficient value will be available if it is a linear model + if (svmcModelDetails.isLinearSVMModel()) + { + System.out.println("Model Deatils: ( Target Value, Attribute Name, Attribute Value, Coefficient)"); + MessageFormat mfDetails = new MessageFormat(" ( {0}, {1}, {2}, {3} )"); + String[] vals = new String[4]; + for (int row =0; row < targets.length; row++) + { + // Print bias of the current target value by invoking getBias method. + vals[0] =(String) targets[row].toString(); + vals[1] = ""; + vals[2] = ""; + vals[3] = m_df.format(svmcModelDetails.getBias(targets[row])) + " (Bias)"; + System.out.println( mfDetails.format(vals) ); + //Get the signature attributes + ModelSignature modelSignature = model.getSignature(); + Collection sortedSet = modelSignature.getAttributes(); + Iterator attrIterator = sortedSet.iterator(); + + while(attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute)attrIterator.next(); + // Print all attribute coefficients -- The FIRST row in the SVM model + // details output shows the value for SVM bias under the COEFFICIENT + // column. + Map attrCoefficientMap = ((OraSVMClassificationModelDetail)svmcModelDetails).getCoefficients(targets[row],attr.getName()); + Object[] attrVals = attrCoefficientMap.keySet().toArray(); + if(attrVals != null) { + for(int iAttr=0; iAttr < attrVals.length; iAttr++) + { + vals[1] = attr.getName(); + vals[2] = ""; + if(attrVals[iAttr] != null) + vals[2] = attrVals[iAttr].toString(); + vals[3] = ""; + Number coefficient = (Number)attrCoefficientMap.get(attrVals[iAttr]); + if(coefficient != null) + vals[3] = m_df.format(coefficient); + System.out.println( mfDetails.format(vals) ); + } + } + } + } + } + } + + /** + * Display classification test metrics object + * + * @param testMetrics classification test metrics object + * @exception JDMException if failed to retrieve test metric details + */ + public static void displayTestMetricDetails( + ClassificationTestMetrics testMetrics) throws JDMException + { + // Retrieve Oracle SVMC model test metrics deatils extensions + // Test Metrics Name + System.out.println("Test Metrics Name = " + testMetrics.getName()); + // Model Name + System.out.println("Model Name = " + testMetrics.getModelName()); + // Test Data Name + System.out.println("Test Data Name = " + testMetrics.getTestDataName()); + // Accuracy + System.out.println("Accuracy = " + m_df.format(testMetrics.getAccuracy().doubleValue())); + // Confusion Matrix + ConfusionMatrix confusionMatrix = testMetrics.getConfusionMatrix(); + Collection categories = confusionMatrix.getCategories(); + Iterator xIterator = categories.iterator(); + System.out.println("Confusion Matrix: Accuracy = " + m_df.format(confusionMatrix.getAccuracy())); + System.out.println("Confusion Matrix: Error = " + m_df.format(confusionMatrix.getError())); + System.out.println("Confusion Matrix:( Actual, Prection, Value )"); + MessageFormat mf = new MessageFormat(" ( {0}, {1}, {2} )"); + String[] vals = new String[3]; + while(xIterator.hasNext()) + { + Object actual = xIterator.next(); + vals[0] = actual.toString(); + Iterator yIterator = categories.iterator(); + while(yIterator.hasNext()) + { + Object predicted = yIterator.next(); + vals[1] = predicted.toString(); + long number = confusionMatrix.getNumberOfPredictions(actual, predicted); + vals[2] = Long.toString(number); + System.out.println(mf.format(vals)); + } + } + // Lift + Lift lift = testMetrics.getLift(); + System.out.println("Lift Details:"); + System.out.println("Lift: Target Attribute Name = " + lift.getTargetAttributeName()); + System.out.println("Lift: Positive Target Value = " + lift.getPositiveTargetValue()); + System.out.println("Lift: Total Cases = " + lift.getTotalCases()); + System.out.println("Lift: Total Positive Cases = " + lift.getTotalPositiveCases()); + int numberOfQuantiles = lift.getNumberOfQuantiles(); + System.out.println("Lift: Number Of Quantiles = " + numberOfQuantiles); + System.out.println("Lift: ( QUANTILE_NUMBER, TOTAL_CASES, QUANTILE_PERCENT_SIZE, POSITIVE_CASES, NEGATIVE_CASES, PROBABILITY_THRESHOLD, LIFT, CUMULATIVE_LIFT, GAIN, CUMULATIVE_GAIN, TARGET_DENSITY, CUMULATIVE_TARGET_DENSITY)"); + MessageFormat mfLift = + new MessageFormat(" ( {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10} )"); + double[] totalCasesPerQuantile = ((OraLift)lift).getCases();//Total cases per quantile + double[] quantilePercentageSize = ((OraLift)lift).getPercentageSize();//Quantile pecentage size + double[] positiveCasesPerQuantile = ((OraLift)lift).getNumberOfPositiveCases();//Positive target cases per quantile + double[] negativeCasesPerQuantile = ((OraLift)lift).getNumberOfNegativeCases();//Negative target cases per quantile + double[] probabilityOrCostThresholdPerQuantile = ((OraLift)lift).getProbabilityOrCostThreshold();//Probability or cost threshold per quantile + double[] liftPerQuantile = ((OraLift)lift).getLift();//Lift values for all quantiles + double[] targetDensityPerQuantile = ((OraLift)lift).getTargetDensity();//Target densities per quantile + + double[] cumulativeLift = ((OraLift)lift).getCumulativeLift(); + double[] cumulativeGain = ((OraLift)lift).getCumulativeGain(); + double[] cumulativeTargetDensity = ((OraLift)lift).getCumulativeTargetDensity(); + + + + String[] messageParams = new String[11]; + + for (int iQuantile = 0; iQuantile < numberOfQuantiles; iQuantile++) + { + //Assign message parameters + messageParams[0] = Integer.toString(iQuantile+1); //QUANTILE_NUMBER + messageParams[1] = m_df.format(totalCasesPerQuantile[iQuantile]); //TOTAL_CASES + messageParams[2] = m_df.format(quantilePercentageSize[iQuantile]);//QUANTILE_PERCENT_SIZE + messageParams[3] = m_df.format(positiveCasesPerQuantile[iQuantile]); //POSITIVE_CASES + messageParams[4] = m_df.format(negativeCasesPerQuantile[iQuantile]); //NEGATIVE_CASES + messageParams[5] = m_df.format(probabilityOrCostThresholdPerQuantile[iQuantile]); //PROBABILITY_THRESHOLD + messageParams[6] = m_df.format(liftPerQuantile[iQuantile]); //LIFT + messageParams[7] = m_df.format(cumulativeLift[iQuantile]); //CUMULATIVE_LIFT + messageParams[8] = m_df.format(cumulativeGain[iQuantile]); //CUMULATIVE_GAIN + messageParams[9] = m_df.format(targetDensityPerQuantile[iQuantile]); //TARGET_DENSITY + messageParams[10] = m_df.format(cumulativeTargetDensity[iQuantile]); //CUMULATIVE_TARGET_DENSITY + System.out.println(mfLift.format(messageParams)); + } + // ROC + ReceiverOperatingCharacterics roc = testMetrics.getROC(); + System.out.println("ROC Details:"); + System.out.println("ROC: Area Under Curve = " + m_df.format(roc.getAreaUnderCurve())); + int nROCThresh = roc.getNumberOfThresholdCandidates(); + System.out.println("ROC: Number Of Threshold Candidates = " + nROCThresh); + System.out.println("ROC: ( INDEX, PROBABILITY, TRUE_POSITIVES, FALSE_NEGATIVES, FALSE_POSITIVES, TRUE_NEGATIVES, TRUE_POSITIVE_FRACTION, FALSE_POSITIVE_FRACTION )"); + MessageFormat mfROC = new MessageFormat(" ( {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7} )"); + String[] rocVals = new String[8]; + for(int iROC=1; iROC <= nROCThresh; iROC++) + { + rocVals[0] = Integer.toString(iROC); //INDEX + rocVals[1] = m_df.format(roc.getProbabilityThreshold(iROC));//PROBABILITY + rocVals[2] = Long.toString(roc.getPositives(iROC, true));//TRUE_POSITIVES + rocVals[3] = Long.toString(roc.getNegatives(iROC, false));//FALSE_NEGATIVES + rocVals[4] = Long.toString(roc.getPositives(iROC, false));//FALSE_POSITIVES + rocVals[5] = Long.toString(roc.getNegatives(iROC, true));//TRUE_NEGATIVES + rocVals[6] = m_df.format(roc.getHitRate(iROC));//TRUE_POSITIVE_FRACTION + rocVals[7] = m_df.format(roc.getFalseAlarmRate(iROC));//FALSE_POSITIVE_FRACTION + System.out.println(mfROC.format(rocVals)); + } + } + + private static void displayTable(String tableName, String whereCause, String orderByColumn) + { + StringBuffer emptyCol = new StringBuffer(" "); + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + PreparedStatement pStmt = null; + ResultSet rs = null; + try + { + pStmt = dbConn.prepareStatement("SELECT * FROM " + tableName + " " + whereCause + " " + orderByColumn); + rs = pStmt.executeQuery(); + ResultSetMetaData rsMeta = rs.getMetaData(); + int colCount = rsMeta.getColumnCount(); + StringBuffer header = new StringBuffer(); + System.out.println("Table : " + tableName); + // Build table header + for(int iCol=1; iCol<=colCount; iCol++) + { + String colName = rsMeta.getColumnName(iCol); + header.append(emptyCol.replace(0, colName.length(), colName)); + emptyCol = new StringBuffer(" "); + } + System.out.println(header.toString()); + // Write table data + while(rs.next()) + { + StringBuffer rowContent = new StringBuffer(); + for(int iCol=1; iCol<=colCount; iCol++) + { + int sqlType = rsMeta.getColumnType(iCol); + Object obj = rs.getObject(iCol); + String colContent = null; + + if(obj instanceof java.lang.Number) + { + try + { + BigDecimal bd = (BigDecimal)obj; + if(bd.scale() > 5) + { + colContent = m_df.format(obj); + } else + { + colContent = bd.toString(); + } + } catch(Exception anyExp) { + colContent = m_df.format(obj); + } + } else + { + if(obj == null) + colContent = "NULL"; + else + colContent = obj.toString(); + } + rowContent.append(" "+emptyCol.replace(0, colContent.length(), colContent)); + emptyCol = new StringBuffer(" "); + } + System.out.println(rowContent.toString()); + } + } catch(Exception anySqlExp) { + anySqlExp.printStackTrace(); + } // Ignore + } + + private static void clean() + { + //Drop the model + try { + m_dmeConn.removeObject("svmcModel_jdm", NamedObject.model); + } catch(JDMException jdmExp) {} + + } +} + diff --git a/dmsvodem.sql b/dmsvodem.sql new file mode 100644 index 0000000..3c16d2e --- /dev/null +++ b/dmsvodem.sql @@ -0,0 +1,264 @@ +Rem +Rem $Header: dmsvodem.sql 25-oct-2007.11:34:45 ramkrish Exp $ +Rem +Rem dmsvodem.sql +Rem +Rem Copyright (c) 2004, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmsvodem.sql - Sample program for the DBMS_DATA_MINING package. +Rem +Rem DESCRIPTION +Rem This script creates an anomaly detection model +Rem for data analysis and outlier identification using the +Rem one-class SVM algorithm +Rem and data in the SH (Sales History)schema in the RDBMS. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ramkrish 06/14/07 - remove commit after settings +Rem ramkrish 10/25/07 - replace deprecated get_model calls with catalog +Rem queries +Rem ktaylor 07/11/05 - minor edits to comments +Rem jcjeon 01/18/05 - add column format +Rem bmilenov 10/28/04 - bmilenov_oneclass_demo +Rem bmilenov 10/25/04 - Remove dbms_output statements +Rem bmilenov 10/22/04 - Comment revision +Rem bmilenov 10/20/04 - Created +Rem + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET echo ON + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM +----------------------------------------------------------------------- +-- Given demographics about a set of customers that are known to have +-- an affinity card, 1) find the most atypical members of this group +-- (outlier identification), 2) discover the common demographic +-- characteristics of the most typical customers with affinity card, +-- and 3) compute how typical a given new/hypothetical customer is. +-- +------- +-- DATA +------- +-- The data for this sample is composed from base tables in the SH schema +-- (See Sample Schema Documentation) and presented through a view: +-- mining_data_one_class_v +-- (See dmsh.sql for view definition). +-- +-- + +----------------------------------------------------------------------- +-- BUILD THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old build data preparation objects, if any +BEGIN + EXECUTE IMMEDIATE 'DROP TABLE svmo_sh_sample_norm'; + EXECUTE IMMEDIATE 'DROP VIEW svmo_sh_sample_prepared'; +EXCEPTION WHEN OTHERS THEN + NULL; +END; +/ +-- Cleanup old model with the same name (if any) +BEGIN DBMS_DATA_MINING.DROP_MODEL('SVMO_SH_Clas_sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-------------------------------- +-- PREPARE DATA +-- + +-- 1. Missing Value treatment for all Predictors +-- This is an optional step. Missing value imputation is recommended +-- when the fraction of missing at random values is high. Sparse data +-- representation where missing values encode 0 (non-present) should +-- be left as it is. +-- For numerical attributes, if z-score normalization is applied, the +-- missing value treatment step can be skipped. +-- For missing value treatment sample code see dmsvcdem.sql. +-- +-- 2. Outlier Treatment +-- This is an optional step. Large outlier values in individual attributes +-- can result in sub-optimal normalization ouput and sub-optimal models. +-- For outlier treatment sample code see dmsvcdem.sql. +-- +-- 3. Normalization +-- Normalization brings all numeric attributes on a similar scale. Unless +-- there are reasons for weighting individual attributes differently, +-- this step is strongly recommended. In the presence of numeric only +-- attributes either min_max or z-score normalization can be used. If the +-- dataset has both numeric and categorical attributes, min_max +-- normalization is preferred. +-- +BEGIN + -- Normalize numerical attributes: AGE, YRS_RESIDENCE + -- CUST_ID is the record unique identifier and therefore excluded + -- from normalization + -- Create normalization specification + DBMS_DATA_MINING_TRANSFORM.CREATE_NORM_LIN ( + norm_table_name => 'svmo_sh_sample_norm'); + + DBMS_DATA_MINING_TRANSFORM.INSERT_NORM_LIN_MINMAX ( + norm_table_name => 'svmo_sh_sample_norm', + data_table_name => 'mining_data_one_class_v', + exclude_list => DBMS_DATA_MINING_TRANSFORM.COLUMN_LIST ( + 'cust_id')); + + -- Create the transformed view + DBMS_DATA_MINING_TRANSFORM.XFORM_NORM_LIN ( + norm_table_name => 'svmo_sh_sample_norm', + data_table_name => 'mining_data_one_class_v', + xform_view_name => 'svmo_sh_sample_prepared'); + +END; +/ + +------------------- +-- SPECIFY SETTINGS +-- +-- Cleanup old settings table (if any) +BEGIN + EXECUTE IMMEDIATE 'DROP TABLE svmo_sh_sample_settings'; +EXCEPTION WHEN OTHERS THEN + NULL; +END; +/ + +-- CREATE AND POPULATE A SETTINGS TABLE +-- +set echo off +CREATE TABLE svmo_sh_sample_settings ( + setting_name VARCHAR2(30), + setting_value VARCHAR2(30)); +set echo on + +BEGIN + -- Populate settings table + -- SVM needs to be selected explicitly (default classifier: Naive Bayes) + + -- Examples of other possible overrides are: + -- select a different rate of outliers in the data (default 0.1) + -- (dbms_data_mining.svms_outlier_rate, ,0.05); + -- select a kernel type (default kernel: selected by the algorithm) + -- (dbms_data_mining.svms_kernel_function, dbms_data_mining.svms_linear); + -- (dbms_data_mining.svms_kernel_function, dbms_data_mining.svms_gaussian); + -- turn off active learning (enabled by default) + -- (dbms_data_mining.svms_active_learning, dbms_data_mining.svms_al_disable); + + INSERT INTO svmo_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.algo_name, dbms_data_mining.algo_support_vector_machines); +END; +/ + +--------------------- +-- CREATE A MODEL +-- +-- Build a new one-class SVM Model +-- Note the NULL sprecification for target column name +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'SVMO_SH_Clas_sample', + mining_function => dbms_data_mining.classification, + data_table_name => 'svmo_sh_sample_prepared', + case_id_column_name => 'cust_id', + target_column_name => NULL, + settings_table_name => 'svmo_sh_sample_settings'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30 +column setting_value format a30 +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'SVMO_SH_CLAS_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +-- For sample code displaying SVM signature see dmsvcdem.sql. + +------------------------ +-- DISPLAY MODEL DETAILS +-- +-- Model details are available only for SVM models with linear kernel. +-- For SVM model details sample code see dmsvcdem.sql. +-- + +----------------------------------------------------------------------- +-- APPLY THE MODEL +----------------------------------------------------------------------- + +-- Depending on the business case, the model can be scored against the +-- build data (e.g, business cases 1 and 2) or against new, previously +-- unseen data (e.g., business case 3). New apply data needs to undergo +-- the same transformations as the build data (see business case 3). + +------------------ +-- BUSINESS CASE 1 +-- Find the top 10 outliers - customers that differ the most from +-- the rest of the population. Depending on the application, such +-- atypical customers can be removed from the data (data cleansing). +-- + +SELECT cust_id FROM ( + SELECT cust_id + FROM svmo_sh_sample_prepared + ORDER BY prediction_probability(SVMO_SH_Clas_sample, 0 using *) DESC, 1) +WHERE rownum < 11; + + +------------------ +-- BUSINESS CASE 2 +-- Find demographic characteristics of the typical affinity card members. +-- These statistics will not be influenced by outliers and are likely to +-- to provide a more truthful picture of the population of interest than +-- statistics computed on the entire group of affinity members. +-- Statistics are computed on the original (non-transformed) data. +column cust_gender format a12 +SELECT a.cust_gender, round(avg(a.age)) age, + round(avg(a.yrs_residence)) yrs_residence, + count(*) cnt +FROM mining_data_one_class_v a, + svmo_sh_sample_prepared b +WHERE prediction(SVMO_SH_Clas_sample using b.*) = 1 +AND a.cust_id=b.cust_id +GROUP BY a.cust_gender +ORDER BY a.cust_gender; + + +------------------ +-- BUSINESS CASE 3 +-- +-- Compute probability of a new/hypothetical customer being a typical +-- affinity card holder. +-- Normalization of the numerical attributes is performed on-the-fly. +-- +column prob_typical format 9.99 + +WITH age_norm AS ( +SELECT shift, scale FROM svmo_sh_sample_norm WHERE col = 'AGE'), +yrs_residence_norm AS ( +SELECT shift, scale FROM svmo_sh_sample_norm WHERE col = 'YRS_RESIDENCE') +SELECT prediction_probability(SVMO_SH_Clas_sample, 1 using + (44 - a.shift)/a.scale AS age, + (6 - b.shift)/b.scale AS yrs_residence, + 'Bach.' AS education, + 'Married' AS cust_marital_status, + 'Exec.' AS occupation, + 'United States of America' AS country_name, + 'M' AS cust_gender, + 'L: 300,000 and above' AS cust_income_level, + '3' AS houshold_size + ) prob_typical +FROM age_norm a, yrs_residence_norm b; + diff --git a/dmsvodemo.java b/dmsvodemo.java new file mode 100644 index 0000000..20d549a --- /dev/null +++ b/dmsvodemo.java @@ -0,0 +1,581 @@ +// Copyright (c) 2004, 2005, Oracle. All rights reserved. +// File: dmsvodemo.java + import java.math.BigDecimal; + + import java.sql.PreparedStatement; + import java.sql.ResultSet; + import java.sql.ResultSetMetaData; + import java.sql.SQLException; + import java.sql.Statement; + + import java.text.DecimalFormat; + import java.text.MessageFormat; + + import java.util.Collection; + import java.util.Iterator; + + import java.util.Map; + import javax.datamining.ExecutionHandle; + import javax.datamining.ExecutionState; + import javax.datamining.ExecutionStatus; + import javax.datamining.JDMException; + import javax.datamining.MiningAlgorithm; + import javax.datamining.MiningFunction; + import javax.datamining.NamedObject; + import javax.datamining.algorithm.svm.KernelFunction; + import javax.datamining.algorithm.svm.classification.SVMClassificationSettings; + import javax.datamining.algorithm.svm.classification.SVMClassificationSettingsFactory; + import javax.datamining.base.AlgorithmSettings; + import javax.datamining.base.Model; + import javax.datamining.base.Task; + import javax.datamining.data.AttributeDataType; + import javax.datamining.data.CategorySet; + import javax.datamining.data.ModelSignature; + import javax.datamining.data.PhysicalAttribute; + import javax.datamining.data.PhysicalAttributeFactory; + import javax.datamining.data.PhysicalAttributeRole; + import javax.datamining.data.PhysicalDataSet; + import javax.datamining.data.PhysicalDataSetFactory; + import javax.datamining.data.SignatureAttribute; + import javax.datamining.modeldetail.svm.SVMClassificationModelDetail; + import javax.datamining.resource.ConnectionSpec; + import javax.datamining.supervised.classification.ClassificationApplySettings; + import javax.datamining.supervised.classification.ClassificationApplySettingsFactory; + import javax.datamining.supervised.classification.ClassificationModel; + import javax.datamining.supervised.classification.ClassificationSettings; + import javax.datamining.supervised.classification.ClassificationSettingsFactory; + import javax.datamining.task.BuildTask; + import javax.datamining.task.BuildTaskFactory; + import javax.datamining.task.apply.DataSetApplyTask; + import javax.datamining.task.apply.DataSetApplyTaskFactory; + + import oracle.dmt.jdm.algorithm.svm.classification.OraSVMClassificationSettings; + import oracle.dmt.jdm.base.OraBuildSettings; + import oracle.dmt.jdm.modeldetail.svm.OraSVMClassificationModelDetail; + import oracle.dmt.jdm.resource.OraConnection; + import oracle.dmt.jdm.resource.OraConnectionFactory; + import oracle.dmt.jdm.supervised.classification.OraClassificationModel; + import oracle.dmt.jdm.transform.normalize.OraNormalizeTransformImpl; +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to solve a classification problem using Support Vector Machines (SVM) +* algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* Given demographic about a set of customers that are known to have +* an affinity card, 1) find the most atypical members of this group +* (outlier identification), 2) discover the common demographic +* characteristics of the most typical customers with affinity card, +* and 3) compute how typical a given new/hypothetical customer is. +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the previous affinity card +* programs. Data exploration and preparing the data is a common step before +* doing data mining. Here in this demo, the following views are created in the user +* schema using CUSTOMERS, COUNTRIES and SUPPLIMENTARY_DEMOGRAPHICS tables. +* +* MINING_DATA_ONE_CLASS_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for building the model. +* +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a classification one-class model using the SVM +* algorithm. +* +* Test Model: +* Classification model performance can be evaluated by computing test +* metrics like accuracy, confusion matrix, lift and ROC. The testModel() or +* computeTestMetrics() method illustrates how to perform the test operation to +* compute various metrics. We skip the test model in this demo. +* +* Apply Model: +* Predicting the target attribute values is the prime function of +* classification one-class models. Depending on the business case, the +* model can be scored against the build data or against new, previously +* unseen data. New apply data needs to undergo the same transformations as +* the build data. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ + + +public class dmsvodemo extends Object { + // Connection related data members + private static javax.datamining.resource.Connection m_dmeConn ; + private static javax.datamining.resource.ConnectionFactory m_dmeConnFactory; + // Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static ClassificationSettingsFactory m_clasFactory; + private static SVMClassificationSettingsFactory m_svmoFactory; + private static BuildTaskFactory m_buildFactory; + private static DataSetApplyTaskFactory m_dsApplyFactory; + private static ClassificationApplySettingsFactory m_applySettingsFactory; + // Global constants + private static DecimalFormat m_df = new DecimalFormat("##.####"); + // Global data members + private static OraNormalizeTransformImpl m_normalizeDataXform; + + public static void main( String args[] ) { + try { + if (args.length != 3 ) { + System.out.println("Usage: java dmsvodemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + // 1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@"+uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Build model - Please see dmnbdemo.java to see how to build a model + // with supplied prior probability. + buildModel(); + // 5. Apply the model + applyModel(); + } catch(Exception anyExp) { + anyExp.printStackTrace(System.out); + } finally { + try { + // 7. Logout from the Data Mining Engine + m_dmeConn.close(); + } catch(Exception anyExp1) { } // Ignore + } + } + + /** + * Initialize all object factories used in the demo program. + * + * @exception JDMException if factory initalization failed + */ + public static void initFactories() throws JDMException + { + m_pdsFactory = (PhysicalDataSetFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalDataSet"); + m_paFactory = (PhysicalAttributeFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalAttribute"); + m_clasFactory = (ClassificationSettingsFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationSettings"); + m_svmoFactory = (SVMClassificationSettingsFactory)m_dmeConn.getFactory( + "javax.datamining.algorithm.svm.classification.SVMClassificationSettings"); + m_buildFactory = (BuildTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.BuildTask"); + m_dsApplyFactory = (DataSetApplyTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.apply.DataSetApplyTask"); + m_applySettingsFactory = (ClassificationApplySettingsFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationApplySettings"); + } + + /** + * This method illustrates how to build a mining model using the + * SVMO_NORM_DATA_BUILD_JDM dataset and classification settings with + * SVM algorithm. + * + * By default, the SVM algorithm chooses a kernel type automatically. This + * choice can be overriden by the user. Linear kernel is preferred for high + * dimensional data, and Gaussian kernel for low dimensional data. Here we + * will let the data mining server choose the kernel type automatically, and + * define no target since this is a one-class classification demo. + * + * @exception JDMException if model build failed + */ + public static void buildModel() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Build Model ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = + m_pdsFactory.create("MINING_DATA_BUILD_V", false); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + buildData.addAttribute(pa); + m_dmeConn.saveObject("svmoBuildData_jdm", buildData, true); + // 2. Create & save Mining Function Settings + // Create SVMC algorithm settings + SVMClassificationSettings svmoAlgo = m_svmoFactory.create(); + // Examples settings are: + // - Select a different rate of outliers in the data (default 0.1) + // svmoAlgo.setOutlierRate(0.05f); + // - Select a kernel type (default kernel: selected by the algorithm) + // svmoAlgo.setKernelFunction(KernelFunction.kLinear); + // svmoAlgo.setKernelFunction(KernelFunction.kGaussian); + // - Turn off active learning (enabled by default) + // svmoAlgo.setActiveLearning(false); + // + //Create ClassificationSettings + ClassificationSettings buildSettings = m_clasFactory.create(); + buildSettings.setAlgorithmSettings(svmoAlgo); + //Set auto data preparation on + ((OraBuildSettings)buildSettings).useAutomatedDataPreparations(true); + m_dmeConn.saveObject("svmoBuildSettings_jdm", buildSettings, true); + // 3. Create, save & execute Build Task + BuildTask buildTask = m_buildFactory.create( + "svmoBuildData_jdm", //Build data specification + "svmoBuildSettings_jdm", //Mining function settings name + "svmoModel_jdm" //Mining model name + ); + buildTask.setDescription("svmoBuildTask_jdm"); + executeTask(buildTask, "svmoBuildTask_jdm"); + //4. Restore the model from the DME and explore the details of the model + ClassificationModel model = + (ClassificationModel)m_dmeConn.retrieveObject( + "svmoModel_jdm", NamedObject.model); + // Display model build settings + ClassificationSettings retrievedBuildSettings = + (ClassificationSettings)model.getBuildSettings(); + if(buildSettings == null) + System.out.println("Failure to restore build settings."); + else + displayBuildSettings(retrievedBuildSettings, "svmoBuildSettings_jdm"); + // Display model signature + displayModelSignature((Model)model); + // Display model details + displaySVMOModelDetails((Model)model); + } + + /** + * This method illustrates how to apply the mining model on the + * SVMO_NORM_DATA_BUILD_JDM dataset to predict customer + * response. After completion of the task, the apply output table with the + * predicted results is created at the user specified location. + * + * @exception JDMException if model apply failed + */ + public static void applyModel() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Apply Model ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = m_pdsFactory.create( + "MINING_DATA_BUILD_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "svmoApplyData_jdm", applyData, true ); + // 2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + m_dmeConn.saveObject( "svmoApplySettings_jdm", clasAS, true); + // 3. Create, store & execute apply Task + DataSetApplyTask applyTask = m_dsApplyFactory.create( + "svmoApplyData_jdm", "svmoModel_jdm", + "svmoApplySettings_jdm", "SVMO_APPLY_OUTPUT_JDM"); + executeTask(applyTask, "svmoApplyTask_jdm"); + // 4. Display apply result + displayTable("SVMO_APPLY_OUTPUT_JDM", // apply output table name + + "where PREDICTION = 0", // 0 means the record does not + // belong to the population + + "order by PROBABILITY DESC", // List from top probability to + // bottom + + 10); // List the first 10 rows + } + + /** + * This method stores the given task with the specified name in the DMS + * and submits the task for asynchronous execution in the DMS. After + * completing the task successfully it returns true. If there is a task + * failure, then it prints error description and returns false. + * + * @param taskObj task object + * @param taskName name of the task + * + * @return boolean returns true when the task is successful + * @exception JDMException if task execution failed + */ + public static boolean executeTask(Task taskObj, String taskName) + throws JDMException { + boolean isTaskSuccess = false; + m_dmeConn.saveObject(taskName, taskObj, true); + ExecutionHandle execHandle = m_dmeConn.execute(taskName); + System.out.print(taskName + " is started, please wait. "); + //Wait for completion of the task + ExecutionStatus status = execHandle.waitForCompletion(Integer.MAX_VALUE); + //Check the status of the task after completion + isTaskSuccess = status.getState().equals(ExecutionState.success); + if( isTaskSuccess ) { + //Task completed successfully + System.out.println(taskName + " is successful."); + } else {//Task failed + System.out.println(taskName + " is failed.\nFailure Description: " + + status.getDescription() ); + } + return isTaskSuccess; + } + + private static void displayBuildSettings( + ClassificationSettings clasSettings, String buildSettingsName) + { + // Display build settings table + System.out.println("BuildSettings Details from the " + + buildSettingsName + " table:"); + displayTable(buildSettingsName, "", "order by SETTING_NAME"); + // Display build settings object obtained from the model + System.out.println("BuildSettings Details from the " + + buildSettingsName + " object:"); + String objName = clasSettings.getName(); + if(objName != null) + System.out.println("Name = " + objName); + String objDescription = clasSettings.getDescription(); + if(objDescription != null) + System.out.println("Description = " + objDescription); + java.util.Date creationDate = clasSettings.getCreationDate(); + String creator = clasSettings.getCreatorInfo(); + String targetAttrName = clasSettings.getTargetAttributeName(); + System.out.println("Target attribute name = " + targetAttrName); + AlgorithmSettings algoSettings = clasSettings.getAlgorithmSettings(); + if(algoSettings == null) + System.out.println("Failure: clasSettings.getAlgorithmSettings() returns null"); + MiningAlgorithm algo = algoSettings.getMiningAlgorithm(); + if(algo == null) System.out.println("Failure: algoSettings.getMiningAlgorithm() returns null"); + System.out.println("Algorithm Name: " + algo.name()); + MiningFunction function = clasSettings.getMiningFunction(); + if(function == null) System.out.println("Failure: clasSettings.getMiningFunction() returns null"); + System.out.println("Function Name: " + function.name()); + // List of SVM algorithm settings availanle in one class model + KernelFunction kernelFunction = ((OraSVMClassificationSettings)algoSettings).getKernelFunction(); + System.out.println("Kernel Function: " + kernelFunction.name()); + double doubleValue = ((OraSVMClassificationSettings)algoSettings).getTolerance(); + System.out.println("Tolerance: " + m_df.format(doubleValue)); + boolean enable = ((OraSVMClassificationSettings)algoSettings).getActiveLearning(); + System.out.println("Is Active Learning enabled? " + enable); + doubleValue = ((OraSVMClassificationSettings)algoSettings).getOutlierRate(); + System.out.println("Outlier Rate: " + m_df.format(doubleValue)); + doubleValue = ((OraSVMClassificationSettings)algoSettings).getStandardDeviation(); + System.out.println("Standard Deviation: " + m_df.format(doubleValue)); + int intValue = ((OraSVMClassificationSettings)algoSettings).getKernelCacheSize(); + System.out.println("Kernel Cache Size: " + intValue); + } + + /** + * This method displayes SVMO model signature. + * + * @param model model object + * @exception JDMException if failed to retrieve model signature + */ + public static void displayModelSignature(Model model) throws JDMException + { + String modelName = model.getName(); + System.out.println("Model Name: " + modelName); + ModelSignature modelSignature = model.getSignature(); + System.out.println("Model Signature: ( Attribute Name, Attribute Type )"); + MessageFormat mfSign = new MessageFormat(" ( {0}, {1} )"); + String[] vals = new String[2]; + Collection sortedSet = modelSignature.getAttributes(); + Iterator attrIterator = sortedSet.iterator(); + while(attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute)attrIterator.next(); + vals[0] = attr.getName(); + vals[1] = attr.getDataType().name(); + System.out.println( mfSign.format(vals) ); + } + } + + /** + * This method displayes SVMO model details. The coefficient indicates the + * relative influence of a given (attribute, value) pair on the target value. + * A negative coefficient value indicates a negative influence. + * + * @param svmcModelDetails svm classification model details object + * @exception JDMException if failed to retrieve model details + */ + public static void displaySVMOModelDetails( + Model model) throws JDMException + { + // Obtains model details + SVMClassificationModelDetail svmcModelDetails = + (SVMClassificationModelDetail)model.getModelDetail(); + // Is linear model? + System.out.println("Is linear model? " + svmcModelDetails.isLinearSVMModel() ); + // Available targets + CategorySet targetSet = ((OraClassificationModel)model).getTargetCategorySet(); + Object[] targets = targetSet.getValues(); + // Attribute coefficient value will be available if it is a linear model + if (svmcModelDetails.isLinearSVMModel()) + { + System.out.println("Model Deatils: ( Target Value, Attribute Name, Attribute Value, Coefficient)"); + MessageFormat mfDetails = new MessageFormat(" ( {0}, {1}, {2}, {3} )"); + String[] vals = new String[4]; + for (int row =0; row < targets.length; row++) + { + // Print bias of the current target value by invoking getBias method. + vals[0] =(String) targets[row].toString(); + vals[1] = ""; + vals[2] = ""; + vals[3] = m_df.format(svmcModelDetails.getBias(targets[row])) + " (Bias)"; + System.out.println( mfDetails.format(vals) ); + //Get the signature attributes + ModelSignature modelSignature = model.getSignature(); + Collection sortedSet = modelSignature.getAttributes(); + Iterator attrIterator = sortedSet.iterator(); + + while(attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute)attrIterator.next(); + // Print all attribute coefficients -- The FIRST row in the SVM model + // details output shows the value for SVM bias under the COEFFICIENT + // column. + Map attrCoefficientMap = ((OraSVMClassificationModelDetail)svmcModelDetails).getCoefficients(targets[row],attr.getName()); + Object[] attrVals = attrCoefficientMap.keySet().toArray(); + if(attrVals != null) { + for(int iAttr=0; iAttr < attrVals.length; iAttr++) + { + vals[1] = attr.getName(); + vals[2] = ""; + if(attrVals[iAttr] != null) + vals[2] = attrVals[iAttr].toString(); + vals[3] = ""; + Number coefficient = (Number)attrCoefficientMap.get(attrVals[iAttr]); + if(coefficient != null) + vals[3] = m_df.format(coefficient); + System.out.println( mfDetails.format(vals) ); + } + } + } + } + } + } + + private static void displayTable(String tableName, String whereCause, String orderByColumn) + { + displayTable(tableName, whereCause, orderByColumn, 0); // display all rows + } + + private static void displayTable(String tableName, String whereCause, String orderByColumn, int maxRow) + { + StringBuffer emptyCol = new StringBuffer(" "); + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + PreparedStatement pStmt = null; + ResultSet rs = null; + try + { + pStmt = dbConn.prepareStatement("SELECT * FROM " + tableName + " " + whereCause + " " + orderByColumn); + rs = pStmt.executeQuery(); + ResultSetMetaData rsMeta = rs.getMetaData(); + int colCount = rsMeta.getColumnCount(); + StringBuffer header = new StringBuffer(); + System.out.println("Table : " + tableName); + // Build table header + for(int iCol=1; iCol<=colCount; iCol++) + { + String colName = rsMeta.getColumnName(iCol); + header.append(emptyCol.replace(0, colName.length(), colName)); + emptyCol = new StringBuffer(" "); + } + System.out.println(header.toString()); + // Write table data + int row = 0; + while(rs.next()) + { + row = row + 1; + if (row > maxRow & maxRow > 0) + break; + + StringBuffer rowContent = new StringBuffer(); + for(int iCol=1; iCol<=colCount; iCol++) + { + int sqlType = rsMeta.getColumnType(iCol); + Object obj = rs.getObject(iCol); + String colContent = null; + + if(obj instanceof java.lang.Number) + { + try + { + BigDecimal bd = (BigDecimal)obj; + if(bd.scale() > 5) + { + colContent = m_df.format(obj); + } else + { + colContent = bd.toString(); + } + } catch(Exception anyExp) { + colContent = m_df.format(obj); + } + } else + { + if(obj == null) + colContent = "NULL"; + else + colContent = obj.toString(); + } + rowContent.append(" "+emptyCol.replace(0, colContent.length(), colContent)); + emptyCol = new StringBuffer(" "); + } + System.out.println(rowContent.toString()); + } + } catch(Exception anySqlExp) { + anySqlExp.printStackTrace(); + } // Ignore + } + + private static void clean() + { + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + Statement stmt = null; + //Drop prepared views + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP VIEW SVMO_NORM_DATA_BUILD_JDM"); + } catch(SQLException anySqlExp) {} // Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP VIEW SVMO_NORM_DATA_APPLY_JDM"); + } catch(SQLException anySqlExp) {} // Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + //Drop apply output table + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP TABLE SVMO_APPLY_OUTPUT_JDM"); + } catch(SQLException anySqlExp) {} // Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + //Drop the model + try { + m_dmeConn.removeObject("svmoModel_jdm", NamedObject.model); + } catch(JDMException jdmExp) {} + } +} diff --git a/dmsvrdem.sql b/dmsvrdem.sql new file mode 100644 index 0000000..9e75ba0 --- /dev/null +++ b/dmsvrdem.sql @@ -0,0 +1,227 @@ +Rem +Rem $Header: dmsvrdem.sql 25-oct-2007.11:34:45 ramkrish Exp $ +Rem +Rem dmsvrdem.sql +Rem +Rem Copyright (c) 2003, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmsvrdem.sql - Sample program for the DBMS_DATA_MINING package. +Rem +Rem DESCRIPTION +Rem This script creates a regression model +Rem using the SVM algorithm +Rem and data in the SH (Sales History) schema in the RDBMS. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ramkrish 06/14/07 - remove commit after settings +Rem ramkrish 10/25/07 - replace deprecated get_model calls with catalog +Rem queries +Rem jiawang 08/02/06 - ENABLE ADP +Rem ktaylor 07/11/05 - minor edits to comments +Rem ramkrish 12/09/04 - fix incorrect table names +Rem bmilenov 11/04/04 - Edit comments +Rem ramkrish 09/28/04 - add data analysis, comments, SQL functions +Rem bmilenov 05/18/04 - Change zscore to minmax normalization +Rem pstengar 12/11/03 - modified apply selection query +Rem ramkrish 10/02/03 - Creation + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET echo ON + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM +----------------------------------------------------------------------- +-- Given demographic, purchase, and affinity card membership data for a +-- set of customers, predict customer's age. Since age is a continuous +-- variable, this is a regression problem. + +----------------------------------------------------------------------- +-- SET UP AND ANALYZE DATA +----------------------------------------------------------------------- + +-- The data for this sample is composed from base tables in the SH Schema +-- (See Sample Schema Documentation) and presented through these views: +-- mining_data_build_v (build data) +-- mining_data_test_v (test data) +-- mining_data_apply_v (apply data) +-- (See dmsh.sql for view definitions). +-- +----------- +-- ANALYSIS +----------- +-- For regression using SVM, perform the following on mining data. +-- +-- 1. Use Auto Data Preparation +-- + +----------------------------------------------------------------------- +-- BUILD THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old model with same name (if any) +BEGIN DBMS_DATA_MINING.DROP_MODEL('SVMR_SH_Regr_sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +------------------- +-- SPECIFY SETTINGS +-- +-- Cleanup old settings table for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE svmr_sh_sample_settings'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- The default algorithm for regression is SVM. +-- see dmsvcdem.sql on choice of kernel function. +-- +CREATE TABLE svmr_sh_sample_settings ( + setting_name VARCHAR2(30), + setting_value VARCHAR2(30)); + +BEGIN + -- Populate settings table + INSERT INTO svmr_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.svms_kernel_function, dbms_data_mining.svms_gaussian); + + INSERT INTO svmr_sh_sample_settings (setting_name, setting_value) VALUES + (dbms_data_mining.prep_auto,dbms_data_mining.prep_auto_on); + + -- Examples of other possible overrides are: + --(dbms_data_mining.svms_conv_tolerance,0.01); + --(dbms_data_mining.svms_epsilon,0.1); + --(dbms_data_mining.svms_kernel_cache_size,50000000); + --(dbms_data_mining.svms_kernel_function,dbms_data_mining.svms_linear); +END; +/ + +--------------------- +-- CREATE A NEW MODEL +-- +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'SVMR_SH_Regr_sample', + mining_function => dbms_data_mining.regression, + data_table_name => 'mining_data_build_v', + case_id_column_name => 'cust_id', + target_column_name => 'age', + settings_table_name => 'svmr_sh_sample_settings'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30 +column setting_value format a30 +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'SVMR_SH_REGR_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +column attribute_type format a20 +SELECT attribute_name, attribute_type + FROM user_mining_model_attributes + WHERE model_name = 'SVMR_SH_REGR_SAMPLE' +ORDER BY attribute_name; + +------------------------ +-- DISPLAY MODEL DETAILS +-- +-- Skip. GET_MODEL_DETAILS_SVM is supported only for Linear Kernels. +-- The current model is built using a Gaussian Kernel (see dmsvcdem.sql). +-- + +----------------------------------------------------------------------- +-- TEST THE MODEL +----------------------------------------------------------------------- + +------------------------------------ +-- COMPUTE METRICS TO TEST THE MODEL +-- + +CREATE VIEW svmr_sh_sample_test AS +SELECT A.cust_id, + PREDICTION(svmr_sh_regr_sample USING *) prediction + FROM mining_data_test_v A; + + +-- COMPUTE TEST METRICS +-- +-- 1. Root Mean Square Error - Sqrt(Mean((x - x')^2)) +-- +column rmse format 9999.99 +SELECT SQRT(AVG((A.prediction - B.age) * (A.prediction - B.age))) rmse + FROM svmr_sh_sample_test A, + mining_data_test_v B + WHERE A.cust_id = B.cust_id; + + + +-- 2. Mean Absolute Error - Mean(|(x - x')|) +-- +column mae format 9999.99 +SELECT AVG(ABS(a.prediction - B.age)) mae + FROM svmr_sh_sample_test A, + mining_data_test_v B + WHERE A.cust_id = B.cust_id; + +-- 3. Residuals +-- If the residuals show substantial variance between +-- the predicted value and the actual, you can consider +-- changing the algorithm parameters. +-- +SELECT TO_CHAR(ROUND(prediction, 4)) prediction, residual + FROM (SELECT A.prediction, (A.prediction - B.age) residual + FROM svmr_sh_sample_test A, + mining_data_test_v B + WHERE A.cust_id = B.cust_id + ORDER BY A.prediction ASC) + WHERE ROWNUM < 11; + +----------------------------------------------------------------------- +-- APPLY THE MODEL +----------------------------------------------------------------------- +------------------------------------------------- +-- SCORE NEW DATA USING SQL DATA MINING FUNCTIONS +-- +------------------ +-- BUSINESS CASE 1 +-- Predict the average age of customers, broken out by gender. +-- +SELECT A.cust_gender, + COUNT(*) AS cnt, + ROUND( + AVG(PREDICTION(svmr_sh_regr_sample USING A.*)),4) + AS avg_age + FROM mining_data_apply_v A +GROUP BY cust_gender +ORDER BY cust_gender; + + +column pred_age format 999.99 +------------------ +-- BUSINESS CASE 2 +-- Create a 10 bucket histogram of customers from Italy based on their age +-- and return each customer's age group. +-- +WITH +cust_italy AS ( +SELECT * + FROM mining_data_apply_v + WHERE country_name = 'Italy' +) +SELECT cust_id, + PREDICTION(svmr_sh_regr_sample USING A.*) pred_age, + WIDTH_BUCKET( + PREDICTION(svmr_sh_regr_sample USING A.*), 10, 100, 10) "Age Group" + FROM cust_italy A +ORDER BY pred_age; diff --git a/dmsvrdemo.java b/dmsvrdemo.java new file mode 100644 index 0000000..9da44ab --- /dev/null +++ b/dmsvrdemo.java @@ -0,0 +1,745 @@ +// Copyright (c) 2004, 2006, Oracle. All rights reserved. +// File: dmsvrdemo.java +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to solve a regression problem using Support Vector Machines (SVM) algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* Given demographic, purchase, and affinity card membership data for a set of +* customers, predict customer's age. Since age is a continuous variable, this +* is a regression problem. +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the +* previous affinity card programs. Data exploration and preparing the data is a +* common step before doing data mining. Here in this demo, the following views are +* created in the user schema using CUSTOMERS, COUNTRIES, and +* SUPPLIMENTARY_DEMOGRAPHICS tables. +* +* MINING_DATA_BUILD_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for building the model. +* +* MINING_DATA_TEST_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for testing the model. +* +* MINING_DATA_APPLY_V: +* This view collects the prospective customers' demographics, purchasing, +* and affinity card response details for predicting customer's age. +* +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a regression model using SVM algorithm. +* +* Test Model: +* Regression models performance can be evaluated by computing different types +* of error rates. The testModel() or computeTestMetrics() method illustrates how +* to perform the test operation to compute various error rates. +* +* Apply Model: +* Predicting the target attribute values is the prime function of regression +* models. The applyModel() method illustrates how to predict the customer's age. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +// Generic Java api imports +import java.math.BigDecimal; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; + +import java.text.DecimalFormat; +import java.text.MessageFormat; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.MiningAlgorithm; +import javax.datamining.MiningFunction; +import javax.datamining.NamedObject; +import javax.datamining.algorithm.svm.KernelFunction; +import javax.datamining.algorithm.svm.regression.SVMRegressionSettings; +import javax.datamining.algorithm.svm.regression.SVMRegressionSettingsFactory; +import javax.datamining.base.AlgorithmSettings; +import javax.datamining.base.Model; +import javax.datamining.base.Task; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.ModelSignature; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.data.SignatureAttribute; +import javax.datamining.modeldetail.svm.SVMRegressionModelDetail; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.supervised.classification.ClassificationModel; +import javax.datamining.supervised.classification.ClassificationSettings; +import javax.datamining.supervised.classification.ClassificationTestMetrics; +import javax.datamining.supervised.regression.RegressionApplySettings; +import javax.datamining.supervised.regression.RegressionApplySettingsFactory; +import javax.datamining.supervised.regression.RegressionModel; +import javax.datamining.supervised.regression.RegressionSettings; +import javax.datamining.supervised.regression.RegressionSettingsFactory; +import javax.datamining.supervised.regression.RegressionTestMetrics; +import javax.datamining.supervised.regression.RegressionTestMetricsTask; +import javax.datamining.supervised.regression.RegressionTestMetricsTaskFactory; +import javax.datamining.supervised.regression.RegressionTestTask; +import javax.datamining.supervised.regression.RegressionTestTaskFactory; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; +import javax.datamining.task.apply.DataSetApplyTask; +import javax.datamining.task.apply.DataSetApplyTaskFactory; + +import oracle.dmt.jdm.algorithm.svm.regression.OraSVMRegressionSettings; +import oracle.dmt.jdm.base.OraBuildSettings; +import oracle.dmt.jdm.base.OraTask; +import oracle.dmt.jdm.modeldetail.svm.OraSVMRegressionModelDetail; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.supervised.regression.OraRegressionApplySettings; +import oracle.dmt.jdm.supervised.regression.OraRegressionTestMetrics; +import oracle.dmt.jdm.task.OraTransformationTask; +import oracle.dmt.jdm.task.OraTransformationTaskFactory; +import oracle.dmt.jdm.transform.normalize.OraNormalizeTransformFactory; +import oracle.dmt.jdm.transform.normalize.OraNormalizeTransformImpl; +import oracle.dmt.jdm.transform.normalize.OraNormalizeType; +// Java Data Mining (JDM) standard api imports +// Oracle Java Data Mining (JDM) implemented api imports + +public class dmsvrdemo extends Object { + // Connection related data members + private static javax.datamining.resource.Connection m_dmeConn; + private static javax.datamining.resource.ConnectionFactory m_dmeConnFactory; + // Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static RegressionSettingsFactory m_regrFactory; + private static SVMRegressionSettingsFactory m_svmrFactory; + private static BuildTaskFactory m_buildFactory; + private static DataSetApplyTaskFactory m_dsApplyFactory; + private static RegressionTestTaskFactory m_testFactory; + private static RegressionApplySettingsFactory m_applySettingsFactory; + private static RegressionTestMetricsTaskFactory m_testMetricsTaskFactory; + // Global constants + private static DecimalFormat m_df = new DecimalFormat("##.####"); + // Global data members + private static OraNormalizeTransformImpl m_buildDataXform; + + public static void main( String args[] ) { + try { + if ( args.length != 3 ) { + System.out.println("Usage: java dmsvrdemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + // 1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@"+uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Build a model + buildModel(); + // 5a. Test model - To compute different type of error rates for the + // model from a test input data. + testModel(); + // 5b. Test model - To compute different type of error rates for the + // model from an apply output data. + computeTestMetrics(); + // 6. Apply the model + applyModel(); + // 7. Start execution of the first task in the sequnece + m_dmeConn.execute("svmrBuildTask_jdm"); + // 8. Monitor and display results (if any) + monitorTaskExecutionProcess(); + } catch(Exception anyExp) { + anyExp.printStackTrace(System.out); + } finally { + try { + // 8. Logout from the Data Mining Engine + m_dmeConn.close(); + } catch(Exception anyExp1) { }//Ignore + } + } + + /** + * Initialize all object factories used in the demo program. + * + * @exception JDMException if factory initalization failed + */ + public static void initFactories() throws JDMException + { + m_pdsFactory = (PhysicalDataSetFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalDataSet"); + m_paFactory = (PhysicalAttributeFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalAttribute"); + m_regrFactory = (RegressionSettingsFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.regression.RegressionSettings"); + m_svmrFactory = (SVMRegressionSettingsFactory)m_dmeConn.getFactory( + "javax.datamining.algorithm.svm.regression.SVMRegressionSettings"); + m_buildFactory = (BuildTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.BuildTask"); + m_dsApplyFactory = (DataSetApplyTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.apply.DataSetApplyTask"); + m_testFactory = (RegressionTestTaskFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.regression.RegressionTestTask"); + m_applySettingsFactory = (RegressionApplySettingsFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.regression.RegressionApplySettings"); + m_testMetricsTaskFactory = (RegressionTestMetricsTaskFactory) m_dmeConn.getFactory( + "javax.datamining.supervised.regression.RegressionTestMetricsTask"); + } + + /** + * This method illustrates how to build mining model using + * MINING_DATA_BUILD_V dataset and regression settings with + * SVM algorithm. + * + * By default SVM algorithm chooses a kernel type automatically. This + * choice can be overriden by the user. Linear kernel is preferred for high + * dimensional data, and Gaussian kernel for low dimensional data. Here we use + * Gaussian kernel in this demo. + * + * @exception JDMException if model build failed + */ + public static void buildModel() throws JDMException + { + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = m_pdsFactory.create("MINING_DATA_BUILD_V", false); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + buildData.addAttribute(pa); + m_dmeConn.saveObject("svmrBuildData_jdm", buildData, true); + // 2. Create & save Mining Function Settings + // Create SVMR algorithm settings + SVMRegressionSettings svmrAlgo = m_svmrFactory.create(); + svmrAlgo.setKernelFunction(KernelFunction.kGaussian); + // Examples settings are: + // svmrAlgo.setKernelFunction(KernelFunction.kLinear); + // svmrAlgo.setEpsilon(0.1f); + // svmrAlgo.setTolerance(0.01f); + // svmrAlgo.setKernelCacheSize(50000000); + // + // Create RegressionSettings + RegressionSettings buildSettings = m_regrFactory.create(); + buildSettings.setAlgorithmSettings(svmrAlgo); + buildSettings.setTargetAttributeName("AGE"); + //Set auto data preparation on + ((OraBuildSettings)buildSettings).useAutomatedDataPreparations(true); + m_dmeConn.saveObject("svmrBuildSettings_jdm", buildSettings, true); + // 3. Create, save & execute Build Task + BuildTask buildTask = m_buildFactory.create( + "svmrBuildData_jdm", //Build data specification + "svmrBuildSettings_jdm", //Mining function settings name + "svmrModel_jdm" //Mining model name + ); + buildTask.setDescription("svmrBuildTask_jdm"); + saveTask(buildTask, "svmrBuildTask_jdm", null); + } + + /** + * This method illustrates how to test the mining model with the + * MINING_DATA_TEST_V dataset using regression test task. After + * completion of the task, a regression test metrics object is created + * in the DMS. Regression test metrics object encapsulates + * different types of error rates. + * + * @exception JDMException if model test failed + */ + public static void testModel() + throws JDMException + { + + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet testData = m_pdsFactory.create( + "MINING_DATA_TEST_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + testData.addAttribute( pa ); + m_dmeConn.saveObject( "svmrTestData_jdm", testData, true ); + // 2. Create, store & execute Test Task + RegressionTestTask testTask = m_testFactory.create( + "svmrTestData_jdm", "svmrModel_jdm", "svrTestMetrics_jdm" ); + // 3. Store the task + saveTask(testTask, "svmrTestTask_jdm", "svmrBuildTask_jdm"); + } + + /** + * This method illustrates how to compute test metrics using + * an apply output table that has actual and predicted target values. Here the + * apply operation is done on the MINING_DATA_TEST_V dataset. It creates + * an apply output table with actual and predicted target values. Using + * RegressionTestMetricsTask test metrics are computed. This produces + * the same test metrics results as RegressionTestTask. + * + * @exception JDMException if model test failed + */ + public static void computeTestMetrics() throws JDMException + { + + // 1. Do the apply on test data to create an apply output table + // Create & save PhysicalDataSpecification + PhysicalDataSet applyData = + m_pdsFactory.create( "MINING_DATA_TEST_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "svmrTestApplyData_jdm", applyData, true ); + // 2. Create & save RegressionApplySettings + RegressionApplySettings regreAS = m_applySettingsFactory.create(); + HashMap sourceAttrMap = new HashMap(); + sourceAttrMap.put( "AGE", "AGE" ); + regreAS.setSourceDestinationMap( sourceAttrMap ); + m_dmeConn.saveObject( "svmrTestApplySettings_jdm", regreAS, true); + // 3. Create & store apply Task + DataSetApplyTask applyTask = m_dsApplyFactory.create( + "svmrTestApplyData_jdm", "svmrModel_jdm", "svmrTestApplySettings_jdm", + "SVMR_TEST_APPLY_OUTPUT_JDM"); + saveTask(applyTask, "svmrTestApplyTask_jdm", "svmrBuildTask_jdm"); + // 4. Generate test metrics on the above new created apply output table + // Create & save PhysicalDataSpecification + PhysicalDataSet applyOutputData = m_pdsFactory.create( + "SVMR_TEST_APPLY_OUTPUT_JDM", false ); + applyOutputData.addAttribute( pa ); + m_dmeConn.saveObject( "svmrTestApplyOutput_jdm", applyOutputData, true ); + // 5. Create a RegressionTestMetricsTask + RegressionTestMetricsTask testMetricsTask = + m_testMetricsTaskFactory.create( "svmrTestApplyOutput_jdm", // apply output data used as input + "AGE", // actual target column + "PREDICTION", // predicted target column + "svrComputeTestMetrics_jdm" // test metrics result name + ); + // 6. Store & execute the task + saveTask(testMetricsTask, "svmrTestMetricsTask_jdm", "svmrTestApplyTask_jdm"); + } + + /** + * This method illustrates how to apply mining model on + * MINING_DATA_APPLY_V dataset to predict customer's age. + * After completion of the task apply output table with the + * predicted results is created at the user specified location. + * + * @exception JDMException if model apply failed + */ + public static void applyModel() throws JDMException + { + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = + m_pdsFactory.create("MINING_DATA_APPLY_V", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "svmrApplyData_jdm", applyData, true ); + // 2. Create & save RegressionApplySettings + RegressionApplySettings regrAS = m_applySettingsFactory.create(); + m_dmeConn.saveObject( "svmrApplySettings_jdm", regrAS, true); + // 3. Create, store & execute apply Task + DataSetApplyTask applyTask = m_dsApplyFactory.create( + "svmrApplyData_jdm", "svmrModel_jdm", "svmrApplySettings_jdm", + "SVMR_APPLY_OUTPUT_JDM"); + saveTask(applyTask, "svmrApplyTask_jdm", "svmrBuildTask_jdm"); + } + + /** + * This method saves the given task with the specified task name and task + * dependency (parent task) in the DME. + * + * @param taskObj task object + * @param taskName name of the task + * @param parentTaskName name of the parent task + * + * @return boolean returns true when the task is successful + * @exception JDMException if task execution failed + */ + public static void saveTask(Task taskObj, String taskName, + String parentTaskName) + throws JDMException + { + if (parentTaskName != null) + ((OraTask) taskObj).addDependency(parentTaskName); //Since OJDM 11.1 + ((OraTask) taskObj).overwriteOutput(true); //Since OJDM 11.1 + m_dmeConn.saveObject(taskName, taskObj, true); + } + + /** + * This method monitor task execution initiated by the first task + * in the sequence of dependent tasks. In addition, this method displays + * task output results (if any). + * @throws JDMException + */ + public static void monitorTaskExecutionProcess() + throws JDMException + { + //BuildTask + System.out.println("---------------------------------------------------"); + System.out.println("--- Build Model ---"); + System.out.println("---------------------------------------------------"); + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of svmrBuildTask_jdm. "); + ExecutionStatus buildTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("svmrBuildTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(buildTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + // 3. Restore the model from the data mining server + RegressionModel model = + (RegressionModel)m_dmeConn.retrieveObject( + "svmrModel_jdm", NamedObject.model); + // 4. Explore the details of the restored model + // Display model build settings + RegressionSettings retrievedBuildSettings = + (RegressionSettings)model.getBuildSettings(); + if(retrievedBuildSettings == null) + System.out.println("Failure to restore build settings."); + else + displayBuildSettings(retrievedBuildSettings, "svmrBuildSettings_jdm"); + // Display model signature + displayModelSignature((Model)model); + // Display model details + displaySVMRModelDetails(model); + + System.out.println("---------------------------------------------------"); + System.out.println("--- Test Model ---"); + System.out.println("---------------------------------------------------"); + + //If model build is successful, then do testData ApplyTask + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of svmcTestTask_jdm. "); + ExecutionStatus testTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("svmrTestTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(testTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + // Restore & display test metrics + RegressionTestMetrics testMetrics = + (RegressionTestMetrics)m_dmeConn.retrieveObject( + "svrTestMetrics_jdm", + NamedObject.testMetrics ); + // Display regression test metrics + displayTestMetricDetails(testMetrics); + } + else + { + System.out.println("It is at state:" + + testTaskCompletionStatus.getState().name() + + ((testTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + testTaskCompletionStatus.getDescription())); + } + System.out.println("---------------------------------------------------"); + System.out.println("--- Test Model - using apply output table ---"); + System.out.println("---------------------------------------------------"); + + //If model build is successful, then do testData ApplyTask + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of svmrTestMetricsTask_jdm. "); + ExecutionStatus testMetricsTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("svmrTestMetricsTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(testMetricsTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + // Restore & display test metrics + RegressionTestMetrics testMetrics = + (RegressionTestMetrics)m_dmeConn.retrieveObject( + "svrComputeTestMetrics_jdm", + NamedObject.testMetrics ); + // Display regression test metrics + displayTestMetricDetails(testMetrics); + } + else + { + System.out.println("It is at state:" + + testMetricsTaskCompletionStatus.getState().name() + + ((testMetricsTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + testMetricsTaskCompletionStatus.getDescription())); + } + + //ApplyTask(s) + //Waiting for apply task to complete + System.out.println("---------------------------------------------------"); + System.out.println("--- Apply Model ---"); + System.out.println("---------------------------------------------------"); + + ExecutionStatus applyTaskStatus = + m_dmeConn.getLastExecutionHandle("svmrApplyTask_jdm").waitForCompletion(Integer.MAX_VALUE); + if (ExecutionState.success.equals(applyTaskStatus.getState())) + { + // Display apply result + displayTable("SVMR_APPLY_OUTPUT_JDM", "where ROWNUM < 11", + "order by CUST_ID"); + } + else + { + System.out.println("svmcApplyTask_jdm is at state:" + + applyTaskStatus.getState().name() + + ((applyTaskStatus.getDescription() == null)? + "": + "State Description:" + applyTaskStatus.getDescription())); + } + } + else + { + System.out.println("It is at state:" + + buildTaskCompletionStatus.getState().name() + + ((buildTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + buildTaskCompletionStatus.getDescription())); + } + + } + + private static void displayBuildSettings( + RegressionSettings regrSettings, String buildSettingsName) + { + // Display build settings table + System.out.println("BuildSettings Details from the " + + buildSettingsName + " table:"); + displayTable(buildSettingsName, "", "order by SETTING_NAME"); + // Display build settings object obtained from the model + System.out.println("BuildSettings Details from the " + + buildSettingsName + " object:"); + String objName = regrSettings.getName(); + if(objName != null) + System.out.println("Name = " + objName); + String objDescription = regrSettings.getDescription(); + if(objDescription != null) + System.out.println("Description = " + objDescription); + java.util.Date creationDate = regrSettings.getCreationDate(); + String creator = regrSettings.getCreatorInfo(); + String targetAttrName = regrSettings.getTargetAttributeName(); + System.out.println("Target attribute name = " + targetAttrName); + AlgorithmSettings algoSettings = regrSettings.getAlgorithmSettings(); + if(algoSettings == null) + System.out.println("Failure: regrSettings.getAlgorithmSettings() returns null"); + MiningAlgorithm algo = algoSettings.getMiningAlgorithm(); + if(algo == null) System.out.println("Failure: algoSettings.getMiningAlgorithm() returns null"); + System.out.println("Algorithm Name: " + algo.name()); + MiningFunction function = regrSettings.getMiningFunction(); + if(function == null) System.out.println("Failure: regrSettings.getMiningFunction() returns null"); + System.out.println("Function Name: " + function.name()); + // List of SVM algorithm settings availabe in linear kernel + KernelFunction kernelFunction = ((OraSVMRegressionSettings)algoSettings).getKernelFunction(); + System.out.println("Kernel Function: " + kernelFunction.name()); + double doubleValue = ((OraSVMRegressionSettings)algoSettings).getComplexityFactor(); + System.out.println("Complexity Factor: " + m_df.format(doubleValue)); + doubleValue = ((OraSVMRegressionSettings)algoSettings).getTolerance(); + System.out.println("Tolerance: " + m_df.format(doubleValue)); + boolean enable = ((OraSVMRegressionSettings)algoSettings).getActiveLearning(); + System.out.println("Is Active Learning enabled? " + enable); + doubleValue = ((OraSVMRegressionSettings)algoSettings).getEpsilon(); + System.out.println("Epsilon: " + m_df.format(doubleValue)); + } + + /** + * This method displayes SVMR model signature. + * + * @param model model object + * @exception JDMException if failed to retrieve model signature + */ + public static void displayModelSignature(Model model) throws JDMException + { + String modelName = model.getName(); + System.out.println("Model Name: " + modelName); + ModelSignature modelSignature = model.getSignature(); + System.out.println("Model Signature: ( Attribute Name, Attribute Type )"); + MessageFormat mfSign = new MessageFormat(" ( {0}, {1} )"); + String[] vals = new String[2]; + Collection sortedSet = modelSignature.getAttributes(); + Iterator attrIterator = sortedSet.iterator(); + while(attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute)attrIterator.next(); + vals[0] = attr.getName(); + vals[1] = attr.getDataType().name(); + System.out.println( mfSign.format(vals) ); + } + } + + /** + * This method displays SVMR model details. The coefficient indicates the + * relative influence of a given (attribute, value). A negative coefficient + * value indicates a negative influence. + * + * @param svmrModelDetails svm regression model details object + * @exception JDMException if failed to retrieve model details + */ + public static void displaySVMRModelDetails(Model model) + throws JDMException + { + SVMRegressionModelDetail svmrModelDetails = + (SVMRegressionModelDetail)model.getModelDetail(); + // Is linear model? + System.out.println("Is linear model? " + svmrModelDetails.isLinearSVMModel() ); + // Attribute coefficient value will be available if it is a linear model + if (svmrModelDetails.isLinearSVMModel()) + { + System.out.println("Model Deatils: ( Attribute Name, Attribute Value, Coefficient)"); + MessageFormat mfDetails = new MessageFormat(" ( {0}, {1}, {2}, {3} )"); + String[] vals = new String[4]; + // Print bias by invoking getBias method. + vals[0] = ""; + vals[1] = ""; + vals[2] = m_df.format(svmrModelDetails.getBias()) + " (Bias)"; + System.out.println( mfDetails.format(vals) ); + //Get the signature attributes + ModelSignature modelSignature = model.getSignature(); + Collection sortedSet = modelSignature.getAttributes(); + Iterator attrIterator = sortedSet.iterator(); + + while(attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute)attrIterator.next(); + // Print all attribute coefficients -- The FIRST row in the SVM model + // details output shows the value for SVM bias under the COEFFICIENT + // column. + Map attrCoefficientMap = ((OraSVMRegressionModelDetail)svmrModelDetails).getCoefficients(attr.getName()); + Object[] attrVals = attrCoefficientMap.keySet().toArray(); + if(attrVals != null) { + for(int iAttr=0; iAttr < attrVals.length; iAttr++) + { + vals[0] = attr.getName(); + vals[1] = ""; + if(attrVals[iAttr] != null) + vals[1] = attrVals[iAttr].toString(); + vals[2] = ""; + Number coefficient = (Number)attrCoefficientMap.get(attrVals[iAttr]); + if(coefficient != null) + vals[2] = m_df.format(coefficient); + System.out.println( mfDetails.format(vals) ); + } + } + } + } + } + + /** + * Display regression test metrics object + * + * @param testMetrics classification test metrics object + * @exception JDMException if failed to retrieve test metric details + */ + public static void displayTestMetricDetails( + RegressionTestMetrics testMetrics) throws JDMException + { + //Retrieve Oracle SVMR model test metrics deatils extensions + // Name + System.out.println("Test Metrics Name = " + testMetrics.getName()); + // Model Name + System.out.println("Model Name = " + testMetrics.getModelName()); + // Test Data Name + System.out.println("Test Data Name = " + testMetrics.getTestDataName()); + // Mean Absolute Error + System.out.println("Mean Absolute Error = " + m_df.format(testMetrics.getMeanAbsoluteError().doubleValue())); + // Mean Actual Value + System.out.println("Mean Actual Value = " + m_df.format(testMetrics.getMeanActualValue().doubleValue())); + // Mean Predicted Value + System.out.println("Mean Predicted Value = " + m_df.format(testMetrics.getMeanPredictedValue().doubleValue())); + // Root Mean Squared Error + System.out.println("Root Mean Squared Error = " + m_df.format(testMetrics.getRMSError().doubleValue())); + } + + private static void displayTable(String tableName, String whereCause, String orderByColumn) + { + StringBuffer emptyCol = new StringBuffer(" "); + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + PreparedStatement pStmt = null; + ResultSet rs = null; + try + { + pStmt = dbConn.prepareStatement("SELECT * FROM " + tableName + " " + whereCause + " " + orderByColumn); + rs = pStmt.executeQuery(); + ResultSetMetaData rsMeta = rs.getMetaData(); + int colCount = rsMeta.getColumnCount(); + StringBuffer header = new StringBuffer(); + System.out.println("Table : " + tableName); + // Build table header + for(int iCol=1; iCol<=colCount; iCol++) + { + String colName = rsMeta.getColumnName(iCol); + header.append(emptyCol.replace(0, colName.length(), colName)); + emptyCol = new StringBuffer(" "); + } + System.out.println(header.toString()); + // Write table data + while(rs.next()) + { + StringBuffer rowContent = new StringBuffer(); + for(int iCol=1; iCol<=colCount; iCol++) + { + int sqlType = rsMeta.getColumnType(iCol); + Object obj = rs.getObject(iCol); + String colContent = null; + + if(obj instanceof java.lang.Number) + { + try + { + BigDecimal bd = (BigDecimal)obj; + if(bd.scale() > 5) + { + colContent = m_df.format(obj); + } else + { + colContent = bd.toString(); + } + } catch(Exception anyExp) { + colContent = m_df.format(obj); + } + } else + { + if(obj == null) + colContent = "NULL"; + else + colContent = obj.toString(); + } + rowContent.append(" "+emptyCol.replace(0, colContent.length(), colContent)); + emptyCol = new StringBuffer(" "); + } + System.out.println(rowContent.toString()); + } + } catch(Exception anySqlExp) { + anySqlExp.printStackTrace(); + } // Ignore + } + + private static void clean() + { + //Drop the model + try { + m_dmeConn.removeObject("svmrModel_jdm", NamedObject.model); + } catch(JDMException jdmExp) {} + } +} diff --git a/dmtreedemo.java b/dmtreedemo.java new file mode 100644 index 0000000..b753d70 --- /dev/null +++ b/dmtreedemo.java @@ -0,0 +1,1230 @@ +// Copyright (c) 2004, 2006, Oracle. All rights reserved. +// File: dmtreedemo.java + +// Generic Java api imports +import java.math.BigDecimal; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; + +import java.text.DecimalFormat; +import java.text.MessageFormat; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Stack; +// Java Data Mining (JDM) standard api imports +import java.util.logging.Level; + +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.MiningAlgorithm; +import javax.datamining.MiningFunction; +import javax.datamining.NamedObject; +import javax.datamining.SizeUnit; +import javax.datamining.algorithm.tree.TreeHomogeneityMetric; +import javax.datamining.algorithm.tree.TreeSettings; +import javax.datamining.algorithm.tree.TreeSettingsFactory; +import javax.datamining.base.AlgorithmSettings; +import javax.datamining.base.Model; +import javax.datamining.base.Task; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.CategoryProperty; +import javax.datamining.data.CategorySet; +import javax.datamining.data.CategorySetFactory; +import javax.datamining.data.ModelSignature; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.data.SignatureAttribute; +import javax.datamining.modeldetail.tree.TreeModelDetail; +import javax.datamining.modeldetail.tree.TreeNode; +import javax.datamining.resource.Connection; +import javax.datamining.resource.ConnectionFactory; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.rule.Predicate; +import javax.datamining.rule.Rule; +import javax.datamining.supervised.classification.ClassificationApplySettings; +import javax.datamining.supervised.classification.ClassificationApplySettingsFactory; +import javax.datamining.supervised.classification.ClassificationModel; +import javax.datamining.supervised.classification.ClassificationSettings; +import javax.datamining.supervised.classification.ClassificationSettingsFactory; +import javax.datamining.supervised.classification.ClassificationTestMetricOption; +import javax.datamining.supervised.classification.ClassificationTestMetrics; +import javax.datamining.supervised.classification.ClassificationTestMetricsTask; +import javax.datamining.supervised.classification.ClassificationTestMetricsTaskFactory; +import javax.datamining.supervised.classification.ClassificationTestTaskFactory; +import javax.datamining.supervised.classification.ConfusionMatrix; +import javax.datamining.supervised.classification.CostMatrix; +import javax.datamining.supervised.classification.CostMatrixFactory; +import javax.datamining.supervised.classification.Lift; +import javax.datamining.supervised.classification.ReceiverOperatingCharacterics; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; +import javax.datamining.task.apply.DataSetApplyTask; +import javax.datamining.task.apply.DataSetApplyTaskFactory; +// Oracle Java Data Mining (JDM) implemented api imports +import oracle.dmt.jdm.algorithm.tree.OraTreeSettings; +import oracle.dmt.jdm.base.OraTask; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.modeldetail.tree.OraTreeModelDetail; +import oracle.dmt.jdm.supervised.classification.OraClassificationTestMetrics; +import oracle.dmt.jdm.supervised.classification.OraLift; + +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to solve a classification problem using Decision Tree (DT) algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* How to predict whether a customer responds or not to the new affinity card +* program using a classifier based on DT algorithm? +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the previous affinity card +* programs. Data exploration and preparing the data is a common step before +* doing data mining. Here in this demo, the following views are created in the user +* schema using CUSTOMERS, COUNTRIES, and SUPPLIMENTARY_DEMOGRAPHICS tables. +* +* MINING_DATA_BUILD_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for building the model. +* +* MINING_DATA_TEST_V: +* This view collects the previous customers' demographics, purchasing, and affinity +* card response details for testing the model. +* +* MINING_DATA_APPLY_V: +* This view collects the prospective customers' demographics and purchasing +* details for predicting response for the new affinity card program. +* +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Prepare Data: +* For decision tree data mining specific data preparations are done +* implicitely, user needs to do only required data cleansing, derived +* attributes etc. as part of the ETL. +* +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a classification model using DT algorithm. +* +* Test Model: +* Classification model performance can be evaluated by computing test +* metrics like accuracy, confusion matrix, lift and ROC. The testModel() or +* computeTestMetrics() method illustrates how to perform a test operation to +* compute various metrics. +* +* Apply Model: +* Predicting the target attribute values is the prime function of +* classification models. The applyModel() method illustrates how to +* predict the customer response for affinity card program. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +public class + +dmtreedemo +{ + //Connection related data members + private static Connection m_dmeConn; + private static ConnectionFactory m_dmeConnFactory; + //Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static ClassificationSettingsFactory m_clasFactory; + private static TreeSettingsFactory m_treeFactory; + private static BuildTaskFactory m_buildFactory; + private static DataSetApplyTaskFactory m_dsApplyFactory; + private static ClassificationTestTaskFactory m_testFactory; + private static ClassificationApplySettingsFactory m_applySettingsFactory; + private static CostMatrixFactory m_costMatrixFactory; + private static CategorySetFactory m_catSetFactory; + private static ClassificationTestMetricsTaskFactory m_testMetricsTaskFactory; + // Global constants + private static DecimalFormat m_df = new DecimalFormat("##.####"); + private static String m_costMatrixName = null; + + public static void main(String[] args) + { + try + { + if (args.length != 3) + { + System.out.println("Usage: java dmtreedemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + // 1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@" + uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + ((OraConnection) m_dmeConn).getLogger().setLevel(Level.FINEST); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + m_costMatrixName = createCostMatrix(); + // 4. Create and save task to build the model + buildModel(); + // 5. Create and save task to test model and add build task + // as its parent task. + computeTestMetrics("DT_TEST_APPLY_OUTPUT_JDM", m_costMatrixName); + // 6. Create and save task to apply the model + applyModel(); + //7. Start execution of the build task that trigger execution of + // its dependent task(s), here after completion of the build task + // test task starts executing and then apply task. + m_dmeConn.execute("treeBuildTask_jdm"); + //8. Monitor the task executions of current and its dependent tasks + // and display task output results + monitorTaskExecutionProcess(); + + } + catch (Exception anyExp) + { + anyExp.printStackTrace(System.out); + } + finally + { + try + { + //6. Logout from the Data Mining Engine + m_dmeConn.close(); + } + catch (Exception anyExp1) + { + //Ignore + } + } + } + + /** + * Initialize all object factories used in the demo program. + * + * @exception JDMException if factory initalization failed + */ + public static void initFactories() + throws JDMException + { + m_pdsFactory = + (PhysicalDataSetFactory) m_dmeConn.getFactory("javax.datamining.data.PhysicalDataSet"); + m_paFactory = + (PhysicalAttributeFactory) m_dmeConn.getFactory("javax.datamining.data.PhysicalAttribute"); + m_clasFactory = + (ClassificationSettingsFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.ClassificationSettings"); + m_treeFactory = + (TreeSettingsFactory) m_dmeConn.getFactory("javax.datamining.algorithm.tree.TreeSettings"); + m_buildFactory = + (BuildTaskFactory) m_dmeConn.getFactory("javax.datamining.task.BuildTask"); + m_dsApplyFactory = + (DataSetApplyTaskFactory) m_dmeConn.getFactory("javax.datamining.task.apply.DataSetApplyTask"); + m_testFactory = + (ClassificationTestTaskFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.ClassificationTestTask"); + m_applySettingsFactory = + (ClassificationApplySettingsFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.ClassificationApplySettings"); + m_costMatrixFactory = + (CostMatrixFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.CostMatrix"); + m_catSetFactory = + (CategorySetFactory) m_dmeConn.getFactory("javax.datamining.data.CategorySet"); + m_testMetricsTaskFactory = + (ClassificationTestMetricsTaskFactory) m_dmeConn.getFactory("javax.datamining.supervised.classification.ClassificationTestMetricsTask"); + } + + /** + * Create and save cost matrix. + * + * Consider an example where it costs $10 to mail a promotion to a + * prospective customer and if the prospect becomes a customer, the + * typical sale including the promotion, is worth $100. Then the cost + * of missing a customer (i.e. missing a $100 sale) is 10x that of + * incorrectly indicating that a person is good prospect (spending + * $10 for the promo). In this case, all prediction errors made by + * the model are NOT equal. To act on what the model determines to + * be the most likely (probable) outcome may be a poor choice. + * + * Suppose that the probability of a BUY reponse is 10% for a given + * prospect. Then the expected revenue from the prospect is: + * .10 * $100 - .90 * $10 = $1. + * + * The optimal action, given the cost matrix, is to simply mail the + * promotion to the customer, because the action is profitable ($1). + * + * In contrast, without the cost matrix, all that can be said is + * that the most likely response is NO BUY, so don't send the + * promotion. This shows that cost matrices can be very important. + * + * The caveat in all this is that the model predicted probabilities + * may NOT be accurate. For binary targets, a systematic approach to + * this issue exists. It is ROC, illustrated below. + * + * With ROC computed on a test set, the user can see how various model + * predicted probability thresholds affect the action of mailing a promotion. + * Suppose I promote when the probability to BUY exceeds 5, 10, 15%, etc. + * what return can I expect? Note that the answer to this question does + * not rely on the predicted probabilities being accurate, only that + * they are in approximately the correct rank order. + * + * Assuming that the predicted probabilities are accurate, provide the + * cost matrix table name as input to the RANK_APPLY procedure to get + * appropriate costed scoring results to determine the most appropriate + * action. + * + * In this demo, we will create the following cost matrix + * + * ActualTarget PredictedTarget Cost + * ------------ --------------- ---- + * 0 0 0 + * 0 1 1 + * 1 0 8 + * 1 1 0 + */ + private static String createCostMatrix() + throws JDMException + { + String costMatrixName = "treeCostMatrix"; + // Create categorySet + CategorySet catSet = + m_catSetFactory.create(AttributeDataType.integerType); + // Add category values + catSet.addCategory(new Integer(0), CategoryProperty.valid); + catSet.addCategory(new Integer(1), CategoryProperty.valid); + // Create cost matrix + CostMatrix costMatrix = m_costMatrixFactory.create(catSet); + // ActualTarget PredictedTarget Cost + // ------------ --------------- ---- + costMatrix.setCellValue(new Integer(0), new Integer(0), 0); + costMatrix.setCellValue(new Integer(0), new Integer(1), 1); + costMatrix.setCellValue(new Integer(1), new Integer(0), 8); + costMatrix.setCellValue(new Integer(1), new Integer(1), 0); + //save cost matrix + m_dmeConn.saveObject(costMatrixName, costMatrix, true); + return costMatrixName; + } + + /** + * This method illustrates how to build a mining model using the + * MINING_DATA_BUILD_V dataset and classification settings with + * DT algorithm. + * + * @exception JDMException if model build failed + */ + public static void buildModel() + throws JDMException + { + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = + m_pdsFactory.create("MINING_DATA_BUILD_V", false); + PhysicalAttribute pa = + m_paFactory.create("CUST_ID", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + buildData.addAttribute(pa); + m_dmeConn.saveObject("treeBuildData_jdm", buildData, true); + //2. Create & save Mining Function Settings + // + // Create default tree algorithm settings + TreeSettings treeAlgo = m_treeFactory.create(); + // Set cost matrix. A cost matrix is used to influence the weighting of + // misclassification during model creation (and scoring). + // See Oracle Data Mining Concepts Guide for more details. + // + String costMatrixName = m_costMatrixName; + // + // Create ClassificationSettings + ClassificationSettings buildSettings = m_clasFactory.create(); + buildSettings.setAlgorithmSettings(treeAlgo); + buildSettings.setCostMatrixName(costMatrixName); + buildSettings.setTargetAttributeName("AFFINITY_CARD"); + m_dmeConn.saveObject("treeBuildSettings_jdm", buildSettings, true); + // 3. Create, save & execute Build Task + BuildTask buildTask = + m_buildFactory.create("treeBuildData_jdm", "treeBuildSettings_jdm", + "treeModel_jdm"); + buildTask.setDescription("treeBuildTask_jdm"); + saveTask(buildTask, "treeBuildTask_jdm", null); + } + + + /** + * This method illustrates how to compute test metrics using + * an apply output table that has actual and predicted target values. Here the + * apply operation is done on the MINING_DATA_TEST_V dataset. It creates + * an apply output table with actual and predicted target values. Using + * ClassificationTestMetricsTask test metrics are computed. This produces + * the same test metrics results as ClassificationTestTask. + * + * @param applyOutputName apply output table name + * @param costMatrixName table name of the supplied cost matrix + * + * @exception JDMException if model test failed + */ + public static void computeTestMetrics(String applyOutputName, + String costMatrixName) + throws JDMException + { + // 1. Do the apply on test data to create an apply output table + // Create & save PhysicalDataSpecification + PhysicalDataSet applyData = + m_pdsFactory.create("MINING_DATA_TEST_V", false); + PhysicalAttribute pa = + m_paFactory.create("CUST_ID", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + applyData.addAttribute(pa); + m_dmeConn.saveObject("treeTestApplyData_jdm", applyData, true); + // 2 Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + HashMap sourceAttrMap = new HashMap(); + sourceAttrMap.put("AFFINITY_CARD", "AFFINITY_CARD"); + clasAS.setSourceDestinationMap(sourceAttrMap); + m_dmeConn.saveObject("treeTestApplySettings_jdm", clasAS, true); + // 3 Create, store & execute apply Task + DataSetApplyTask applyTask = + m_dsApplyFactory.create("treeTestApplyData_jdm", "treeModel_jdm", + "treeTestApplySettings_jdm", + applyOutputName); + saveTask(applyTask, "treeTestApplyTask_jdm", "treeBuildTask_jdm"); + + { + // Compute test metrics on new created apply output table + // 4. Create & save PhysicalDataSpecification + PhysicalDataSet applyOutputData = + m_pdsFactory.create(applyOutputName, false); + applyOutputData.addAttribute(pa); + m_dmeConn.saveObject("treeTestApplyOutput_jdm", applyOutputData, + true); + // 5. Create a ClassificationTestMetricsTask + ClassificationTestMetricsTask testMetricsTask = + // apply output data used as input + // actual target column + // predicted target column + // test metrics result name + m_testMetricsTaskFactory.create("treeTestApplyOutput_jdm", + "AFFINITY_CARD", "PREDICTION", + "dtTestMetrics_jdm"); // enable confusion matrix computation + testMetricsTask.computeMetric(ClassificationTestMetricOption.confusionMatrix, + true); // enable lift computation + testMetricsTask.computeMetric(ClassificationTestMetricOption.lift, + true); // enable ROC computation + testMetricsTask.computeMetric(ClassificationTestMetricOption.receiverOperatingCharacteristics, + true); + //testMetricsTask.setPositiveTargetValue(new Integer(1)); + testMetricsTask.setNumberOfLiftQuantiles(10); + testMetricsTask.setPredictionRankingAttrName("PROBABILITY"); + // Store & execute the task + saveTask(testMetricsTask, "treeTestMetricsTask_jdm", + "treeTestApplyTask_jdm"); + if (costMatrixName != null) + { + ClassificationTestMetricsTask testMetricsCostTask = + // apply output data used as input + // actual target column + // predicted target column + // test metrics result name + m_testMetricsTaskFactory.create("treeTestApplyOutput_jdm", + "AFFINITY_CARD", "PREDICTION", + "dtTestMetricsWithCost_jdm"); // enable confusion matrix computation + testMetricsCostTask.computeMetric(ClassificationTestMetricOption.confusionMatrix, + true); // enable lift computation + testMetricsCostTask.computeMetric(ClassificationTestMetricOption.lift, + true); // enable ROC computation + testMetricsCostTask.computeMetric(ClassificationTestMetricOption.receiverOperatingCharacteristics, + true); + //testMetricsCostTask.setPositiveTargetValue(new Integer(1)); + testMetricsCostTask.setNumberOfLiftQuantiles(10); + testMetricsCostTask.setPredictionRankingAttrName("PROBABILITY"); + testMetricsCostTask.setCostMatrixName(costMatrixName); + saveTask(testMetricsCostTask, "treeTMWithCostTask_jdm", + "treeTestApplyTask_jdm"); + } + } + } + + + /** + * This method illustrates how to apply the mining model on the + * MINING_DATA_APPLY_V dataset to predict customer + * response. After completion of the task apply output table with the + * predicted results is created at the user specified location. + * + * @exception JDMException if model apply failed + */ + public static void applyModel() + throws JDMException + { + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = + m_pdsFactory.create("MINING_DATA_APPLY_V", false); + PhysicalAttribute pa = + m_paFactory.create("CUST_ID", AttributeDataType.integerType, + PhysicalAttributeRole.caseId); + applyData.addAttribute(pa); + m_dmeConn.saveObject("treeApplyData_jdm", applyData, true); + // 2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + // Add source attributes + HashMap sourceAttrMap = new HashMap(); + sourceAttrMap.put("COUNTRY_NAME", "COUNTRY_NAME"); + clasAS.setSourceDestinationMap(sourceAttrMap); + // Add cost matrix + clasAS.setCostMatrixName(m_costMatrixName); + m_dmeConn.saveObject("treeApplySettings_jdm", clasAS, true); + // 3. Create, store & execute apply Task + DataSetApplyTask applyTask = + m_dsApplyFactory.create("treeApplyData_jdm", "treeModel_jdm", + "treeApplySettings_jdm", + "TREE_APPLY_OUTPUT1_JDM"); + saveTask(applyTask, "treeApplyTask1_jdm", "treeBuildTask_jdm"); + + + // 1. Create & save PhysicalDataSpecification + applyData = m_pdsFactory.create("MINING_DATA_APPLY_V", false); + pa = + m_paFactory.create("CUST_ID", AttributeDataType.integerType, PhysicalAttributeRole.caseId); + applyData.addAttribute(pa); + m_dmeConn.saveObject("treeApplyData_jdm", applyData, true); + // 2. Create & save ClassificationApplySettings + clasAS = m_applySettingsFactory.create(); + // Add cost matrix + clasAS.setCostMatrixName(m_costMatrixName); + m_dmeConn.saveObject("treeApplySettings_jdm", clasAS, true); + // 3. Create, store & execute apply Task + applyTask = + m_dsApplyFactory.create("treeApplyData_jdm", "treeModel_jdm", + "treeApplySettings_jdm", + "TREE_APPLY_OUTPUT2_JDM"); + saveTask(applyTask, "treeApplyTask2_jdm", "treeBuildTask_jdm"); + + + // 1. Create & save PhysicalDataSpecification + applyData = m_pdsFactory.create("MINING_DATA_APPLY_V", false); + pa = + m_paFactory.create("CUST_ID", AttributeDataType.integerType, PhysicalAttributeRole.caseId); + applyData.addAttribute(pa); + m_dmeConn.saveObject("treeApplyData_jdm", applyData, true); + // 2. Create & save ClassificationApplySettings + clasAS = m_applySettingsFactory.create(); + // Add source attributes + sourceAttrMap = new HashMap(); + sourceAttrMap.put("AGE", "AGE"); + sourceAttrMap.put("OCCUPATION", "OCCUPATION"); + clasAS.setSourceDestinationMap(sourceAttrMap); + m_dmeConn.saveObject("treeApplySettings_jdm", clasAS, true); + // 3. Create, store & execute apply Task + applyTask = + m_dsApplyFactory.create("treeApplyData_jdm", "treeModel_jdm", + "treeApplySettings_jdm", + "TREE_APPLY_OUTPUT3_JDM"); + saveTask(applyTask, "treeApplyTask3_jdm", "treeBuildTask_jdm"); + + } + + /** + * This method saves the given task with the specified task name and task + * dependency (parent task) in the DME. + * + * @param taskObj task object + * @param taskName name of the task + * @param parentTaskName name of the parent task + * + * @return boolean returns true when the task is successful + * @exception JDMException if task execution failed + */ + public static void saveTask(Task taskObj, String taskName, + String parentTaskName) + throws JDMException + { + if (parentTaskName != null) + ((OraTask) taskObj).addDependency(parentTaskName); //Since OJDM 11.1 + //if (!(taskObj instanceof BuildTask)) + ((OraTask) taskObj).overwriteOutput(true); //Since OJDM 11.1 + m_dmeConn.saveObject(taskName, taskObj, true); + } + + /** + * This method monitor task execution initiated by the first task + * in the sequence of dependent tasks. In addition, this method displays + * task output results (if any). + * @throws JDMException + */ + public static void monitorTaskExecutionProcess() + throws JDMException + { + //BuildTask + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of treeBuildTask_jdm. "); + ExecutionStatus buildTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("treeBuildTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(buildTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + displayModelDetails(); + + //If model build is successful, then do testData ApplyTask + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of treeTestApplyTask_jdm. "); + ExecutionStatus testApplyTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("treeTestApplyTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(testApplyTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + //If testdata apply is successful, then wait for its child test metrics tasks + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of treeTestMetricsTask_jdm. "); + ExecutionStatus testTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("treeTestMetricsTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(testTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + displayTestMetrics("dtTestMetrics_jdm", null); + } + else + { + System.out.println("It is at state:" + + testTaskCompletionStatus.getState().name() + + ((testTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + testTaskCompletionStatus.getDescription())); + } + + //TestMetricsTask with cost matrix + //1. Wait for the completion of the task + System.out.print("Waiting for the completion of treeTMWithCostTask_jdm. "); + ExecutionStatus tmCostTaskCompletionStatus = + m_dmeConn.getLastExecutionHandle("treeTMWithCostTask_jdm").waitForCompletion(Integer.MAX_VALUE); + //2. If successful + if (ExecutionState.success.equals(tmCostTaskCompletionStatus.getState())) + { + System.out.println("It is successful. "); + displayTestMetrics("dtTestMetricsWithCost_jdm", m_costMatrixName); + //If test metrics task is successful, then run the apply tasks + //ApplyTask(s) + //Waiting for all apply tasks to complete + ExecutionStatus applyTask1Status = + m_dmeConn.getLastExecutionHandle("treeApplyTask1_jdm").waitForCompletion(Integer.MAX_VALUE); + ExecutionStatus applyTask2Status = + m_dmeConn.getLastExecutionHandle("treeApplyTask2_jdm").waitForCompletion(Integer.MAX_VALUE); + ExecutionStatus applyTask3Status = + m_dmeConn.getLastExecutionHandle("treeApplyTask3_jdm").waitForCompletion(Integer.MAX_VALUE); + if (ExecutionState.success.equals(applyTask1Status.getState()) && + ExecutionState.success.equals(applyTask2Status.getState()) && + ExecutionState.success.equals(applyTask3Status.getState())) + { + displayApplyResults(); + } + else + { + System.out.println("treeApplyTask1_jdm is at state:" + + applyTask1Status.getState().name() + + ((applyTask1Status.getDescription() == + null)? "": + "State Description:" + applyTask1Status.getDescription())); + System.out.println("treeApplyTask2_jdm is at state:" + + applyTask2Status.getState().name() + + ((applyTask2Status.getDescription() == + null)? "": + "State Description:" + applyTask2Status.getDescription())); + System.out.println("treeApplyTask3_jdm is at state:" + + applyTask3Status.getState().name() + + ((applyTask3Status.getDescription() == + null)? "": + "State Description:" + applyTask3Status.getDescription())); + } + } + else + { + System.out.println("It is at state:" + + tmCostTaskCompletionStatus.getState().name() + + ((tmCostTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + tmCostTaskCompletionStatus.getDescription())); + } + + + } + else + { + System.out.println("It is at state:" + + testApplyTaskCompletionStatus.getState().name() + + ((testApplyTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + testApplyTaskCompletionStatus.getDescription())); + } + } + else + { + System.out.println("It is at state:" + + buildTaskCompletionStatus.getState().name() + + ((buildTaskCompletionStatus.getDescription() == + null)? "": + "State Description:" + buildTaskCompletionStatus.getDescription())); + } + } + + public static void trackTaskExecution(String taskName, + ExecutionHandle execHandle) + throws JDMException + { + System.out.print(taskName + " is started, please wait. "); + //Wait for completion of the task + ExecutionStatus status = + execHandle.waitForCompletion(Integer.MAX_VALUE); + //Check the status of the task after completion + boolean isTaskSuccess = + status.getState().equals(ExecutionState.success); + if (isTaskSuccess) //Task completed successfully + System.out.println(taskName + " is successful."); + else //Task failed + System.out.println(taskName + " failed.\nFailure Description: " + + status.getDescription()); + } + + private static void displayBuildSettings(ClassificationSettings clasSettings, + String buildSettingsName) + { + System.out.println("BuildSettings Details from the " + + buildSettingsName + " table:"); + displayTable(buildSettingsName, "", "order by SETTING_NAME"); + System.out.println("BuildSettings Details from the " + + buildSettingsName + + " model build settings object:"); + String objName = clasSettings.getName(); + if (objName != null) + System.out.println("Name = " + objName); + String objDescription = clasSettings.getDescription(); + if (objDescription != null) + System.out.println("Description = " + objDescription); + java.util.Date creationDate = clasSettings.getCreationDate(); + String creator = clasSettings.getCreatorInfo(); + String targetAttrName = clasSettings.getTargetAttributeName(); + System.out.println("Target attribute name = " + targetAttrName); + AlgorithmSettings algoSettings = clasSettings.getAlgorithmSettings(); + if (algoSettings == null) + System.out.println("Failure: clasSettings.getAlgorithmSettings() returns null"); + MiningAlgorithm algo = algoSettings.getMiningAlgorithm(); + if (algo == null) + System.out.println("Failure: algoSettings.getMiningAlgorithm() returns null"); + System.out.println("Algorithm Name: " + algo.name()); + MiningFunction function = clasSettings.getMiningFunction(); + if (function == null) + System.out.println("Failure: clasSettings.getMiningFunction() returns null"); + System.out.println("Function Name: " + function.name()); + try + { + String costMatrixName = clasSettings.getCostMatrixName(); + if (costMatrixName != null) + { + System.out.println("Cost Matrix Details from the " + + costMatrixName + " table:"); + displayTable(costMatrixName, "", + "order by ACTUAL_TARGET_VALUE, PREDICTED_TARGET_VALUE"); + } + } + catch (Exception jdmExp) + { + System.out.println("Failure: clasSettings.getCostMatrixName()throws exception"); + jdmExp.printStackTrace(); + } + // List of DT algorithm settings + // treeAlgo.setBuildHomogeneityMetric(TreeHomogeneityMetric.gini); + // treeAlgo.setMaxDepth(7); + // ((OraTreeSettings)treeAlgo).setMinDecreaseInImpurity(0.1, SizeUnit.percentage); + // treeAlgo.setMinNodeSize( 0.05, SizeUnit.percentage ); + // treeAlgo.setMinNodeSize( 10, SizeUnit.count ); + // ((OraTreeSettings)treeAlgo).setMinDecreaseInImpurity(20, SizeUnit.count); + TreeHomogeneityMetric homogeneityMetric = + ((OraTreeSettings) algoSettings).getBuildHomogeneityMetric(); + System.out.println("Homogeneity Metric: " + homogeneityMetric.name()); + int intValue = ((OraTreeSettings) algoSettings).getMaxDepth(); + System.out.println("Max Depth: " + intValue); + double doubleValue = + ((OraTreeSettings) algoSettings).getMinNodeSizeForSplit(SizeUnit.percentage); + System.out.println("MinNodeSizeForSplit (percentage): " + + m_df.format(doubleValue)); + doubleValue = + ((OraTreeSettings) algoSettings).getMinNodeSizeForSplit(SizeUnit.count); + System.out.println("MinNodeSizeForSplit (count): " + + m_df.format(doubleValue)); + /* + doubleValue = ((OraTreeSettings)algoSettings).getMinNodeSize(); + SizeUnit unit = ((OraTreeSettings)algoSettings).getMinNodeSizeUnit(); + System.out.println("Min Node Size (" + unit.name() +"): " + m_df.format(doubleValue)); + */ + doubleValue = + ((OraTreeSettings) algoSettings).getMinNodeSize(SizeUnit.count); + System.out.println("Min Node Size (" + SizeUnit.count.name() + "): " + + m_df.format(doubleValue)); + doubleValue = + ((OraTreeSettings) algoSettings).getMinNodeSize(SizeUnit.percentage); + System.out.println("Min Node Size (" + SizeUnit.percentage.name() + + "): " + m_df.format(doubleValue)); + } + + /** + * This method displayes DT model signature. + * + * @param model model object + * @exception JDMException if failed to retrieve model signature + */ + public static void displayModelSignature(Model model) + throws JDMException + { + String modelName = model.getName(); + System.out.println("Model Name: " + modelName); + ModelSignature modelSignature = model.getSignature(); + System.out.println("ModelSignature Deatils: ( Attribute Name, Attribute Type )"); + MessageFormat mfSign = + new MessageFormat(" ( {0}, {1} )"); + String[] vals = new String[3]; + Collection sortedSet = modelSignature.getAttributes(); + Iterator attrIterator = sortedSet.iterator(); + while (attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute) attrIterator.next(); + vals[0] = attr.getName(); + vals[1] = attr.getDataType().name(); + System.out.println(mfSign.format(vals)); + } + } + + public static void displayModelDetails() + throws JDMException + { + //4. Restore the model from the DME and explore the details of the model + ClassificationModel model = + (ClassificationModel) m_dmeConn.retrieveObject("treeModel_jdm", + NamedObject.model); + // Display model build settings + ClassificationSettings retrievedBuildSettings = + (ClassificationSettings) model.getBuildSettings(); + if (retrievedBuildSettings == null) + System.out.println("Failure to restore build settings."); + else + displayBuildSettings(retrievedBuildSettings, + "treeBuildSettings_jdm"); + // Display model signature + displayModelSignature((Model) model); + // Display model detail + TreeModelDetail treeModelDetails = + (TreeModelDetail) model.getModelDetail(); + displayTreeModelDetailsExtensions(treeModelDetails); + } + + + /** + * This method displayes DT model details. + * + * @param treeModelDetails tree model details object + * @exception JDMException if failed to retrieve model details + */ + public static void displayTreeModelDetailsExtensions(TreeModelDetail treeModelDetails) + throws JDMException + { + System.out.println("\nTreeModelDetail: Model name=" + "treeModel_jdm"); + TreeNode root = treeModelDetails.getRootNode(); + System.out.println("\nRoot node: " + root.getIdentifier()); + + // get the info for the tree model + int treeDepth = ((OraTreeModelDetail) treeModelDetails).getTreeDepth(); + System.out.println("Tree depth: " + treeDepth); + int totalNodes = + ((OraTreeModelDetail) treeModelDetails).getNumberOfNodes(); + System.out.println("Total number of nodes: " + totalNodes); + int totalLeaves = + ((OraTreeModelDetail) treeModelDetails).getNumberOfLeafNodes(); + System.out.println("Total number of leaf nodes: " + totalLeaves); + + Stack nodeStack = new Stack(); + nodeStack.push(root); + while (!nodeStack.empty()) + { + TreeNode node = (TreeNode) nodeStack.pop(); + // display this node + int nodeId = node.getIdentifier(); + long caseCount = node.getCaseCount(); + Object prediction = node.getPrediction(); + int level = node.getLevel(); + int children = node.getNumberOfChildren(); + TreeNode parent = node.getParent(); + System.out.println("\nNode id=" + nodeId + " at level " + level); + if (parent != null) + System.out.println("parent: " + parent.getIdentifier() + + ", children=" + children); + System.out.println("Case count: " + caseCount + ", prediction: " + + prediction); + Predicate predicate = node.getPredicate(); + System.out.println("Predicate: " + predicate.toString()); + Predicate[] surrogates = node.getSurrogates(); + if (surrogates != null) + for (int i = 0; i < surrogates.length; i++) + System.out.println("Surrogate[" + i + "]: " + surrogates[i]); + // add child nodes in the stack + if (children > 0) + { + TreeNode[] childNodes = node.getChildren(); + for (int i = 0; i < childNodes.length; i++) + nodeStack.push(childNodes[i]); + } + } + + TreeNode[] allNodes = treeModelDetails.getNodes(); + System.out.print("\nNode identifiers by getNodes():"); + for (int i = 0; i < allNodes.length; i++) + System.out.print(" " + allNodes[i].getIdentifier()); + System.out.println(); + + // display the node identifiers + int[] nodeIds = treeModelDetails.getNodeIdentifiers(); + System.out.print("Node identifiers by getNodeIdentifiers():"); + for (int i = 0; i < nodeIds.length; i++) + System.out.print(" " + nodeIds[i]); + System.out.println(); + + TreeNode node = treeModelDetails.getNode(nodeIds.length - 1); + System.out.println("Node identifier by getNode(" + + (nodeIds.length - 1) + "): " + + node.getIdentifier()); + Rule rule2 = treeModelDetails.getRule(nodeIds.length - 1); + System.out.println("Rule identifier by getRule(" + + (nodeIds.length - 1) + "): " + + rule2.getRuleIdentifier()); + + // get the rules and display them + Collection ruleColl = treeModelDetails.getRules(); + Iterator ruleIterator = ruleColl.iterator(); + while (ruleIterator.hasNext()) + { + Rule rule = (Rule) ruleIterator.next(); + int ruleId = rule.getRuleIdentifier(); + Predicate antecedent = (Predicate) rule.getAntecedent(); + Predicate consequent = (Predicate) rule.getConsequent(); + System.out.println("\nRULE " + ruleId + ": support=" + + rule.getSupport() + " (abs=" + + rule.getAbsoluteSupport() + "), confidence=" + + rule.getConfidence()); + System.out.println(antecedent); + System.out.println("=======>"); + System.out.println(consequent); + } + } + + public static void displayTestMetrics(String metricsName, + String costMatrixName) + throws JDMException + { + if (costMatrixName != null) + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Test Model - using apply output table ---"); + System.out.println("--- - using cost matrix table ---"); + System.out.println("---------------------------------------------------"); + } + else + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Test Model - using apply output table ---"); + System.out.println("--- - using no cost matrix table ---"); + System.out.println("---------------------------------------------------"); + } + // Restore & display test metrics + ClassificationTestMetrics testMetrics = + (ClassificationTestMetrics) m_dmeConn.retrieveObject(metricsName, + NamedObject.testMetrics); + // Display classification test metrics + displayTestMetricDetails(testMetrics); + } + + /** + * Display classification test metrics object + * + * @param testMetrics classification test metrics object + * @exception JDMException if failed to retrieve test metric details + */ + public static void displayTestMetricDetails(ClassificationTestMetrics testMetrics) + throws JDMException + { + // Retrieve Oracle ABN model test metrics deatils extensions + // Test Metrics Name + System.out.println("Test Metrics Name = " + testMetrics.getName()); + // Model Name + System.out.println("Model Name = " + testMetrics.getModelName()); + // Test Data Name + System.out.println("Test Data Name = " + + testMetrics.getTestDataName()); + // Accuracy + System.out.println("Accuracy = " + + m_df.format(testMetrics.getAccuracy().doubleValue())); + // Confusion Matrix + ConfusionMatrix confusionMatrix = testMetrics.getConfusionMatrix(); + Collection categories = confusionMatrix.getCategories(); + Iterator xIterator = categories.iterator(); + System.out.println("Confusion Matrix: Accuracy = " + + m_df.format(confusionMatrix.getAccuracy())); + System.out.println("Confusion Matrix: Error = " + + m_df.format(confusionMatrix.getError())); + System.out.println("Confusion Matrix:( Actual, Prection, Value )"); + MessageFormat mf = + new MessageFormat(" ( {0}, {1}, {2} )"); + String[] vals = new String[3]; + while (xIterator.hasNext()) + { + Object actual = xIterator.next(); + vals[0] = actual.toString(); + Iterator yIterator = categories.iterator(); + while (yIterator.hasNext()) + { + Object predicted = yIterator.next(); + vals[1] = predicted.toString(); + long number = + confusionMatrix.getNumberOfPredictions(actual, predicted); + vals[2] = Long.toString(number); + System.out.println(mf.format(vals)); + } + } + // Lift + Lift lift = ((OraClassificationTestMetrics)testMetrics).getLift("1"); + System.out.println("Lift Details:"); + System.out.println("Lift: Target Attribute Name = " + + lift.getTargetAttributeName()); + System.out.println("Lift: Positive Target Value = " + + lift.getPositiveTargetValue()); + System.out.println("Lift: Total Cases = " + lift.getTotalCases()); + System.out.println("Lift: Total Positive Cases = " + + lift.getTotalPositiveCases()); + int numberOfQuantiles = lift.getNumberOfQuantiles(); + System.out.println("Lift: Number Of Quantiles = " + numberOfQuantiles); + System.out.println("Lift: ( QUANTILE_NUMBER, TOTAL_CASES, QUANTILE_PERCENT_SIZE, POSITIVE_CASES, NEGATIVE_CASES, PROBABILITY_THRESHOLD, LIFT, CUMULATIVE_LIFT, GAIN, CUMULATIVE_GAIN, TARGET_DENSITY, CUMULATIVE_TARGET_DENSITY)"); + MessageFormat mfLift = + new MessageFormat(" ( {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10} )"); + double[] totalCasesPerQuantile = ((OraLift)lift).getCases();//Total cases per quantile + double[] quantilePercentageSize = ((OraLift)lift).getPercentageSize();//Quantile pecentage size + double[] positiveCasesPerQuantile = ((OraLift)lift).getNumberOfPositiveCases();//Positive target cases per quantile + double[] negativeCasesPerQuantile = ((OraLift)lift).getNumberOfNegativeCases();//Negative target cases per quantile + double[] probabilityOrCostThresholdPerQuantile = ((OraLift)lift).getProbabilityOrCostThreshold();//Probability or cost threshold per quantile + double[] liftPerQuantile = ((OraLift)lift).getLift();//Lift values for all quantiles + double[] targetDensityPerQuantile = ((OraLift)lift).getTargetDensity();//Target densities per quantile + + double[] cumulativeLift = ((OraLift)lift).getCumulativeLift(); + double[] cumulativeGain = ((OraLift)lift).getCumulativeGain(); + double[] cumulativeTargetDensity = ((OraLift)lift).getCumulativeTargetDensity(); + + + + String[] messageParams = new String[11]; + + for (int iQuantile = 0; iQuantile < numberOfQuantiles; iQuantile++) + { + //Assign message parameters + messageParams[0] = Integer.toString(iQuantile+1); //QUANTILE_NUMBER + messageParams[1] = m_df.format(totalCasesPerQuantile[iQuantile]); //TOTAL_CASES + messageParams[2] = m_df.format(quantilePercentageSize[iQuantile]);//QUANTILE_PERCENT_SIZE + messageParams[3] = m_df.format(positiveCasesPerQuantile[iQuantile]); //POSITIVE_CASES + messageParams[4] = m_df.format(negativeCasesPerQuantile[iQuantile]); //NEGATIVE_CASES + messageParams[5] = m_df.format(probabilityOrCostThresholdPerQuantile[iQuantile]); //PROBABILITY_THRESHOLD + messageParams[6] = m_df.format(liftPerQuantile[iQuantile]); //LIFT + messageParams[7] = m_df.format(cumulativeLift[iQuantile]); //CUMULATIVE_LIFT + messageParams[8] = m_df.format(cumulativeGain[iQuantile]); //CUMULATIVE_GAIN + messageParams[9] = m_df.format(targetDensityPerQuantile[iQuantile]); //TARGET_DENSITY + messageParams[10] = m_df.format(cumulativeTargetDensity[iQuantile]); //CUMULATIVE_TARGET_DENSITY + System.out.println(mfLift.format(messageParams)); + } + // ROC + ReceiverOperatingCharacterics roc = ((OraClassificationTestMetrics)testMetrics).getROC("1"); + System.out.println("ROC Details:"); + System.out.println("ROC: Area Under Curve = " + + m_df.format(roc.getAreaUnderCurve())); + int nROCThresh = roc.getNumberOfThresholdCandidates(); + System.out.println("ROC: Number Of Threshold Candidates = " + + nROCThresh); + System.out.println("ROC: ( INDEX, PROBABILITY, TRUE_POSITIVES, FALSE_NEGATIVES, FALSE_POSITIVES, TRUE_NEGATIVES, TRUE_POSITIVE_FRACTION, FALSE_POSITIVE_FRACTION )"); + MessageFormat mfROC = + new MessageFormat(" ( {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7} )"); + String[] rocVals = new String[8]; + for (int iROC = 1; iROC <= nROCThresh; iROC++) + { + rocVals[0] = Integer.toString(iROC); //INDEX + rocVals[1] = + m_df.format(roc.getProbabilityThreshold(iROC)); //PROBABILITY + rocVals[2] = + Long.toString(roc.getPositives(iROC, true)); //TRUE_POSITIVES + rocVals[3] = + Long.toString(roc.getNegatives(iROC, false)); //FALSE_NEGATIVES + rocVals[4] = + Long.toString(roc.getPositives(iROC, false)); //FALSE_POSITIVES + rocVals[5] = + Long.toString(roc.getNegatives(iROC, true)); //TRUE_NEGATIVES + rocVals[6] = + m_df.format(roc.getHitRate(iROC)); //TRUE_POSITIVE_FRACTION + rocVals[7] = + m_df.format(roc.getFalseAlarmRate(iROC)); //FALSE_POSITIVE_FRACTION + System.out.println(mfROC.format(rocVals)); + } + } + + public static void displayApplyResults() + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Business case 1 ---"); + System.out.println("--- Find the 10 customers who live in Italy ---"); + System.out.println("--- that are least expensive to be convinced to ---"); + System.out.println("--- use an affinity card. ---"); + System.out.println("---------------------------------------------------"); + // 4. Display apply result -- Note that APPLY results do not need to be + // reverse transformed, as done in the case of model details. This is + // because class values of a classification target were not (required to + // be) binned or normalized. + // + // Find the 10 customers who live in Italy that are least expensive to be + // convinced to use an affinity card. + displayTable("TREE_APPLY_OUTPUT1_JDM", + "where COUNTRY_NAME='Italy' and ROWNUM < 11 ", + "order by COST"); + + System.out.println("---------------------------------------------------"); + System.out.println("--- Business case 2 ---"); + System.out.println("--- List ten customers (ordered by their id) ---"); + System.out.println("--- along with likelihood and cost to use or ---"); + System.out.println("--- reject the affinity card. ---"); + System.out.println("---------------------------------------------------"); + // 4. Display apply result -- Note that APPLY results do not need to be + // reverse transformed, as done in the case of model details. This is + // because class values of a classification target were not (required to + // be) binned or normalized. + // + // List ten customers (ordered by their id) along with likelihood and cost + // to use or reject the affinity card (Note: while this example has a + // binary target, such a query is useful in multi-class classification - + // Low, Med, High for example). + displayTable("TREE_APPLY_OUTPUT2_JDM", "where ROWNUM < 21", + "order by CUST_ID, PREDICTION"); + + System.out.println("---------------------------------------------------"); + System.out.println("--- Business case 3 ---"); + System.out.println("--- Find the customers who work in Tech support ---"); + System.out.println("--- and are under 25 who is going to response ---"); + System.out.println("--- to the new affinity card program. ---"); + System.out.println("---------------------------------------------------"); + // 4. Display apply result -- Note that APPLY results do not need to be + // reverse transformed, as done in the case of model details. This is + // because class values of a classification target were not (required to + // be) binned or normalized. + // + // Find the customers who work in Tech support and are under 25 who is + // going to response to the new affinity card program. + displayTable("TREE_APPLY_OUTPUT3_JDM", + "where OCCUPATION = 'TechSup' " + "and AGE < 25 " + + "and PREDICTION = 1 ", "order by CUST_ID"); + } + + private static void displayTable(String tableName, String whereCause, + String orderByColumn) + { + StringBuffer emptyCol = new StringBuffer(" "); + + java.sql.Connection dbConn = + ((OraConnection) m_dmeConn).getDatabaseConnection(); + PreparedStatement pStmt = null; + ResultSet rs = null; + try + { + pStmt = + dbConn.prepareStatement("SELECT * FROM " + tableName + " " + whereCause + + " " + orderByColumn); + rs = pStmt.executeQuery(); + ResultSetMetaData rsMeta = rs.getMetaData(); + int colCount = rsMeta.getColumnCount(); + StringBuffer header = new StringBuffer(); + System.out.println("Table : " + tableName); + //Build table header + for (int iCol = 1; iCol <= colCount; iCol++) + { + String colName = rsMeta.getColumnName(iCol); + header.append(emptyCol.replace(0, colName.length(), colName)); + emptyCol = new StringBuffer(" "); + } + System.out.println(header.toString()); + //Write table data + while (rs.next()) + { + StringBuffer rowContent = new StringBuffer(); + for (int iCol = 1; iCol <= colCount; iCol++) + { + int sqlType = rsMeta.getColumnType(iCol); + Object obj = rs.getObject(iCol); + String colContent = null; + + if (obj instanceof java.lang.Number) + { + try + { + BigDecimal bd = (BigDecimal) obj; + if (bd.scale() > 5) + { + colContent = m_df.format(obj); + } + else + { + colContent = bd.toString(); + } + } + catch (Exception anyExp) + { + colContent = m_df.format(obj); + } + } + else + { + if (obj == null) + colContent = "NULL"; + else + colContent = obj.toString(); + } + + rowContent.append(" " + + emptyCol.replace(0, colContent.length(), colContent)); + emptyCol = new StringBuffer(" "); + } + System.out.println(rowContent.toString()); + } + } + catch (Exception anySqlExp) + { + anySqlExp.printStackTrace(); + } //Ignore + } + + private static void clean() + { + //Drop the model + try + { + m_dmeConn.removeObject("treeModel_jdm", NamedObject.model); + } + catch (Exception jdmExp) + { + } + } +} diff --git a/dmtxtfe.sql b/dmtxtfe.sql new file mode 100644 index 0000000..755a87e --- /dev/null +++ b/dmtxtfe.sql @@ -0,0 +1,208 @@ +Rem +Rem $Header: dmtxtfe.sql 12-jul-2005.07:43:16 ktaylor Exp $ +Rem +Rem textfe.sql +Rem +Rem Copyright (c) 2003, 2005, Oracle. All rights reserved. +Rem +Rem NAME +Rem textfe.sql - Oracle TEXT Term (or Feature) Extractor +Rem +Rem DESCRIPTION +Rem This script demonstrates a means to extract terms for +Rem text mining from Oracle Text documents (i.e. CLOB or +Rem VARCHAR2 columns containing text documents) using a Text +Rem Index built on those documents. +Rem +Rem For more information on term extraction for text mining, +Rem see Oracle Data Mining Application Developer's Guide. +Rem +Rem This program uses the following schema object: +Rem +Rem . BUILD_TEXT_IDX - the Oracle Text Index built +Rem on MINING_BUILD_TEXT. Please see rdbms/demo/dmsh.sql +Rem to see how MINING_BUILD_TEXT is constructed from +Rem data from the Sample Schema. +Rem +Rem Given this Text Index, the program demonstrates how to +Rem extract terms from the documents using the Text Index. +Rem The terms are generated in an output table in the multi-record +Rem case format - i.e. in the form +Rem (sequence_id, attribute_name, attribute_value) +Rem +Rem This output table can then be used to generate a nested table +Rem column (DM_Nested_Numerical) in the final table that represents +Rem the training data that is to be used for model creation, or the +Rem scoring table that is to be used for model scoring. +Rem +Rem Simply put, terms extracted from text documents will become +Rem generic attributes in training or scoring data. This data can +Rem then be classified, clustered or feature-extracted using the +Rem DBMS_DATA_MINING package. +Rem +Rem Since the number of attributes (i.e. the terms) is typically +Rem greater than 1000, these attributes are composed into a nested +Rem column in the input table. +Rem +Rem The goal of this program is to enable users to build their +Rem own term extractors, given a document table with a text index +Rem built on the documents. +Rem +Rem NOTES +Rem +Rem MODIFIED (MM/DD/YY) +Rem ktaylor 07/12/05 - minor edits to comments +Rem ramkrish 10/28/04 - cleanup/comments +Rem ramkrish 09/16/04 - update for 10gR2 +Rem xbarr 06/25/04 - xbarr_dm_rdbms_migration +Rem ramkrish 02/06/04 - fix nested table +Rem ramkrish 12/09/03 - explain the steps with comments +Rem cbhagwat 11/11/03 - NMF_CLUSTERING to SVM_CLASSIFICATION +Rem cbhagwat 10/06/03 - Creation + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET echo ON + +-- Cleanup for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE txt_sample_pref_terms'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE txt_sample_tf_out'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE txt_sample_term_out'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE txt_sample_terms'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE txt_sample_text_cat'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE txt_sample_data_input'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE nontxt_attrib'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN CTX_DDL.DROP_PREFERENCE(preference_name => 'txt_sample_pref'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- Step 1. The sample Text document table is MINING_BUILD_TEXT +-- This table is constructed when you run rdbms/demo/dmsh.sql. + +-- Step 2. The sample Text Index is BUILD_TEXT_INDEX +-- This index is also constructed when you run rdbms/demo/dmsh.sql + +-- Given the presence of these two schema objects, you can now +-- proceed to extract terms from text documents in MINING_BUILD_TEXT +-- using the following steps: + +-- Step 3. Create preferences for Text term extraction +-- (This routine must be used exclusively with ODM; +-- it is a public, but undocumented, routine in Oracle10g) +-- +BEGIN CTX_DDL.CREATE_PREFERENCE('txt_sample_pref', 'SVM_CLASSIFIER'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +-- Step 4. Define an ancillary table for categories +-- (required to execute preference choices) +-- +CREATE TABLE txt_sample_text_cat (id NUMBER, cat NUMBER) +/ + +-- Step 5. Extract terms set up by preference into intermediate terms tables +-- 1. txt_sample_term_out - terms set by preference +-- 2. txt_sample_pref_terms - term definitions +-- +-- The parameters are: +-- 'BUILD_TEXT_IDX', -- index_name - Text index name +-- 'CUST_ID', -- doc_id - the case-id +-- 'txt_sample_text_cat', -- cattab - category table name +-- 'id', -- catdocid - docid for category tab +-- 'cat', -- catid - category id +-- 'txt_sample_pref_terms', -- restab - term definitions +-- 'txt_sample_pref' -- preference - Text preference name +-- +CREATE TABLE txt_sample_term_out AS +SELECT * + FROM TABLE(ctxsys.drvodm.feature_prep ( + 'BUILD_TEXT_IDX', + 'CUST_ID', + 'txt_sample_text_cat', + 'id', + 'cat', + 'txt_sample_pref_terms', + 'txt_sample_pref')); + +-- At the end of this step: +-- . txt_sample_term_out has the schema +-- (sequence_id, value) +-- sequence_id contains the values of CUST_ID, the case identifier +-- column in MINING_BUILD_TEXT. +-- + +-- Step 6. Explain the terms in the intermediate tables to generate +-- the final terms table. This table will contain the text +-- elements that can be used as attributes for mining. +-- (This drvodm routine must be used exclusively with ODM; +-- it is a public, but undocumented, routine in Oracle10g) +-- +CREATE TABLE txt_sample_terms AS +SELECT A.sequence_id, B.text, A.value + FROM txt_sample_term_out A, + TABLE(ctxsys.drvodm.feature_explain( + 'txt_sample_pref_terms')) B + WHERE A.attribute_id = B.id; + +-- Step 7. (Optional) Display the extracted terms +-- +column text format a45 +SELECT * + FROM (SELECT sequence_id,text,value + FROM txt_sample_terms + ORDER BY sequence_id, text) + WHERE ROWNUM < 10; + +-- Step 8. Now, assume that you have a table containing training data +-- with non-text attributes, with matching sequence ids +-- (i.e. matching values of CUST_ID). +-- +-- See MINING_BUILD_TEXT in rdbms/demo/dmsh.sql as an example +-- +-- Add the text mining attributes to this table as a nested table, +-- as shown below. +-- + +-- Just for the sake of this demo, create a dummy table with +-- NULL non-text attributes, using txt_sample_terms itself as +-- the source (to prepare a table with matching case-id's) +-- In an actual scenario, the non-text columns may be +-- projected from a different table. +-- +CREATE TABLE nontxt_attrib AS +SELECT A.sequence_id case_id, 1 age, 1 salary, 1 class + FROM txt_sample_terms A; + +-- You can now create the mining data input table (or a view) +-- with text and non-text attributes as follows: +-- +CREATE TABLE txt_sample_data_input + NESTED TABLE txt_terms STORE AS txt_terms AS +SELECT N.*, + CAST(MULTISET( + SELECT DM_Nested_Numerical (T.text, T.value) + FROM txt_sample_terms T + WHERE N.case_id = T.sequence_id) + AS DM_Nested_Numericals) txt_terms + FROM nontxt_attrib N; + +-- Step 9. Read rdbms/demo/dmsh.sql to revise the above steps +-- in the context of an end-to-end demo of Text Mining. +-- dmsh.sql performs all of the steps discussed above, +-- against tables in the Sample Schema. The text data +-- prepared in this manner can be classified using +-- dmtxtsvm.sql, or feature extracted using dmtxtnmf.sql. diff --git a/dmtxtnmf.sql b/dmtxtnmf.sql new file mode 100644 index 0000000..c055874 --- /dev/null +++ b/dmtxtnmf.sql @@ -0,0 +1,158 @@ +Rem +Rem $Header: dmtxtnmf.sql 25-oct-2007.11:34:46 ramkrish Exp $ +Rem +Rem nmfdemo.sql +Rem +Rem Copyright (c) 2003, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem dmtxtnmf.sql - Sample program for the DBMS_DATA_MINING package. +Rem +Rem DESCRIPTION +Rem This script creates a text mining model +Rem using non-negative matrix factorization. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ramkrish 10/25/07 - replace deprecated get_model calls with catalog +Rem queries +Rem ktaylor 07/12/05 - minor edits to comments +Rem ramkrish 10/28/04 - cleanup/comments +Rem amozes 07/30/04 - format coefficient +Rem xbarr 06/25/04 - xbarr_dm_rdbms_migration +Rem cbhagwat 10/17/03 - feature_extraction +Rem cbhagwat 10/13/03 - cbhagwat_txn109175 +Rem cbhagwat 10/10/03 - fix +Rem cbhagwat 10/08/03 - Creation + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET echo ON + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM +----------------------------------------------------------------------- +-- Mine the text features extracted using dmtxtfe.sql using NMF +-- algorithm. + +----------------------------------------------------------------------- +-- SET UP AND ANALYZE THE DATA +----------------------------------------------------------------------- +-- See dmtxtfe.sql. Note that the text features are input here +-- through a nested table. + +----------------------------------------------------------------------- +-- BUILD THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old model and objects for repeat runs +BEGIN DBMS_DATA_MINING.DROP_MODEL('T_NMF_Sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE t_nmf_sample_norm'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW t_nmf_sample_build_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-------------------------------- +-- PREPARE BUILD (TRAINING) DATA +-- +BEGIN + -- Create a normalization table + DBMS_DATA_MINING_TRANSFORM.CREATE_NORM_LIN ( + norm_table_name => 't_nmf_sample_norm'); + + -- Normalize appropriate columns + DBMS_DATA_MINING_TRANSFORM.INSERT_NORM_LIN_MINMAX ( + norm_table_name => 't_nmf_sample_norm', + data_table_name => 'mining_build_nested_text', + exclude_list => dbms_data_mining_transform.column_list ( + 'AFFINITY_CARD', + 'BULK_PACK_DISKETTES', + 'FLAT_PANEL_MONITOR', + 'HOME_THEATER_PACKAGE', + 'BOOKKEEPING_APPLICATION', + 'PRINTER_SUPPLIES', + 'Y_BOX_GAMES', + 'OS_DOC_SET_KANJI', + 'cust_id', + 'comments'), + round_num => 0 + ); + + -- Create the transformed view + DBMS_DATA_MINING_TRANSFORM.XFORM_NORM_LIN ( + norm_table_name => 't_nmf_sample_norm', + data_table_name => 'mining_build_nested_text', + xform_view_name => 't_nmf_sample_build_prepared'); +END; +/ +-- NMFS settings (For info only) +-- insert into nmfs_settings values +--(dbms_data_mining.nmfs_conv_tolerance,0.05); +--(dbms_data_mining.nmfs_num_iterations,50); +--(dbms_data_mining.nmfs_random_seed,-1); +--(dbms_data_mining.nmfs_stop_criteria,dbms_data_mining.nmfs_sc_iter_or_conv); + +--------------------- +-- CREATE A NEW MODEL +-- +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'T_NMF_Sample', + mining_function => dbms_data_mining.feature_extraction, + data_table_name => 't_nmf_sample_build_prepared', + case_id_column_name => 'cust_id'); +END; +/ + +------------------------- +-- DISPLAY MODEL SETTINGS +-- +column setting_name format a30; +column setting_value format a30; +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'T_NMF_SAMPLE' +ORDER BY setting_name; + +-------------------------- +-- DISPLAY MODEL SIGNATURE +-- +column attribute_type format a20 +SELECT attribute_name, attribute_type + FROM user_mining_model_attributes + WHERE model_name = 'T_NMF_SAMPLE' +ORDER BY attribute_name; + +------------------------ +-- DISPLAY MODEL DETAILS +-- +column attribute_name format a30; +column attribute_value format a20; +column coefficient format 9.99999; +set pages 15; +SET line 120; +break ON feature_id; + +SELECT t.feature_id, + a.attribute_name, + a.attribute_value, + a.coefficient + FROM TABLE(dbms_data_mining.get_model_details_nmf('T_NMF_Sample')) t, + TABLE(t.attribute_set) a +WHERE feature_id < 3 +ORDER BY 1,2,3,4; + +----------------------------------------------------------------------- +-- APPLY THE MODEL +----------------------------------------------------------------------- +-- See dmnmdemo.sql for examples. The key difference here +-- is the nested table input, and you can adapt that sample +-- code to accept the table with a nested table column as +-- input. diff --git a/dmtxtnmfdemo.java b/dmtxtnmfdemo.java new file mode 100644 index 0000000..6201ccf --- /dev/null +++ b/dmtxtnmfdemo.java @@ -0,0 +1,843 @@ +// Copyright (c) 2004, 2006, Oracle. All rights reserved. +// File: dmtxtnmfdemo.java + +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to build and apply a feature extraction model using the non-negative matrix +* factorization (NMF) algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* Given demographic data about a set of customers, extract features +* from the given dataset with text mining. +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the previous affinity card +* programs. Data exploration and preparing the data is a common step before +* doing data mining. Here in this demo, the following views are created +* in the user schema using CUSTOMERS, COUNTRIES, and SUPPLIMENTARY_DEMOGRAPHICS +* tables. +* +* MINING_BUILD_TEXT: +* This view collects the previous customers' comments(text), demographics, +* purchasing details, and affinity card response details for building the model. +* +* MINING_APPLY_TEXT: +* This view collects the prospective customers' comments(text), demographics, +* and purchasing details for predicting response to the new affinity card +* program. +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Prepare Data: +* In general, attributes need to be of similar scale in order to be treated +* equally during the model build. Therefore normalization is required. +* The prepareData() method illustrates the normalization of the build and apply +* data. +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a feature extraction model using the NMF algorithm. +* Apply Model: +* For a descriptive mining function like feature extraction, "scoring" +* involves providing the probability values for each feature. +* During model apply, an NMF model maps the original data into the +* new set of attributes (features) discovered by the model. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +// Generic api imports +import java.math.BigDecimal; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; +import java.text.DecimalFormat; +import java.text.MessageFormat; +import java.util.Collection; +import java.util.Iterator; +// Java Data Mining (JDM) standard imports +import java.util.Map; +import java.util.TreeMap; +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.MiningAlgorithm; +import javax.datamining.MiningFunction; +import javax.datamining.NamedObject; +import javax.datamining.base.AlgorithmSettings; +import javax.datamining.base.Model; +import javax.datamining.base.Task; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.ModelSignature; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.data.SignatureAttribute; +import javax.datamining.resource.Connection; +import javax.datamining.resource.ConnectionFactory; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; +import javax.datamining.task.apply.DataSetApplyTask; +import javax.datamining.task.apply.DataSetApplyTaskFactory; +// Oracle Java Data Mining (JDM) implemented api imports +import oracle.dmt.jdm.algorithm.nmf.OraNMFAlgorithmSettingsFactory; +import oracle.dmt.jdm.algorithm.nmf.OraNMFAlgorithmSettings; +import oracle.dmt.jdm.featureextraction.OraFeature; +import oracle.dmt.jdm.featureextraction.OraFeatureExtractionApplySettings; +import oracle.dmt.jdm.featureextraction.OraFeatureExtractionApplySettingsFactory; +import oracle.dmt.jdm.featureextraction.OraFeatureExtractionModel; +import oracle.dmt.jdm.featureextraction.OraFeatureExtractionSettings; +import oracle.dmt.jdm.featureextraction.OraFeatureExtractionSettingsFactory; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.task.OraTransformationTask; +import oracle.dmt.jdm.task.OraTransformationTaskFactory; +import oracle.dmt.jdm.transform.normalize.OraNormalizeTransformFactory; +import oracle.dmt.jdm.transform.normalize.OraNormalizeTransform; +import oracle.dmt.jdm.transform.normalize.OraNormalizeType; +import oracle.dmt.jdm.transform.text.OraTextTransform; +import oracle.dmt.jdm.transform.text.OraTextTransformFactory; + + +public class dmtxtnmfdemo extends Object{ + //Connection related data members + private static Connection m_dmeConn; + private static ConnectionFactory m_dmeConnFactory; + //Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static OraFeatureExtractionSettingsFactory m_feSettingFactory; + private static OraNMFAlgorithmSettingsFactory m_feAlgFactory; + private static BuildTaskFactory m_buildFactory; + private static DataSetApplyTaskFactory m_dsApplyFactory; + private static OraFeatureExtractionApplySettingsFactory m_applySettingsFactory; + private static OraTextTransformFactory m_textXformFactory; + private static OraNormalizeTransformFactory m_normalizeXformFactory; + private static OraTransformationTaskFactory m_xformTaskFactory; + // Global constants used for formatting output + private static String UNDERLINE = "*************************************"; + private static String TAB = " "; + private static char SPACE = ' '; + private static int SECOND_COLUMN = 40; + private static int THIRD_COLUMN = 70; + // Global constants + private static DecimalFormat m_df = new DecimalFormat("##.####"); + private static boolean displayModelDeatils = false;//By default it is set to false. To view the details of the model this flag can be enabled + + public static void main( String args[] ) { + try { + if (( args.length != 0 ) & ( args.length != 3 )) { + System.out.println("Usage: java dmtxtnmfdemo "); + System.out.println(" or: java dmtxtnmfdemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + //1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@"+uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Prepare data + prepareData(); + // 5. Build a model + buildModel(); + // 6. Apply the model + applyModel(); + } catch(Exception anyExp) { + anyExp.printStackTrace(System.out); + } finally { + try { + // 7. Logout from the Data Mining Engine + m_dmeConn.close(); + } catch(Exception anyExp1) { }//Ignore + } + } + + /** + * Initialize all object factories used in the demo program. + * + * @exception JDMException if factory initalization failed + */ + public static void initFactories() throws JDMException + { + m_pdsFactory = (PhysicalDataSetFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalDataSet"); + m_paFactory = (PhysicalAttributeFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalAttribute"); + m_feSettingFactory = (OraFeatureExtractionSettingsFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.featureextraction.OraFeatureExtractionSettings"); + m_feAlgFactory = (OraNMFAlgorithmSettingsFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.algorithm.nmf.OraNMFAlgorithmSettings"); + m_buildFactory = (BuildTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.BuildTask"); + m_dsApplyFactory = (DataSetApplyTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.apply.DataSetApplyTask"); + m_applySettingsFactory = (OraFeatureExtractionApplySettingsFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.featureextraction.OraFeatureExtractionApplySettings"); + m_normalizeXformFactory = (OraNormalizeTransformFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.transform.normalize.OraNormalizeTransform"); + m_textXformFactory = (OraTextTransformFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.transform.text.OraTextTransform"); + m_xformTaskFactory = (OraTransformationTaskFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.task.OraTransformationTask"); + } + + /** + * This method illustrates preparation of the data for the build and apply + * operations by using normalization transformation. + * + * Here numerical attribute AGE is prepared using default normalization + * which is min-max normalization. The values for shift and scale are computed + * to be shift = min, and scale = (max - min) respectively. + * + * COLUMN_NAME DATA_TYPE DISTINCT NORMALIZING + * ------------------ --------- -------- ----------- + * CUST_ID NUMBER 1500 + * CUST_GENDER CHAR 2 + * AGE NUMBER 66 MINMAX + * CUST_MARITAL_STATUS VARCHAR2 7 + * COUNTRY_NAME VARCHAR2 19 + * CUST_INCOME_LEVEL VARCHAR2 12 + * EDUCATION VARCHAR2 16 + * OCCUPATION VARCHAR2 15 + * HOUSEHOLD_SIZE VARCHAR2 6 + * YRS_RESIDENCE NUMBER 15 MINMAX + * AFFINITY_CARD NUMBER 2 + * BULK_PACK_DISKETTES NUMBER 2 + * FLAT_PANEL_MONITOR NUMBER 2 + * HOME_THEATER_PACKAGE NUMBER 2 + * BOOKKEEPING_APPLICATION NUMBER 2 + * PRINTER_SUPPLIES NUMBER 1 + * Y_BOX_GAMES NUMBER 2 + * OS_DOC_SET_KANJI NUMBER 2 + * OS_DOC_SET_KANJI NUMBER 2 + * CPMMENTS VARCHAR2(4000) 44 + * + * The following views are created after the execution of this method. + * + * Unprepared Data ---> Prepared(Normalized) Data + * ------------------------ --------------------------- + * MINING_BUILD_TEXT TXTNMF_NORM_DATA_BUILD_JDM + * MINING_APPLY_TEXT TXTNMF_NORM_DATA_APPLY_JDM + * + * @exception JDMException if data preparation failed + */ + public static void prepareData() throws JDMException + { + boolean isOutputAsView = false; + String inputDataURI = null; + String outputDataURI = null; + String inputNormalizationDefinitionTable = null; + OraTransformationTask xformTask = null; + //------------------------------------------------------------------------ + // 1. Prepare build data + //------------------------------------------------------------------------ + // Text Transformation - Convert text column into a nested column in order + // to perform text mining + isOutputAsView = false; + inputDataURI = "MINING_BUILD_TEXT"; + outputDataURI = "TXTNMF_BUILD_NESTED_TEXT"; + String caseId = "CUST_ID"; + String[] textColumnList = {"COMMENTS"}; + OraTextTransform textDataXform = + (OraTextTransform)m_textXformFactory.create( + inputDataURI, outputDataURI, caseId, textColumnList); + xformTask = m_xformTaskFactory.create(textDataXform); + executeTask(xformTask, "txtnmfPrepareTextB_jdm"); + // Normalization + isOutputAsView = true; + inputDataURI = "TXTNMF_BUILD_NESTED_TEXT"; + outputDataURI = "TXTNMF_NORM_DATA_BUILD_JDM"; + OraNormalizeType normalizeType = OraNormalizeType.min_max; + Integer roundingNumber = new Integer(0); + OraNormalizeTransform buildDataXform = + (OraNormalizeTransform)m_normalizeXformFactory.create( + inputDataURI, outputDataURI, isOutputAsView, + normalizeType, roundingNumber); + String[] excludeColumnList = { + "CUST_ID", + "AFFINITY_CARD", + "BULK_PACK_DISKETTES", + "FLAT_PANEL_MONITOR", + "HOME_THEATER_PACKAGE", + "BOOKKEEPING_APPLICATION", + "PRINTER_SUPPLIES", + "Y_BOX_GAMES", + "OS_DOC_SET_KANJI", + "COMMENTS" + }; + buildDataXform.setExcludeColumnList(excludeColumnList); + xformTask = m_xformTaskFactory.create(buildDataXform); + executeTask(xformTask, "txtnmfPrepareBuild_jdm"); + //------------------------------------------------------------------------ + // 2. Prepare apply data + //------------------------------------------------------------------------ + // Text Transformation - Convert text column into a nested column in order + // to perform text mining + isOutputAsView = false; + inputDataURI = "MINING_APPLY_TEXT"; + outputDataURI = "TXTNMF_APPLY_NESTED_TEXT"; + caseId = "CUST_ID"; + textColumnList = new String[] {"COMMENTS"}; + //Get feature tables created by the build text transformation + OraTransformationTask buildTextXformTask = (OraTransformationTask)m_dmeConn.retrieveObject( + "txtnmfPrepareTextB_jdm", NamedObject.task); + String[] buildFeatureTables = ((OraTextTransform)buildTextXformTask.getTransformation()).getFeatureTables(); + textDataXform = + (OraTextTransform)m_textXformFactory.create( + inputDataURI, outputDataURI, caseId, textColumnList, + buildFeatureTables); + xformTask = m_xformTaskFactory.create(textDataXform); + executeTask(xformTask, "txtnmfPrepareTextA_jdm"); + // Normalization + isOutputAsView = true; + inputDataURI = "TXTNMF_APPLY_NESTED_TEXT"; + outputDataURI = "TXTNMF_NORM_DATA_APPLY_JDM"; + inputNormalizationDefinitionTable = buildDataXform.getNormalizationDefinitionTable(); + OraNormalizeTransform applyDataXform = + (OraNormalizeTransform)m_normalizeXformFactory.create( + inputDataURI, outputDataURI, isOutputAsView, inputNormalizationDefinitionTable); + xformTask = m_xformTaskFactory.create(applyDataXform); + executeTask(xformTask, "txtnmfPrepareApply_jdm"); + } + + /** + * This method illustrates how to build a mining model using the + * "TXTNMF_NORM_DATA_BUILD_JDM" dataset with the NMF algorithm. + * + * After completing the build task, the model named "txtnmfModel_jdm" will + * be created. + * + * @exception JDMException if model build failed + */ + public static void buildModel() throws JDMException + { + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = m_pdsFactory.create("TXTNMF_NORM_DATA_BUILD_JDM", false); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + buildData.addAttribute(pa); + m_dmeConn.saveObject("txtnmfBuildData_jdm", buildData, true); + // 2. Create & save Mining Function Settings + //Create NMF algorithm settings + OraNMFAlgorithmSettings nmfAlgo = + (OraNMFAlgorithmSettings)m_feAlgFactory.create(); + // Examples settings are: + // nmfAlgo.setMaxNumberOfIterations(10); + // nmfAlgo.setMinConvergenceTolerance(0.05); + // nmfAlgo.setSeedValue(-1); + // + // Create OraFeatureExtractionSettings + OraFeatureExtractionSettings buildSettings = m_feSettingFactory.create(); + buildSettings.setAlgorithmSettings(nmfAlgo); + buildSettings.setNumberOfFeatures(10); + m_dmeConn.saveObject("txtnmfBuildSettings_jdm", buildSettings, true); + // 3. Create, save & execute Build Task + BuildTask buildTask = m_buildFactory.create( + "txtnmfBuildData_jdm", //Build data specification + "txtnmfBuildSettings_jdm", //Mining function settings name + "txtnmfModel_jdm" //Mining model name + ); + buildTask.setDescription("txtnmfBuildTask_jdm"); + executeTask(buildTask, "txtnmfBuildTask_jdm"); + // 4. Restore the model from the DME and explore the details of the model + OraFeatureExtractionModel model = (OraFeatureExtractionModel) + m_dmeConn.retrieveObject("txtnmfModel_jdm", NamedObject.model); + + // Display model build settings + OraFeatureExtractionSettings retrievedBuildSettings = + (OraFeatureExtractionSettings)model.getBuildSettings(); + if(buildSettings == null) + System.out.println("Failure to restore build settings."); + else + displayBuildSettings(retrievedBuildSettings, "txtnmfBuildSettings_jdm"); + // Display model signature + displayModelSignature((Model)model); + // Display model details + if(displayModelDeatils) + displayFEModelDetails(model); + } + + /** + * The Apply operation is performed by a task that requires the location of + * the dataset, the model name, the output specification, and the location + * of the output. + * + * The output table "nmf_apply_output_jdm" is specified by a MiningApplyOutput + * object to contain the feature identifier and the match quality for feature + * extraction models. + * + * In this example, the NMF model is applied with the + * "TXTNMF_NORM_DATA_APPLY_JDM" prepared dataset to obtain the feature + * identifier and the match quality. + * + * @exception JDMException if model apply failed + */ + public static void applyModel() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Apply Model ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = m_pdsFactory.create( + "TXTNMF_NORM_DATA_APPLY_JDM", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "txtnmfNMFData_jdm", applyData, true ); + // 2. Create & save FeatureExtractionApplySettings + OraFeatureExtractionApplySettings feAS = m_applySettingsFactory.create(); + m_dmeConn.saveObject( "txtnmfApplySettings_jdm", feAS, true); + + // 3. Create, store & execute apply Task + DataSetApplyTask applyTask = m_dsApplyFactory.create( + "txtnmfNMFData_jdm", "txtnmfModel_jdm", "txtnmfApplySettings_jdm", + "TXTNMF_APPLY_OUTPUT_JDM"); + executeTask(applyTask, "txtnmfApplyTask_jdm"); + // 4. Display apply result -- the first 10 rows + displayTable("TXTNMF_APPLY_OUTPUT_JDM", + "where ROWNUM < 11", + "order by CUST_ID"); + } + /** + * This method stores the given task with the specified name in the DMS + * and submits the task for asynchronous execution in the DMS. After + * completing the task successfully it returns true. If there is a task + * failure, then it prints the error description and returns false. + * + * @param taskObj task object + * @param taskName name of the task + * + * @return boolean returns true when the task is successful + * @exception JDMException if task execution failed + */ + public static boolean executeTask(Task taskObj, String taskName) throws JDMException + { + boolean isTaskSuccess = false; + m_dmeConn.saveObject(taskName, taskObj, true); + ExecutionHandle execHandle = m_dmeConn.execute(taskName); + System.out.print(taskName + " is started, please wait. "); + //Wait for completion of the task + ExecutionStatus status = execHandle.waitForCompletion(Integer.MAX_VALUE); + //Check the status of the task after completion + isTaskSuccess = status.getState().equals(ExecutionState.success); + if( isTaskSuccess ) { + //Task completed successfully + System.out.println(taskName + " is successful."); + } else {//Task failed + System.out.println(taskName + " is failed.\nFailure Description: " + + status.getDescription() ); + } + return isTaskSuccess; + } + + private static void displayBuildSettings( + OraFeatureExtractionSettings featureSettings, String buildSettingsName) + { + // Display build settings table + System.out.println("BuildSettings Details from the " + + buildSettingsName + " table:"); + displayTable(buildSettingsName, "", "order by SETTING_NAME"); + // Display build settings object obtained from the model + System.out.println("BuildSettings Details from the " + + buildSettingsName + " model build settings object:"); + String objName = featureSettings.getName(); + if(objName != null) + System.out.println("Name = " + objName); + String objDescription = featureSettings.getDescription(); + if(objDescription != null) + System.out.println("Description = " + objDescription); + java.util.Date creationDate = featureSettings.getCreationDate(); + String creator = featureSettings.getCreatorInfo(); + AlgorithmSettings algoSettings = featureSettings.getAlgorithmSettings(); + if(algoSettings == null) + System.out.println("Failure: featureSettings.getAlgorithmSettings() returns null"); + MiningAlgorithm algo = algoSettings.getMiningAlgorithm(); + if(algo == null) System.out.println("Failure: algoSettings.getMiningAlgorithm() returns null"); + System.out.println("Algorithm Name: " + algo.name()); + MiningFunction function = featureSettings.getMiningFunction(); + if(function == null) System.out.println("Failure: featureSettings.getMiningFunction() returns null"); + System.out.println("Function Name: " + function.name()); + // List of NMF algorithm settings + long intValue = ((OraNMFAlgorithmSettings)algoSettings).getMaxNumberOfIterations(); + System.out.println("Max Number Of Iterations: " + intValue); + double doubleValue = ((OraNMFAlgorithmSettings)algoSettings).getMinConvergenceTolerance(); + System.out.println("Min Convergence Tolerance: " + m_df.format(doubleValue)); + intValue = ((OraNMFAlgorithmSettings)algoSettings).getSeedValue(); + System.out.println("Seed Value: " + intValue); + intValue = featureSettings.getNumberOfFeatures(); + System.out.println("Number Of Features: " + intValue); + } + + /** + * This method displayes the NMF model signature. + * + * @param model model object + * @exception JDMException + */ + public static void displayModelSignature(Model model) throws JDMException + { + String modelName = model.getName(); + System.out.println("Model Name: " + modelName); + // Display the first 10 rows only + ModelSignature modelSignature = model.getSignature(); + System.out.println("Model Signature: ( Attribute Name, Attribute Type )"); + MessageFormat mfSign = new MessageFormat(" ( {0}, {1} )"); + String[] vals = new String[2]; + Collection sortedSet = modelSignature.getAttributes(); + Iterator attrIterator = sortedSet.iterator(); + + /****************************************************************/ + // this part of code sorts the columns by name + // to get the deterministic order of columns + // this code can be omitted otherwise + // sort the attributes by name + TreeMap treeMap = new TreeMap(); + while(attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute) attrIterator.next(); + String attrName = attr.getName(); + treeMap.put( attrName, attr ); + } + Collection sortedSig = treeMap.values(); + attrIterator = sortedSig.iterator(); + /****************************************************************/ + + while(attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute)attrIterator.next(); + vals[0] = attr.getName(); + vals[1] = attr.getDataType().name(); + System.out.println( mfSign.format(vals) ); + } + } + + private static void displayTable(String tableName, String whereCause, String orderByColumn) + { + StringBuffer emptyCol = new StringBuffer(" "); + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + PreparedStatement pStmt = null; + ResultSet rs = null; + try + { + pStmt = dbConn.prepareStatement("SELECT * FROM " + tableName + " " + whereCause + " " + orderByColumn); + rs = pStmt.executeQuery(); + ResultSetMetaData rsMeta = rs.getMetaData(); + int colCount = rsMeta.getColumnCount(); + StringBuffer header = new StringBuffer(); + System.out.println("Table : " + tableName); + + /****************************************************************/ + // this part of code sorts the columns by name + // to get the deterministic order of columns + // this code can be omitted otherwise + TreeMap treeMap = new TreeMap(); + for(int iCol=1; iCol<=colCount; iCol++) + { + String colName = rsMeta.getColumnName(iCol); + treeMap.put( colName, new Integer(iCol) ); + } + Collection colColl = treeMap.values(); + int[] colIndex = new int[colCount]; + Iterator colIt = colColl.iterator(); + for( int i=0; colIt.hasNext(); i++ ) + { + Integer index = (Integer) colIt.next(); + colIndex[i] = index.intValue(); + } + /****************************************************************/ + + // Build table header + for(int iCol=1; iCol<=colCount; iCol++) + { + String colName = rsMeta.getColumnName( colIndex[iCol-1] ); + // if no ordering is needed (with the above code block omitted), + // this line can be used + // String colName = rsMeta.getColumnName(iCol); + header.append(emptyCol.replace(0, colName.length(), colName)); + emptyCol = new StringBuffer(" "); + } + System.out.println(header.toString()); + // Write table data + while(rs.next()) + { + StringBuffer rowContent = new StringBuffer(); + for(int iCol=1; iCol<=colCount; iCol++) + { + int sqlType = rsMeta.getColumnType( colIndex[iCol-1] ); + Object obj = rs.getObject( colIndex[iCol-1] ); + // if no ordering is needed (with the above code block omitted), + // the following two lines can be used + // int sqlType = rsMeta.getColumnType(iCol); + // Object obj = rs.getObject(iCol); + String colContent = null; + + if(obj instanceof java.lang.Number) + { + try + { + BigDecimal bd = (BigDecimal)obj; + if(bd.scale() > 5) + { + colContent = m_df.format(obj); + } else + { + colContent = bd.toString(); + } + } catch(Exception anyExp) { + colContent = m_df.format(obj); + } + } else + { + if(obj == null) + colContent = "NULL"; + else + colContent = obj.toString(); + } + rowContent.append(" "+emptyCol.replace(0, colContent.length(), colContent)); + emptyCol = new StringBuffer(" "); + } + System.out.println(rowContent.toString()); + } + } catch(Exception anySqlExp) { + anySqlExp.printStackTrace(); + } // Ignore + } + + /** + * Each feature is a linear combination of the original attribute set; + * the coefficients of these linear combinations are non-negative. + * The model details return for each feature the coefficients + * associated with each one of the original attributes. Categorical + * attributes are described by (attribute_name, attribute_value) pairs. + * That is, for a given feature, each distinct value of a categorical + * attribute has its own coefficient. + * + * @param model model to be presented + * @exception JDMException if failed to retrieve model details + */ + public static void displayFEModelDetails(OraFeatureExtractionModel model) throws JDMException + { + System.out.println(UNDERLINE+"\n"+"NMF model details"+"\n"+UNDERLINE+"\n"); + System.out.println("\n"+TAB+"Listing all features:\n"+UNDERLINE); + Collection features = model.getFeatures(); + if ( features == null ){ + System.out.println(TAB+TAB+"Error printing features."); + return; + } + + /****************************************************************/ + // this part of code sorts the features by id + // to get the deterministic order of features + // this code can be omitted otherwise + // use tree map to sort the features/attributes for determinstic results + OraFeature sampleFeature = null; + Iterator it = features.iterator(); + + TreeMap treeMap = new TreeMap(); + while( it.hasNext() ) + { + OraFeature feature = (OraFeature)it.next(); + int featureId = feature.getFeatureIdentifier(); + treeMap.put( new Integer(featureId), feature ); + } + Collection featuresOrdered = treeMap.values(); + it = featuresOrdered.iterator(); + /****************************************************************/ + + while ( it.hasNext() ){ + OraFeature feature = (OraFeature)it.next(); + printFeature(feature); + if ( sampleFeature == null ) + sampleFeature = feature; + } + + System.out.println("\n"+TAB+"Listing Top 3 features:\n"+UNDERLINE); + Collection topNfeatures = model.getFeatures(3); + if ( topNfeatures == null ){ + System.out.println(TAB+TAB+"Error printing Top N features."); + return; + } + + Iterator itTopN = topNfeatures.iterator(); + while ( itTopN.hasNext() ){ + OraFeature feature = (OraFeature)itTopN.next(); + printFeature(feature); + } + + if ( sampleFeature != null ){ + System.out.println(TAB+"Listing all attribute names for the feature:" + sampleFeature.getFeatureIdentifier()); + System.out.println(TAB+"____________________________________________"); + String[] attrNames = sampleFeature.getAttributeNames(); + for ( int ni = 0 ; ni < attrNames.length ; ni++ ) { + Map attrValCoefficientMap = sampleFeature.getAttributeCoefficients(attrNames[ni]); + System.out.println("\n"+TAB+TAB+"Attribute Name:" + attrNames[ni] ); + printCoefficients(attrNames[ni], attrValCoefficientMap, false); + } + } + } + + /** + * Display a single feature + * + * @param feature specific feature to be displayed + * @throws JDMException if failed to retrieve the feature details + */ + public static void printFeature(OraFeature feature) throws JDMException + { + if ( feature == null ){ + System.out.println("Error: feature is null"); + return; + } + + System.out.println("\n" + TAB+TAB+"Feature : " + feature.getFeatureIdentifier() ); + String[] featureAttrNames = feature.getAttributeNames(); + //Print attributes coefficient details for each attribute + if(featureAttrNames != null) { + for(int iAttr=0; iAttr < featureAttrNames.length; iAttr++) + { + Map attrValCoefficientMap = feature.getAttributeCoefficients(featureAttrNames[iAttr]); + printCoefficients(featureAttrNames[iAttr], attrValCoefficientMap, true); + } + } + } + + + + private static void printCoefficients (String attrName, Map attrValCoefficientMap, boolean printAttrName) + throws JDMException + { + if ( attrValCoefficientMap == null ){ + System.out.println("Error printing coefficients for this feature."); + return; + } + + if ( printAttrName == true ) + print3Columns(new String[]{"Attribute","Value","Coefficient"} ); + else + print3Columns(new String[]{"","Value","Coefficient"} ); + + System.out.println(TAB+TAB+TAB +"____________________________________________________________________________" ); + Object[] attrVals = attrValCoefficientMap.keySet().toArray(); + if(attrVals != null) { + for(int iAttr=0; iAttr < attrVals.length; iAttr++) + { + print3Columns ( new String[]{ + ( printAttrName == true ? attrName : "" ) , + (( attrVals[iAttr] == null ? "" : attrVals[iAttr] )).toString(), + String.valueOf(m_df.format((Number)attrValCoefficientMap.get(attrVals[iAttr]))) + } + ); + } + } + + } + + private static void print3Columns(String[] names){ + if ( names == null || names.length != 3 ) + return; + + StringBuffer sbOut = new StringBuffer(TAB+TAB+TAB); + sbOut.append(names[0]); + + int padLength = Math.max ( SECOND_COLUMN - sbOut.length(), 0 ); + for ( int ni = 0 ; ni < padLength; ni++) + sbOut.append(SPACE); + + sbOut.append(names[1]); + padLength = Math.max ( THIRD_COLUMN - sbOut.length(), 0 ); + for ( int ni = 0 ; ni < padLength; ni++) + sbOut.append(SPACE); + + sbOut.append(names[2]); + System.out.println(sbOut.toString()); + } + + private static void clean() + { + java.sql.Connection dbConn = + ((OraConnection) m_dmeConn).getDatabaseConnection(); + Statement stmt = null; + // Drop prepared tables + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP TABLE TXTNMF_BUILD_NESTED_TEXT"); + } catch(SQLException anySqlExp) {}//Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP TABLE TXTNMF_APPLY_NESTED_TEXT"); + } catch(SQLException anySqlExp) {}//Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + // Drop prepared views + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP VIEW TXTNMF_NORM_DATA_BUILD_JDM"); + } catch(SQLException anySqlExp) {}//Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP VIEW TXTNMF_NORM_DATA_APPLY_JDM"); + } catch(SQLException anySqlExp) {}//Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + // Drop apply output table + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP TABLE TXTNMF_APPLY_OUTPUT_JDM"); + } catch(SQLException anySqlExp) {}//Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + try { + m_dmeConn.removeObject("txtnmfModel_jdm", NamedObject.model); + } catch(JDMException jdmExp) {} + } +} diff --git a/dmtxtsvm.sql b/dmtxtsvm.sql new file mode 100644 index 0000000..03ed409 --- /dev/null +++ b/dmtxtsvm.sql @@ -0,0 +1,229 @@ +Rem +Rem $Header: dmtxtsvm.sql 25-oct-2007.11:34:46 ramkrish Exp $ +Rem +Rem +Rem Copyright (c) 2003, 2007, Oracle. All rights reserved. +Rem +Rem dmtxtsvm.sql - Sample program for the DBMS_DATA_MINING package. +Rem +Rem DESCRIPTION +Rem This script creates a text mining model using +Rem SVM classification. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ramkrish 10/25/07 - replace deprecated get_model calls with catalog +Rem queries +Rem ktaylor 07/12/05 - minor edits to comments +Rem ramkrish 01/28/05 - 4148186 - provide correct model names +Rem ramkrish 10/28/04 - cleanup/comments +Rem xbarr 06/25/04 - xbarr_dm_rdbms_migration +Rem bmilenov 05/18/04 - Change zscore to minmax normalization +Rem cbhagwat 02/25/04 - Format changes +Rem cbhagwat 10/13/03 - cbhagwat_txn109175 +Rem cbhagwat 10/10/03 - fix +Rem cbhagwat 10/08/03 - Creation + +SET serveroutput ON +SET trimspool ON +SET pages 10000 +SET echo ON + +----------------------------------------------------------------------- +-- SAMPLE PROBLEM +----------------------------------------------------------------------- +-- Mine the text features extracted using dmtxtfe.sql using SVM +-- algorithm. + +----------------------------------------------------------------------- +-- SET UP AND ANALYZE THE DATA +----------------------------------------------------------------------- +-- See dmtxtfe.sql. Note that the text features are input here +-- through a nested table column called 'COMMENTS'. + +----------------------------------------------------------------------- +-- BUILD THE MODEL +----------------------------------------------------------------------- + +-- Cleanup old model and objects for repeat runs +BEGIN DBMS_DATA_MINING.DROP_MODEL('T_SVM_Clas_sample'); +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP TABLE t_svmc_sample_settings'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- Create settings table to choose linear kernel +CREATE TABLE t_svmc_sample_settings ( + setting_name VARCHAR2(30), + setting_value VARCHAR2 (30)); + +BEGIN + -- Populate settings table + INSERT INTO t_svmc_sample_settings VALUES + (dbms_data_mining.algo_name, + dbms_data_mining.algo_support_vector_machines); + --(dbms_data_mining.svms_conv_tolerance,0.01); + --(dbms_data_mining.svms_kernel_cache_size,50000000); + INSERT INTO t_svmc_sample_settings VALUES + (dbms_data_mining.svms_kernel_function,dbms_data_mining.svms_linear); + COMMIT; +END; +/ + +--------------- +-- CREATE MODEL + +-- Cleanup old objects for repeat runs +BEGIN EXECUTE IMMEDIATE 'DROP TABLE t_svmc_sample_norm'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +BEGIN EXECUTE IMMEDIATE 'DROP VIEW t_svmc_sample_build_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ +-- Prepare mining_data_build data as appropriate +BEGIN + -- Make a numerical bin boundary table + DBMS_DATA_MINING_TRANSFORM.CREATE_NORM_LIN ( + norm_table_name => 't_svmc_sample_norm'); + + -- Normalize data + DBMS_DATA_MINING_TRANSFORM.INSERT_NORM_LIN_MINMAX ( + norm_table_name => 't_svmc_sample_norm', + data_table_name => 'mining_build_nested_text', + exclude_list => DBMS_DATA_MINING_TRANSFORM.COLUMN_LIST ( + 'CUST_ID', + 'AFFINITY_CARD', + 'BULK_PACK_DISKETTES', + 'FLAT_PANEL_MONITOR', + 'HOME_THEATER_PACKAGE', + 'BOOKKEEPING_APPLICATION', + 'PRINTER_SUPPLIES', + 'Y_BOX_GAMES', + 'OS_DOC_SET_KANJI', + 'COMMENTS'), + round_num => 0 + ); + + -- Create the transformed view + DBMS_DATA_MINING_TRANSFORM.XFORM_NORM_LIN ( + norm_table_name => 't_svmc_sample_norm', + data_table_name => 'mining_build_nested_text', + xform_view_name => 't_svmc_sample_build_prepared'); +END; +/ + +-- Create SVM model +BEGIN + DBMS_DATA_MINING.CREATE_MODEL( + model_name => 'T_SVM_Clas_sample', + mining_function => dbms_data_mining.classification, + data_table_name => 't_svmc_sample_build_prepared', + case_id_column_name => 'cust_id', + target_column_name => 'affinity_card', + settings_table_name => 't_svmc_sample_settings'); +END; +/ + +-- Display the model settings +column setting_name format a30; +column setting_value format a30; +SELECT setting_name, setting_value + FROM user_mining_model_settings + WHERE model_name = 'T_SVM_CLAS_SAMPLE' +ORDER BY setting_name; + +-- Display the model signature +column attribute_name format a40 +column attribute_type format a20 +SELECT attribute_name, attribute_type + FROM user_mining_model_attributes + WHERE model_name = 'T_SVM_CLAS_SAMPLE' +ORDER BY attribute_name; + +-- Display model details +-- Note how several text terms extracted from the COMMENTs documents +-- show up as predictors. +-- +SET line 120 +column class format a10 +column attribute_name format a25 +column attribute_value format a25 +column coefficient format 9.99 +WITH +mod_dtls AS ( +SELECT * + FROM TABLE(DBMS_DATA_MINING.GET_MODEL_DETAILS_SVM('T_SVM_Clas_sample')) +), +model_details AS ( +SELECT d.class, a.attribute_name, a.attribute_value, a.coefficient + FROM mod_dtls d, + TABLE(d.attribute_set) a +ORDER BY class, ABS(coefficient) DESC +) +-- +SELECT TO_CHAR(class) class, + attribute_name, + attribute_value, + coefficient + FROM model_details + WHERE ROWNUM < 6; + +----------------------------------------------------------------------- +-- TEST THE MODEL +----------------------------------------------------------------------- +-- See dmsvcdem.sql for examples. The key difference here +-- is the nested table input, and you can adapt that sample +-- code to accept the table with a nested table column as +-- input. + +----------------------------------------------------------------------- +-- SCORE NEW DATA USING SQL DATA MINING FUNCTIONS +----------------------------------------------------------------------- + +BEGIN EXECUTE IMMEDIATE 'DROP VIEW t_svmc_sample_apply_prepared'; +EXCEPTION WHEN OTHERS THEN NULL; END; +/ + +-- Prepare scoring data +BEGIN + -- Create the transformed view + DBMS_DATA_MINING_TRANSFORM.XFORM_NORM_LIN ( + norm_table_name => 't_svmc_sample_norm', + data_table_name => 'mining_apply_nested_text', + xform_view_name => 't_svmc_sample_apply_prepared'); +END; +/ + +-- The key here is to demonstrate the use of these functions on +-- a scoring table with nested table input for attributes. + +------------------ +-- BUSINESS CASE 1 +-- +-- Find the 10 customers that are most likely to use an affinity card. +-- Note that the SQL data mining functions seamless work against +-- tables that contain nested table columns of type DM_Nested_Numerical +-- or DM_Nested_Categorical. The nested column COMMENT is also part +-- of this input. +-- +SELECT cust_id + FROM (SELECT cust_id + FROM t_svmc_sample_apply_prepared + ORDER BY PREDICTION_PROBABILITY(T_SVM_Clas_sample, 1 USING *) DESC, 1) +WHERE ROWNUM < 11; + +------------------ +-- BUSINESS CASE 2 +-- Find the average age of customers who are likely to use an +-- affinity card. Break out the results by gender. +-- +SELECT cust_gender, + COUNT(*) AS cnt, + ROUND(AVG(age)) AS avg_age + FROM t_svmc_sample_apply_prepared + WHERE PREDICTION(T_SVM_Clas_sample USING *) = 1 +GROUP BY cust_gender +ORDER BY cust_gender; diff --git a/dmtxtsvmdemo.java b/dmtxtsvmdemo.java new file mode 100644 index 0000000..f96f0e5 --- /dev/null +++ b/dmtxtsvmdemo.java @@ -0,0 +1,774 @@ +// Copyright (c) 2004, 2006, Oracle. All rights reserved. +// File: dmtxtsvmdemo.java +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to solve a classification problem using the Support Vector Machines (SVM) +* algorithm. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* How to predict whether a customer responds or not to the new affinity card +* program using a classifier based on the SVM algorithm with text mining? +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* comments(text), demographics, purchasing, and response details for the +* previous affinity card programs. Data exploration and preparing the data is a +* common step before doing data mining. Here in this demo, the following views are +* created in the user schema using CUSTOMERS, COUNTRIES, and +* SUPPLIMENTARY_DEMOGRAPHICS tables. +* +* MINING_BUILD_TEXT: +* This view collects the previous customers' comments(text), demographics, +* purchasing, and affinity card response details for building the model. +* +* MINING_APPLY_TEXT: +* This view collects the prospective customers' comments(text), demographics, +* and purchasing details for predicting response for the new affinity card +* program. +* ------------------------------------------------------------------------------ +* DATA MINING PROCESS +* ------------------------------------------------------------------------------ +* Prepare Data: +* 1. Missing Value treatment for Predictors in Build, Test and Apply data +* See dmsvcdemo.java for a definition of missing values, and the steps to be +* taken for missing value imputation. SVM interprets all NULL values for a +* given attribute as "sparse". We skip missing values treatment in this demo. +* +* 2. Outlier/Clipping Treatment for Predictors for Build data +* See dmsvcdemo.java for discussion of outlier treatment. We skip outlier +* treatment in this demo. +* +* 3. Normalize Predictors in Build, Test, and Apply data, unlike Regression +* using SVM, the target attribute is NOT normalized. +* +* The PrepareData() method in this demo program illustrates the preparation of the +* build and apply data. +* +* Build Model: +* Mining Model is the prime object in data mining. The buildModel() method +* illustrates how to build a classification model using the SVM algorithm with +* text mining. +* +* Apply Model: +* Predicting the target attribute values is the prime function of +* classification text mining models. The applyModel() method illustrates how to +* predict the customer response for an affinity card program. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ +// Generic Java api imports +import java.math.BigDecimal; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; +import java.text.DecimalFormat; +import java.text.MessageFormat; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +// Java Data Mining (JDM) standard api imports +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.MiningAlgorithm; +import javax.datamining.MiningFunction; +import javax.datamining.NamedObject; +import javax.datamining.algorithm.svm.KernelFunction; +import javax.datamining.algorithm.svm.classification.SVMClassificationSettings; +import javax.datamining.algorithm.svm.classification.SVMClassificationSettingsFactory; +import javax.datamining.base.AlgorithmSettings; +import javax.datamining.base.Model; +import javax.datamining.base.Task; +import javax.datamining.data.AttributeDataType; +import javax.datamining.data.CategorySet; +import javax.datamining.data.ModelSignature; +import javax.datamining.data.PhysicalAttribute; +import javax.datamining.data.PhysicalAttributeFactory; +import javax.datamining.data.PhysicalAttributeRole; +import javax.datamining.data.PhysicalDataSet; +import javax.datamining.data.PhysicalDataSetFactory; +import javax.datamining.data.SignatureAttribute; +import javax.datamining.modeldetail.svm.SVMClassificationModelDetail; +import javax.datamining.resource.ConnectionSpec; +import javax.datamining.supervised.classification.ClassificationApplySettings; +import javax.datamining.supervised.classification.ClassificationApplySettingsFactory; +import javax.datamining.supervised.classification.ClassificationModel; +import javax.datamining.supervised.classification.ClassificationSettings; +import javax.datamining.supervised.classification.ClassificationSettingsFactory; +import javax.datamining.supervised.classification.ClassificationTestMetricsTaskFactory; +import javax.datamining.supervised.classification.ClassificationTestTaskFactory; +import javax.datamining.task.BuildTask; +import javax.datamining.task.BuildTaskFactory; +import javax.datamining.task.apply.DataSetApplyTask; +import javax.datamining.task.apply.DataSetApplyTaskFactory; +// Oracle Java Data Mining (JDM) implemented api imports +import oracle.dmt.jdm.algorithm.svm.classification.OraSVMClassificationSettings; +import oracle.dmt.jdm.modeldetail.svm.OraSVMClassificationModelDetail; +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.supervised.classification.OraClassificationModel; +import oracle.dmt.jdm.task.OraPredictTaskFactory; +import oracle.dmt.jdm.task.OraTransformationTask; +import oracle.dmt.jdm.task.OraTransformationTaskFactory; +import oracle.dmt.jdm.transform.clipping.OraClippingTransformFactory; +import oracle.dmt.jdm.transform.normalize.OraNormalizeTransformFactory; +import oracle.dmt.jdm.transform.normalize.OraNormalizeTransform; +import oracle.dmt.jdm.transform.normalize.OraNormalizeType; +import oracle.dmt.jdm.transform.text.OraTextTransform; +import oracle.dmt.jdm.transform.text.OraTextTransformFactory; + + +public class dmtxtsvmdemo extends Object { + // Connection related data members + private static javax.datamining.resource.Connection m_dmeConn; + private static javax.datamining.resource.ConnectionFactory m_dmeConnFactory; + // Object factories used in this demo program + private static PhysicalDataSetFactory m_pdsFactory; + private static PhysicalAttributeFactory m_paFactory; + private static ClassificationSettingsFactory m_clasFactory; + private static SVMClassificationSettingsFactory m_svmcFactory; + private static BuildTaskFactory m_buildFactory; + private static DataSetApplyTaskFactory m_dsApplyFactory; + private static ClassificationTestTaskFactory m_testFactory; + private static OraPredictTaskFactory m_predictFactory; + private static ClassificationApplySettingsFactory m_applySettingsFactory; + private static ClassificationTestMetricsTaskFactory m_testMetricsTaskFactory; + private static OraTextTransformFactory m_textXformFactory; + private static OraNormalizeTransformFactory m_normalizeXformFactory; + private static OraClippingTransformFactory m_clippingXformFactory; + private static OraTransformationTaskFactory m_xformTaskFactory; + // Global constants + private static DecimalFormat m_df = new DecimalFormat("##.####"); + // Global data members + private static OraNormalizeTransform m_normalizeDataXform; + + private static boolean displayModelDeatils = false;//By default it is set to false. To view the details of the model this flag can be enabled + + public static void main( String args[] ) { + try { + if (( args.length != 0 ) & ( args.length != 3 )) { + System.out.println("Usage: java dmtxtsvmdemo "); + System.out.println(" or: java dmtxtsvmdemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + // 1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@"+uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. Prepare data + prepareData(); + // 5. Build model + buildModel(); + // 6. Test model - See dmsvcdemo.java for examples. The key difference + // here is the nested table input, and you can adapt that sample code to + // accept the table with a nested table column as input. + // 7. Apply the model + applyModel(); + } catch(Exception anyExp) { + anyExp.printStackTrace(System.out); + } finally { + try { + // 8. Logout from the Data Mining Engine + m_dmeConn.close(); + } catch(Exception anyExp1) { } // Ignore + } + } + + /** + * Initialize all object factories used in the demo program. + */ + public static void initFactories() throws JDMException + { + m_pdsFactory = (PhysicalDataSetFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalDataSet"); + m_paFactory = (PhysicalAttributeFactory)m_dmeConn.getFactory( + "javax.datamining.data.PhysicalAttribute"); + m_clasFactory = (ClassificationSettingsFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationSettings"); + m_svmcFactory = (SVMClassificationSettingsFactory)m_dmeConn.getFactory( + "javax.datamining.algorithm.svm.classification.SVMClassificationSettings"); + m_buildFactory = (BuildTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.BuildTask"); + m_predictFactory = (OraPredictTaskFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.task.OraPredictTask"); + m_testFactory = (ClassificationTestTaskFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationTestTask"); + m_dsApplyFactory = (DataSetApplyTaskFactory)m_dmeConn.getFactory( + "javax.datamining.task.apply.DataSetApplyTask"); + m_applySettingsFactory = (ClassificationApplySettingsFactory)m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationApplySettings"); + m_testMetricsTaskFactory = (ClassificationTestMetricsTaskFactory) m_dmeConn.getFactory( + "javax.datamining.supervised.classification.ClassificationTestMetricsTask"); + m_clippingXformFactory = (OraClippingTransformFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.transform.clipping.OraClippingTransform"); + m_normalizeXformFactory = (OraNormalizeTransformFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.transform.normalize.OraNormalizeTransform"); + m_textXformFactory = (OraTextTransformFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.transform.text.OraTextTransform"); + m_xformTaskFactory = (OraTransformationTaskFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.task.OraTransformationTask"); + } + + /** + * This method illustrates preparation of the data for build, test, and apply + * operations by using missing value, clipping and normalization + * transformation. + * + * The following table illustrates customer attributes available for building + * the mining model and data characteristics and type of transformation used + * for each attribute. + * + * Transformations: + * 1. Missing Value (MISSING): Skipped - see dmsvcdemo.java for example. + * + * 2. Clipping (CLIPPING): Skipped - see dmsvcdemo.java for example. + * + * 3. Normalization (NORMALIZING): Normalize numerical attributes AGE and + * YRS_RESIDENCE. We will use default(minmax) normalization type to + * treat these numerical attributes. + * + * COLUMN_NAME DATA_TYPE DISTINCT NORMALIZING + * ------------------ --------- -------- ----------- + * CUST_ID NUMBER 1500 + * CUST_GENDER CHAR 2 + * AGE NUMBER 66 MINMAX + * CUST_MARITAL_STATUS VARCHAR2 7 + * COUNTRY_NAME VARCHAR2 19 + * CUST_INCOME_LEVEL VARCHAR2 12 + * EDUCATION VARCHAR2 16 + * OCCUPATION VARCHAR2 15 + * HOUSEHOLD_SIZE VARCHAR2 6 + * YRS_RESIDENCE NUMBER 15 MINMAX + * AFFINITY_CARD NUMBER 2 + * BULK_PACK_DISKETTES NUMBER 2 + * FLAT_PANEL_MONITOR NUMBER 2 + * HOME_THEATER_PACKAGE NUMBER 2 + * BOOKKEEPING_APPLICATION NUMBER 2 + * PRINTER_SUPPLIES NUMBER 1 + * Y_BOX_GAMES NUMBER 2 + * OS_DOC_SET_KANJI NUMBER 2 + * OS_DOC_SET_KANJI NUMBER 2 + * COMMENTS VARCHAR2(4000) 44 + * + * The following tables are created after the execution of this method. + * + * Unprepared Data ---> Prepared(Normalized) Data + * ------------------------ --------------------------- + * MINING_BUILD_TEXT TXTSVM_NORM_DATA_BUILD_JDM + * MINING_APPLY_TEXT TXTSVM_NORM_DATA_APPLY_JDM + */ + public static void prepareData() throws JDMException + { + boolean isOutputAsView = false; + String inputDataURI = null; + String outputDataURI = null; + String inputNormalizationDefinitionTable = null; + String inputClippingDefinitionTable = null; + OraTransformationTask xformTask = null; + //------------------------------------------------------------------------ + // 1. Prepare build data + //------------------------------------------------------------------------ + // Text Transformation - Convert text column into a nested column in order + // to perform text mining + isOutputAsView = false; + inputDataURI = "MINING_BUILD_TEXT"; + outputDataURI = "TXTSVM_BUILD_NESTED_TEXT"; + String caseId = "CUST_ID"; + String[] textColumnList = {"COMMENTS"}; + OraTextTransform textDataXform = + (OraTextTransform)m_textXformFactory.create( + inputDataURI, outputDataURI, caseId, textColumnList); + xformTask = m_xformTaskFactory.create(textDataXform); + executeTask(xformTask, "txtsvmPrepareTextB_jdm"); + // Normalization - unlike SVM regression, the classification target is + // NOT normalized here. In addition, case id and binary numerical + // attributes do not need to be normalized in any case. + // + // Create normalization definition table from mining build nested data + isOutputAsView = true; + inputDataURI = "TXTSVM_BUILD_NESTED_TEXT"; + outputDataURI = "TXTSVM_NORM_DATA_BUILD_JDM"; + OraNormalizeType normalizeType = OraNormalizeType.min_max; + Integer roundingNumber = new Integer(0); + OraNormalizeTransform buildDataXform = + (OraNormalizeTransform)m_normalizeXformFactory.create( + inputDataURI, outputDataURI, isOutputAsView, + normalizeType, roundingNumber); + String[] excludeColumnList = { + "CUST_ID", + "AFFINITY_CARD", + "BULK_PACK_DISKETTES", + "FLAT_PANEL_MONITOR", + "HOME_THEATER_PACKAGE", + "BOOKKEEPING_APPLICATION", + "PRINTER_SUPPLIES", + "Y_BOX_GAMES", + "OS_DOC_SET_KANJI", + "COMMENTS" + }; + buildDataXform.setExcludeColumnList(excludeColumnList); + xformTask = m_xformTaskFactory.create(buildDataXform); + executeTask(xformTask, "txtsvmPrepareBuild_jdm"); + //------------------------------------------------------------------------ + // 2. Prepare apply data - if the data for model creation has been + // prepared, then the data to be scored using the model must be + // prepared in the same manner in order to obtain meaningful results. + //------------------------------------------------------------------------ + // Text Transformation - Convert text column into a nested column in order + // to perform text mining + isOutputAsView = false; + inputDataURI = "MINING_APPLY_TEXT"; + outputDataURI = "TXTSVM_APPLY_NESTED_TEXT"; + caseId = "CUST_ID"; + textColumnList = new String[] {"COMMENTS"}; + //Get feature tables created by the build text transformation + OraTransformationTask buildTextXformTask = (OraTransformationTask)m_dmeConn.retrieveObject( + "txtsvmPrepareTextB_jdm", NamedObject.task); + String[] buildFeatureTables = ((OraTextTransform)buildTextXformTask.getTransformation()).getFeatureTables(); + textDataXform = + (OraTextTransform)m_textXformFactory.create( + inputDataURI, outputDataURI, caseId, textColumnList, + buildFeatureTables); + xformTask = m_xformTaskFactory.create(textDataXform); + executeTask(xformTask, "txtsvmPrepareTextA_jdm"); + // Normalization + isOutputAsView = true; + inputDataURI = "TXTSVM_APPLY_NESTED_TEXT"; + outputDataURI = "TXTSVM_NORM_DATA_APPLY_JDM"; + inputNormalizationDefinitionTable = + buildDataXform.getNormalizationDefinitionTable(); + OraNormalizeTransform applyDataXform = + (OraNormalizeTransform)m_normalizeXformFactory.create( + inputDataURI, outputDataURI, + isOutputAsView, inputNormalizationDefinitionTable); + xformTask = m_xformTaskFactory.create(applyDataXform); + executeTask(xformTask, "txtsvmPrepareApply_jdm"); + } + + /** + * This method illustrates how to build a text mining model using the + * TXTSVM_NORM_DATA_BUILD_JDM dataset and classification settings with + * the SVM algorithm. + * + * By default, the SVM algorithm chooses a kernel type automatically. This + * choice can be overriden by the user. Linear kernel is preferred for high + * dimensional data, and Gaussian kernel for low dimensional data. Here we use + * linear kernel to demonstrate the getModelDetail() API, which applies only + * for models. + */ + public static void buildModel() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Build Model ---"); + System.out.println("---------------------------------------------------"); + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet buildData = + m_pdsFactory.create("TXTSVM_NORM_DATA_BUILD_JDM", false); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + buildData.addAttribute(pa); + m_dmeConn.saveObject("txtsvmBuildData_jdm", buildData, true); + // 2. Create & save Mining Function Settings + // Create SVMC algorithm settings + SVMClassificationSettings svmcAlgo = m_svmcFactory.create(); + svmcAlgo.setKernelFunction(KernelFunction.kLinear); + // Examples settings are: + // svmcAlgo.setKernelFunction(KernelFunction.kGaussian); + // svmcAlgo.setComplexityFactor(0.01f); + // svmcAlgo.setTolerance(0.01f); + // + //Create ClassificationSettings + ClassificationSettings buildSettings = m_clasFactory.create(); + buildSettings.setAlgorithmSettings(svmcAlgo); + buildSettings.setTargetAttributeName("AFFINITY_CARD"); + m_dmeConn.saveObject("txtsvmBuildSettings_jdm", buildSettings, true); + // 3. Create, save & execute Build Task + BuildTask buildTask = m_buildFactory.create( + "txtsvmBuildData_jdm", //Build data specification + "txtsvmBuildSettings_jdm", //Mining function settings name + "txtsvmModel_jdm" //Mining model name + ); + buildTask.setDescription("txtsvmBuildTask_jdm"); + executeTask(buildTask, "txtsvmBuildTask_jdm"); + //4. Restore the model from the DME and explore the details of the model + ClassificationModel model = + (ClassificationModel)m_dmeConn.retrieveObject( + "txtsvmModel_jdm", NamedObject.model); + // Display model build settings + ClassificationSettings retrievedBuildSettings = + (ClassificationSettings)model.getBuildSettings(); + if(buildSettings == null) + System.out.println("Failure to restore build settings."); + else + displayBuildSettings(retrievedBuildSettings, "txtsvmBuildSettings_jdm"); + // Display model signature + displayModelSignature((Model)model); + // Display model details + if(displayModelDeatils) + displaySVMCModelDetails((Model)model); + } + + /** + * This method illustrates how to apply the mining model on the + * TXTSVM_NORM_DATA_APPLY_JDM dataset to predict customer + * response. After completion of the task, an apply output table with the + * predicted results is created at the user-specified location. + */ + public static void applyModel() throws JDMException + { + System.out.println("---------------------------------------------------"); + System.out.println("--- Apply Model ---"); + System.out.println("---------------------------------------------------"); + // The key here is to demonstrate the use of these functions on a scoring + // table with nested table input for attributes. + // 1. Create & save PhysicalDataSpecification + PhysicalDataSet applyData = m_pdsFactory.create( + "TXTSVM_NORM_DATA_APPLY_JDM", false ); + PhysicalAttribute pa = m_paFactory.create("CUST_ID", + AttributeDataType.integerType, PhysicalAttributeRole.caseId ); + applyData.addAttribute( pa ); + m_dmeConn.saveObject( "txtsvmApplyData_jdm", applyData, true ); + // 2. Create & save ClassificationApplySettings + ClassificationApplySettings clasAS = m_applySettingsFactory.create(); + m_dmeConn.saveObject( "txtsvmApplySettings_jdm", clasAS, true); + // 3. Create, store & execute apply Task + DataSetApplyTask applyTask = m_dsApplyFactory.create( + "txtsvmApplyData_jdm", "txtsvmModel_jdm", + "txtsvmApplySettings_jdm", "TXTSVM_APPLY_OUTPUT_JDM"); + executeTask(applyTask, "txtsvmApplyTask_jdm"); + // 4. Display apply result -- Note that APPLY results do not need to be + // reverse transformed, as done in the case of model details. This is + // because class values of a classification target were not (required to + // be) binned or normalized. + // + // Find the 10 customers who are most likely to use an affinity card. + // Note that the SQL data mining functions seamless work against + // tables that contain nested table columns of type DM_Nested_Numerical + // or DM_Nested_Categorical. The nested column COMMENT is also part + // of this input. + displayTable("TXTSVM_APPLY_OUTPUT_JDM", + "where PREDICTION =1 and ROWNUM < 11", + "order by PROBABILITY desc"); + } + + /** + * This method stores the given task with the specified name in the DMS + * and submits the task for asynchronous execution in the DMS. After + * completing the task successfully it returns true. If there is a task + * failure, then it prints error description and returns false. + * + * @param taskObj task object + * @param taskName name of the task + * + * @return boolean returns true when the task is successful + */ + public static boolean executeTask(Task taskObj, String taskName) + throws JDMException { + boolean isTaskSuccess = false; + m_dmeConn.saveObject(taskName, taskObj, true); + ExecutionHandle execHandle = m_dmeConn.execute(taskName); + System.out.print(taskName + " is started, please wait. "); + //Wait for completion of the task + ExecutionStatus status = execHandle.waitForCompletion(Integer.MAX_VALUE); + //Check the status of the task after completion + isTaskSuccess = status.getState().equals(ExecutionState.success); + if( isTaskSuccess ) { + //Task completed successfully + System.out.println(taskName + " is successful."); + } else {//Task failed + System.out.println(taskName + " is failed.\nFailure Description: " + + status.getDescription() ); + } + return isTaskSuccess; + } + + private static void displayBuildSettings( + ClassificationSettings clasSettings, String buildSettingsName) + { + // Display build settings table + System.out.println("BuildSettings Details from the " + + buildSettingsName + " table:"); + displayTable(buildSettingsName, "", "order by SETTING_NAME"); + // Display build settings object obtained from the model + System.out.println("BuildSettings Details from the " + + buildSettingsName + " model build settings object:"); + String objName = clasSettings.getName(); + if(objName != null) + System.out.println("Name = " + objName); + String objDescription = clasSettings.getDescription(); + if(objDescription != null) + System.out.println("Description = " + objDescription); + java.util.Date creationDate = clasSettings.getCreationDate(); + String creator = clasSettings.getCreatorInfo(); + String targetAttrName = clasSettings.getTargetAttributeName(); + System.out.println("Target attribute name = " + targetAttrName); + AlgorithmSettings algoSettings = clasSettings.getAlgorithmSettings(); + if(algoSettings == null) + System.out.println("Failure: clasSettings.getAlgorithmSettings() returns null"); + MiningAlgorithm algo = algoSettings.getMiningAlgorithm(); + if(algo == null) System.out.println("Failure: algoSettings.getMiningAlgorithm() returns null"); + System.out.println("Algorithm Name: " + algo.name()); + MiningFunction function = clasSettings.getMiningFunction(); + if(function == null) System.out.println("Failure: clasSettings.getMiningFunction() returns null"); + System.out.println("Function Name: " + function.name()); + try { + Map map = clasSettings.getPriorProbabilitiesMap(targetAttrName); + if(map != null) System.out.println("Priors Map: " + map.toString()); + } catch(Exception jdmExp) + { + System.out.println("Failure: clasSettings.getPriorProbabilitiesMap(targetAttrName)throws exception"); + jdmExp.printStackTrace(); + } + // List of SVM algorithm settings availabe in linear kernel + KernelFunction kernelFunction = ((OraSVMClassificationSettings)algoSettings).getKernelFunction(); + System.out.println("Kernel Function: " + kernelFunction.name()); + double doubleValue = ((OraSVMClassificationSettings)algoSettings).getComplexityFactor(); + System.out.println("Complexity Factor: " + m_df.format(doubleValue)); + doubleValue = ((OraSVMClassificationSettings)algoSettings).getTolerance(); + System.out.println("Tolerance: " + m_df.format(doubleValue)); + boolean enable = ((OraSVMClassificationSettings)algoSettings).getActiveLearning(); + System.out.println("Is Active Learning enabled? " + enable); + } + + /** + * This method displayes SVMC model signature. + * + * @param model model object + */ + public static void displayModelSignature(Model model) throws JDMException + { + String modelName = model.getName(); + System.out.println("Model Name: " + modelName); + ModelSignature modelSignature = model.getSignature(); + System.out.println("Model Signature: ( Attribute Name, Attribute Type )"); + MessageFormat mfSign = new MessageFormat(" ( {0}, {1} )"); + String[] vals = new String[2]; + Collection sortedSet = modelSignature.getAttributes(); + Iterator attrIterator = sortedSet.iterator(); + while(attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute)attrIterator.next(); + vals[0] = attr.getName(); + vals[1] = attr.getDataType().name(); + System.out.println( mfSign.format(vals) ); + } + } + + /** + * This method displayes SVMC model details. The coefficient indicates the + * relative influence of a given (attribute, value) pair on the target value. + * A negative coefficient value indicates a negative influence. + * + * @param svmcModelDetails svm classification model details object + * @exception JDMException if failed to retrieve model details + */ + public static void displaySVMCModelDetails( + Model model) throws JDMException + { + // Obtains model details + SVMClassificationModelDetail svmcModelDetails = + (SVMClassificationModelDetail)model.getModelDetail(); + // Is linear model? + System.out.println("Is linear model? " + svmcModelDetails.isLinearSVMModel() ); + // Available targets + CategorySet targetSet = ((OraClassificationModel)model).getTargetCategorySet(); + Object[] targets = targetSet.getValues(); + // Attribute coefficient value will be available if it is a linear model + if (svmcModelDetails.isLinearSVMModel()) + { + System.out.println("Model Deatils: ( Target Value, Attribute Name, Attribute Value, Coefficient)"); + MessageFormat mfDetails = new MessageFormat(" ( {0}, {1}, {2}, {3} )"); + String[] vals = new String[4]; + for (int row =0; row < targets.length; row++) + { + // Print bias of the current target value by invoking getBias method. + vals[0] =(String) targets[row].toString(); + vals[1] = ""; + vals[2] = ""; + vals[3] = m_df.format(svmcModelDetails.getBias(targets[row])) + " (Bias)"; + System.out.println( mfDetails.format(vals) ); + //Get the signature attributes + ModelSignature modelSignature = model.getSignature(); + Collection sortedSet = modelSignature.getAttributes(); + Iterator attrIterator = sortedSet.iterator(); + + while(attrIterator.hasNext()) + { + SignatureAttribute attr = (SignatureAttribute)attrIterator.next(); + // Print all attribute coefficients -- The FIRST row in the SVM model + // details output shows the value for SVM bias under the COEFFICIENT + // column. + Map attrCoefficientMap = ((OraSVMClassificationModelDetail)svmcModelDetails).getCoefficients(targets[row],attr.getName()); + Object[] attrVals = attrCoefficientMap.keySet().toArray(); + if(attrVals != null) { + for(int iAttr=0; iAttr < attrVals.length; iAttr++) + { + vals[1] = attr.getName(); + vals[2] = ""; + if(attrVals[iAttr] != null) + vals[2] = attrVals[iAttr].toString(); + vals[3] = ""; + Number coefficient = (Number)attrCoefficientMap.get(attrVals[iAttr]); + if(coefficient != null) + vals[3] = m_df.format(coefficient); + System.out.println( mfDetails.format(vals) ); + } + } + } + } + } + } + + private static void displayTable(String tableName, String whereCause, String orderByColumn) + { + StringBuffer emptyCol = new StringBuffer(" "); + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + PreparedStatement pStmt = null; + ResultSet rs = null; + try + { + pStmt = dbConn.prepareStatement("SELECT * FROM " + tableName + " " + whereCause + " " + orderByColumn); + rs = pStmt.executeQuery(); + ResultSetMetaData rsMeta = rs.getMetaData(); + int colCount = rsMeta.getColumnCount(); + StringBuffer header = new StringBuffer(); + System.out.println("Table : " + tableName); + // Build table header + for(int iCol=1; iCol<=colCount; iCol++) + { + String colName = rsMeta.getColumnName(iCol); + header.append(emptyCol.replace(0, colName.length(), colName)); + emptyCol = new StringBuffer(" "); + } + System.out.println(header.toString()); + // Write table data + while(rs.next()) + { + StringBuffer rowContent = new StringBuffer(); + for(int iCol=1; iCol<=colCount; iCol++) + { + int sqlType = rsMeta.getColumnType(iCol); + Object obj = rs.getObject(iCol); + String colContent = null; + + if(obj instanceof java.lang.Number) + { + try + { + BigDecimal bd = (BigDecimal)obj; + if(bd.scale() > 5) + { + colContent = m_df.format(obj); + } else + { + colContent = bd.toString(); + } + } catch(Exception anyExp) { + colContent = m_df.format(obj); + } + } else + { + if(obj == null) + colContent = "NULL"; + else + colContent = obj.toString(); + } + rowContent.append(" "+emptyCol.replace(0, colContent.length(), colContent)); + emptyCol = new StringBuffer(" "); + } + System.out.println(rowContent.toString()); + } + } catch(Exception anySqlExp) { + anySqlExp.printStackTrace(); + } // Ignore + } + + private static void clean() + { + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + Statement stmt = null; + //Drop prepared tables + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP TABLE TXTSVM_BUILD_NESTED_TEXT"); + } catch(SQLException anySqlExp) {} // Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP TABLE TXTSVM_APPLY_NESTED_TEXT"); + } catch(SQLException anySqlExp) {} // Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + //Drop prepared views + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP VIEW TXTSVM_NORM_DATA_BUILD_JDM"); + } catch(SQLException anySqlExp) {} // Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP VIEW TXTSVM_NORM_DATA_APPLY_JDM"); + } catch(SQLException anySqlExp) {} // Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + //Drop apply output table + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP TABLE TXTSVM_APPLY_OUTPUT_JDM"); + } catch(SQLException anySqlExp) {} // Ignore + finally{ + try { + stmt.close(); + } + catch(Exception anySqlExp){} + } + //Drop the model + try { + m_dmeConn.removeObject("txtsvmModel_jdm", NamedObject.model); + } catch(JDMException jdmExp) {} + } +} diff --git a/dmxfdemo.java b/dmxfdemo.java new file mode 100644 index 0000000..8f66550 --- /dev/null +++ b/dmxfdemo.java @@ -0,0 +1,893 @@ +// Copyright (c) 2001, 2007, Oracle. All rights reserved. +// File: dmxfdemo.java + +/** +* This demo program describes how to use the Oracle Data Mining (ODM) Java API +* to perform mining transformations: discretization, clipping, and normalization. +* ------------------------------------------------------------------------------ +* PROBLEM DEFINITION +* ------------------------------------------------------------------------------ +* Data preparation is an important step preceding actual data mining. The following +* types of transformation are demonstrated: discretization, clipping and +* normalization. +* Discretization involves mapping both continuous and discrete values to discrete +* values of reduced cardinality. It can be performed on both categorical and +* numerical attributes. The following types of discretization are demonstrated +* for numerical attributes: equal width, quantile and custom. Top-N method can be +* applied to categorical attributes. +* Normalization involves scaling continuous values down to specific range - as +* in -1.0 to 1.0 or 0.0 to 1.0 such that xnew = (xold - shift)/scale. +* It applies only to numerical attributes. Min-Max Normalization and Z-Score +* Normalization are shown. +* Clipping involves setting the tail values of a particular attribute to some +* specified quantile of the data, or removing the tails. It applies only to +* numerical attributes. Winsorizing and trimming methods are presented. +* ------------------------------------------------------------------------------ +* DATA DESCRIPTION +* ------------------------------------------------------------------------------ +* Data for this demo is composed from base tables in the Sales History (SH) +* Schema. The SH schema is an Oracle Database Sample Schema that has the customer +* demographics, purchasing, and response details for the previous affinity card +* programs. Data exploration and preparing the data is a common step before +* doing data mining. Here in this demo, the following views are created +* in the user schema using CUSTOMERS, COUNTRIES, and SUPPLIMENTARY_DEMOGRAPHICS +* tables. +* +* MINING_DATA_BUILD_V: +* This view collects the previous customers' demographic, purchasing, and affinity +* card response details for building the model. +* ------------------------------------------------------------------------------ +* EXECUTING DEMO PROGRAM +* ------------------------------------------------------------------------------ +* Refer to Oracle Data Mining Administrator's Guide +* for guidelines for executing this demo program. +*/ + +// Generic api imports +import java.math.BigDecimal; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.text.DecimalFormat; +import java.text.MessageFormat; +import java.util.Vector; +import java.util.ArrayList; +// Java Data Mining (JDM) standard imports +import javax.datamining.ExecutionHandle; +import javax.datamining.ExecutionState; +import javax.datamining.ExecutionStatus; +import javax.datamining.JDMException; +import javax.datamining.base.Task; +import javax.datamining.resource.ConnectionSpec; +// Oracle Java Data Mining (JDM) implemented api imports +import oracle.dmt.jdm.resource.OraConnection; +import oracle.dmt.jdm.resource.OraConnectionFactory; +import oracle.dmt.jdm.task.OraTransformationTask; +import oracle.dmt.jdm.task.OraTransformationTaskFactory; +import oracle.dmt.jdm.transform.OraTransformationFactory; +import oracle.dmt.jdm.transform.OraTransformationSequence; +import oracle.dmt.jdm.transform.binning.OraAttributeBins; +import oracle.dmt.jdm.transform.binning.OraBinningTransform; +import oracle.dmt.jdm.transform.binning.OraBinningTransformFactory; +import oracle.dmt.jdm.transform.binning.OraCategoricalAttributeBins; +import oracle.dmt.jdm.transform.binning.OraCategoricalBin; +import oracle.dmt.jdm.transform.binning.OraCategoricalBinningType; +import oracle.dmt.jdm.transform.binning.OraNumericalAttributeBins; +import oracle.dmt.jdm.transform.binning.OraNumericalBin; +import oracle.dmt.jdm.transform.binning.OraNumericalBinningType; +import oracle.dmt.jdm.transform.clipping.OraClippingTransform; +import oracle.dmt.jdm.transform.clipping.OraClippingTransformFactory; +import oracle.dmt.jdm.transform.clipping.OraClippingType; +import oracle.dmt.jdm.transform.normalize.OraNormalizeTransform; +import oracle.dmt.jdm.transform.normalize.OraNormalizeTransformFactory; +import oracle.dmt.jdm.transform.normalize.OraNormalizeType; +import oracle.dmt.jdm.utils.OraSQLUtils; + +public class dmxfdemo extends Object{ + //Connection related data members + private static javax.datamining.resource.Connection m_dmeConn = null; + private static javax.datamining.resource.ConnectionFactory m_dmeConnFactory = null; + //Object factories used in this demo program + private static OraTransformationFactory m_xformFactory = null; + private static OraTransformationTaskFactory m_xformTaskFactory = null; + private static OraBinningTransformFactory m_binXformFactory = null; + // Global constant used for formatting + protected static DecimalFormat m_df = new DecimalFormat("00.##E0"); + + public static void main( String args[] ) { + try { + if (( args.length != 0 ) & ( args.length != 3 )) { + System.out.println("Usage: java dmxfdemo "); + System.out.println(" or: java dmxfdemo :: "); + return; + } + String uri = args[0]; + String name = args[1]; + String password = args[2]; + //1. Login to the Data Mining Engine + m_dmeConnFactory = new OraConnectionFactory(); + ConnectionSpec connSpec = m_dmeConnFactory.getConnectionSpec(); + connSpec.setURI("jdbc:oracle:thin:@"+uri); + connSpec.setName(name); + connSpec.setPassword(password); + m_dmeConn = m_dmeConnFactory.getConnection(connSpec); + // 2. Clean up all previuosly created demo objects + clean(); + // 3. Initialize factories for mining objects + initFactories(); + // 4. custom binning + binDataCustom("MINING_DATA_BINNED_CUSTOM"); + // 5. discretize data using equal width + binDataEqWidth(); + // 6. discretize data using quantile + binDataQtile(); + // 7. bin using supervised method + binSupervised(); + // 8. clip data using trimming + clipDataTrim(); + // 9. clip data using winsorizing + clipDataWinsorize(); + // 10. normalize data using min-max + normalizeMinMax(); + // 11. normalize data using z-score + normalizeZScore(); + } catch(Exception anyExp) { + anyExp.printStackTrace(System.out); + } finally { + try { + // 10. Logout from the Data Mining Engine + m_dmeConn.close(); + } catch(Exception anyExp1) { }//Ignore + } + } + + /** + * Initialize all object factories used in the demo program. + * + * @exception JDMException if factory initalization failed + */ + public static void initFactories() throws JDMException + { + m_xformFactory = (OraTransformationFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.transform.OraTransformation"); + m_xformTaskFactory = (OraTransformationTaskFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.task.OraTransformationTask"); + + m_binXformFactory = (OraBinningTransformFactory)m_dmeConn.getFactory( + "oracle.dmt.jdm.transform.binning.OraBinningTransform"); + + } + + /** + * Illustrates how to perform equal width data discretization + * + * @exception JDMException if discretization failed + */ + public static void binDataEqWidth() throws JDMException + { + binData("MINING_DATA_BINNED_EQW", OraNumericalBinningType.equi_width); + } + + /** + * Illustrates how to perform quantile data discretization + * + * @exception JDMException if discretization failed + */ + public static void binDataQtile() throws JDMException + { + binData("MINING_DATA_BINNED_QTL",OraNumericalBinningType.quantile); + } + + /** + * Illustrates how to perform data discretization. + * + * @param resultXformName name of the result discretized view + * @param binningType type of discretization to perform i.e., + * quantile, equal width or custom + * @throws JDMException if discretization failed + */ + public static void binData(String resultXformName, OraNumericalBinningType binningType) + throws JDMException + { + // Schema where the original data and resulting transformations reside + String schema = ( m_dmeConn.getConnectionSpec().getName() ).toUpperCase(); + + // Create discretization transformation instance + OraBinningTransform obt = m_xformFactory.createBinningTransform(); + obt.setTransformInputData(schema + "." + "MINING_DATA_BUILD_V"); + obt.setTransformOutputData(schema + "." + resultXformName); + + // Specify the number of numeric bins + obt.setNumberOfBinsForNumerical(10); + + // Specify the number of categoric bins + obt.setNumberOfBinsForCategorical(8); + + // Specify the list of excluded attributes + String[] excludedList = new String[]{ + "CUST_ID", "CUST_GENDER" + }; + obt.setExcludeColumnList(excludedList); + + // Specify the type of numeric binning: equal-width or quantile + // ( default is quantile ) + obt.setNumericalBinningType(binningType); + // Specify the type of categorical binning as Top-N: by default it is none + obt.setCategoricalBinningType(OraCategoricalBinningType.top_n); + + ArrayList xformList = new ArrayList(); + xformList.add(obt); + //Create a transformation sequence object + OraTransformationSequence xformSeq = + m_xformFactory.createTransformationSequence( + schema + "." + "MINING_DATA_BUILD_V", // name of the input data set + xformList, //List of transformations. In this case only one type of transformation i.e., supervised binning + schema + "." + resultXformName // name of the transformation result + ); + String xformSeqName = "bin_" + binningType.name() + "_xfSeq"; + m_dmeConn.saveObject(xformSeqName, xformSeq, true); + + OraTransformationTask xformTask = m_xformTaskFactory.create( + xformSeqName, false); + + executeTask(xformTask, "xFormBin_jdm"); + displayDiscretizationResults( + binningType, + schema + "." + resultXformName, + new String[]{"CUST_INCOME_LEVEL","OCCUPATION"} + ); + } + + /** + * Illustrates how to perform custom data discretization. First discretization + * of 2 numerical attributes is performed. "AGE" is binned with equal width + * method with 10 bins and "YRS_RESIDENCE" with quantile method and 5 bins. + * Categorical attributes "EDUCATION" and "OCCUPATION" are discretized + * with the Top-N method into 15 and 10 bins. This method illustrates + * how additional attributes can be added to the existing discretization + * tables: "AFFINITY_CARD" and ""HOUSEHOLD_SIZE". Finally results are combined + * into a single array and custom transformation task is performed. + * + * @param resultXformName name of the result transformation view + * @throws JDMException if transformation failed + */ + public static void binDataCustom(String resultXformName) throws JDMException + { + System.out.println("Custom binning"); + System.out.println("--------------------------------------------"); + // Schema where the original data and resulting transformations reside + String schema = ( m_dmeConn.getConnectionSpec().getName() ).toUpperCase(); + + // Numeric custom binning + OraNumericalAttributeBins[] customNumBins = m_binXformFactory.computeNumericBins( + schema + "." + "MINING_DATA_BUILD_V", // name of the input data set + new String[] { + "AGE", "YRS_RESIDENCE", + }, + new OraNumericalBinningType[] { + OraNumericalBinningType.equi_width, + OraNumericalBinningType.quantile + }, + new Integer[] {new Integer(10), new Integer(5)} + ); + + if ( customNumBins == null ){ + System.out.println("Error: no numeric bins were computed"); + return; + } + + //Categoric custom binning + OraCategoricalAttributeBins[] customCatBins = m_binXformFactory.computeCategoricBins( + schema + "." + "MINING_DATA_BUILD_V", // name of the input data set + new String[] { + "EDUCATION", "OCCUPATION", + }, + new OraCategoricalBinningType[] { + OraCategoricalBinningType.top_n, + OraCategoricalBinningType.top_n, + }, + new Integer[] {new Integer(15), new Integer(10),} + ); + + if ( customCatBins == null ){ + System.out.println("Error: no categoric bins were computed"); + return; + } + + // combine custom bins into the single array + OraAttributeBins[] customBins = null; + customBins = incrementArray(customBins, (OraAttributeBins[])customNumBins); + customBins = incrementArray(customBins, (OraAttributeBins[])customCatBins); + + // show resulting array of custom bins + for ( int i = 0 ; i < customBins.length; i++ ) { + System.out.println("Attribute:" + customBins[i].getAttributeName() ); + + if ( customBins[i] instanceof OraNumericalAttributeBins ){ + OraNumericalAttributeBins oraNumBin = (OraNumericalAttributeBins)customBins[i]; + OraNumericalBin[] bs = oraNumBin.getBins(); + System.out.println("\tBin ID\tLower\tUpper" ); + for ( int j = 0 ; j < bs.length; j++ ) { + System.out.println("\t" + bs[j].getBinID() + "\t" + m_df.format(bs[j].getStartValue()) + + "\t" + m_df.format(bs[j].getEndValue()) ); + } + } + else if ( customBins[i] instanceof OraCategoricalAttributeBins ){ + OraCategoricalAttributeBins oraCatBin = (OraCategoricalAttributeBins)customBins[i]; + OraCategoricalBin[] bs = oraCatBin.getBins(); + System.out.println("\tBin ID\tCategory" ); + for ( int j = 0 ; j < bs.length; j++ ) { + Object[] categories = bs[j].getCategories(); + System.out.print("\t" + bs[j].getBinID() +"\t" ); + for ( int k = 0 ; k < categories.length; k++ ) { + System.out.print(categories[k].toString() ); + if ( k < categories.length - 1 ) + System.out.print(";"); + } + System.out.println(); + } + } + } + // Create discretization transformation instance + OraBinningTransform obt = m_xformFactory.createBinningTransform(customBins); + + // Specify the type of numeric binning: custom + obt.setNumericalBinningType(OraNumericalBinningType.custom); + // Specify the type of categoric binning: custom + obt.setCategoricalBinningType(OraCategoricalBinningType.custom); + + ArrayList xformList = new ArrayList(); + xformList.add(obt); + //Create a transformation sequence object + OraTransformationSequence xformSeq = + m_xformFactory.createTransformationSequence( + schema + "." + "MINING_DATA_BUILD_V", // name of the input data set + xformList, //List of transformations. In this case only one type of transformation i.e., supervised binning + schema + "." + resultXformName // name of the transformation result + ); + String xformSeqName = "bin_" + OraNumericalBinningType.custom.name() + "_xfSeq"; + m_dmeConn.saveObject(xformSeqName, xformSeq, true); + + OraTransformationTask xformTask = m_xformTaskFactory.create(xformSeqName, true); + executeTask(xformTask, "xCustomBin_jdm"); + + // display content of the bin definition tables + showBinDefinitionTableContents(obt.getCategoricalBinTable(), "categorical"); + showBinDefinitionTableContents(obt.getNumericalBinTable(), "numerical"); + + displayDiscretizationResults( + OraNumericalBinningType.custom, + schema + "." + resultXformName, + new String[]{"AGE", "CUST_INCOME_LEVEL","EDUCATION", "OCCUPATION"} + ); + + // Bin additional attribute and add + // to the existing bin definition tables + //---------------------------------------------------------------- + // Numeric custom binning + OraNumericalAttributeBins[] customNumBinsAdd = m_binXformFactory.computeNumericBins( + schema + "." + "MINING_DATA_BUILD_V", // name of the input data set + new String[] { + "AFFINITY_CARD", + }, + new OraNumericalBinningType[] { + OraNumericalBinningType.quantile, + }, + new Integer[] {new Integer(6)} + ); + + if ( customNumBins == null ){ + System.out.println("Error: no numeric bins were computed"); + return; + } + + //Categoric custom binning + OraCategoricalAttributeBins[] customCatBinsAdd = m_binXformFactory.computeCategoricBins( + schema + "." + "MINING_DATA_BUILD_V", // name of the input data set + new String[] { + "HOUSEHOLD_SIZE", + }, + new OraCategoricalBinningType[] { + OraCategoricalBinningType.top_n, + }, + new Integer[] {new Integer(15), new Integer(10),} + ); + + if ( customCatBins == null ){ + System.out.println("Error: no categoric bins were computed"); + return; + } + + // combine custom bins into the single array + OraAttributeBins[] customBinsAdd = null; + customBinsAdd = incrementArray(customBinsAdd, (OraAttributeBins[])customNumBinsAdd); + customBinsAdd = incrementArray(customBinsAdd, (OraAttributeBins[])customCatBinsAdd); + + // clean up previous view + dropView ( null, resultXformName); + + OraBinningTransform obtAdd = m_xformFactory.createBinningTransform( + obt.getCategoricalBinTable(), + obt.getNumericalBinTable(), + customBinsAdd); + obtAdd.setTransformInputData(schema + "." + "MINING_DATA_BUILD_V"); + obtAdd.setTransformOutputData(schema + "." + resultXformName); + + // Specify the type of numeric binning: custom + obtAdd.setNumericalBinningType(OraNumericalBinningType.custom); + // Specify the type of categoric binning: custom + obtAdd.setCategoricalBinningType(OraCategoricalBinningType.custom); + + OraTransformationTask xformTaskAdd = m_xformTaskFactory.create(obtAdd); + executeTask(xformTaskAdd, "xCustomBinAdd_jdm"); + + // display content of the new bin definition tables + showBinDefinitionTableContents(obtAdd.getCategoricalBinTable(), "categorical"); + showBinDefinitionTableContents(obtAdd.getNumericalBinTable(), "numerical"); + + // show results + displayDiscretizationResults( + OraNumericalBinningType.custom, + schema + "." + resultXformName, + new String[]{"AFFINITY_CARD","HOUSEHOLD_SIZE"} + ); + } + + /** + * For supervised functions with the known target attribute, supervised + * binning is a recommended approach. It is a smart binning based on the + * target attribute values. This method is supported from 11.1 release + * of ODM. + */ + public static void binSupervised() throws JDMException { + // Schema where the original data and resulting transformations reside + String schema = ( m_dmeConn.getConnectionSpec().getName() ).toUpperCase(); + + // Create discretization transformation instance + OraBinningTransform obt = m_xformFactory.createBinningTransform(); + + + // Specify the list of excluded attributes + String[] excludedList = new String[]{ + "CUST_ID", "CUST_GENDER" + }; + obt.setExcludeColumnList(excludedList); + + // Specify the type of numeric binning: supervised + obt.setNumericalBinningType(OraNumericalBinningType.supervised); + // Specify the type of categorical binning as supervised + obt.setCategoricalBinningType(OraCategoricalBinningType.supervised); + obt.setTargetAttributeName("AFFINITY_CARD"); + + ArrayList xformList = new ArrayList(); + xformList.add(obt); + //Create a transformation sequence object + OraTransformationSequence xformSeq = + m_xformFactory.createTransformationSequence( + schema + "." + "MINING_DATA_BUILD_V", // name of the input data set + xformList, //List of transformations. In this case only one type of transformation i.e., supervised binning + schema + "." + "MINING_DATA_BINNED_SUP" // name of the transformation result + ); + m_dmeConn.saveObject("superBin_xformSeq", xformSeq, true); + + OraTransformationTask xformTask = m_xformTaskFactory.create( + "superBin_xformSeq", false); + executeTask(xformTask, "xFormSuperBin_jdm"); + displayDiscretizationResults( + OraNumericalBinningType.supervised, + schema + "." + "MINING_DATA_BINNED_SUP", + new String[]{"CUST_INCOME_LEVEL","OCCUPATION"} + ); + } + + /** + * Shows histogram for selected binned attributes + * + * @param binningType type of discretization performed i.e., quantile, equal + * width or custom + * @param xformResult name of the result discretized view + * @param attributes names of attributes for which histogram is displayed + */ + public static void displayDiscretizationResults( + OraNumericalBinningType binningType, String xformResult, String[] attributes) + { + System.out.println("\nShowing results of the discretization transformation"); + System.out.println("\tType of discretization: " + binningType.name() ); + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + for ( int i = 0; i < attributes.length; i++ ) { + String sqlQuery = MessageFormat.format( + "SELECT {0} BIN_NUMBER, COUNT(*) FREQUENCY FROM ({1}) GROUP BY {0} " + + "ORDER BY FREQUENCY DESC,BIN_NUMBER ASC", + new String[]{ + "\""+attributes[i]+"\"", + xformResult + } + ); + Statement stmt = null; + ResultSet rs = null; + System.out.println("\tHistogram for:" + attributes[i]); + try{ + stmt = dbConn.createStatement(); + rs = stmt.executeQuery(sqlQuery); + while ( rs.next() ){ + String binValue = rs.getString("BIN_NUMBER"); + int freq = rs.getInt("FREQUENCY"); + System.out.println("\t\t"+binValue + " " + freq); + } + } + catch(Exception e){ + System.out.println(e); + } + finally{ + try{rs.close(); stmt.close();} + catch(Exception e){} + } + } + } + + + /** + * Shows results of the clipping for selected attributes + * + * @param schema schema where result transformation view resides + * @param xformResult name of the resulting transformation view + * @param attribute name of the attribute for which transformation was performed + * @param clippingType type of clipping which was performed, i.e. + * trimming or winsorising + */ + public static void displayClippingResults( String schema, String xformResult, + String attribute, OraClippingType clippingType) + { + System.out.println("\nShowing results of the clipping transformation"); + System.out.println("\tClipping type: " + + ( true == clippingType.equals(OraClippingType.trim) ? "trim" : "winsorize") ); + System.out.println("\tMinimum and maximum values for:" + attribute + + " before clipping transformation"); + + String sqlQuery = MessageFormat.format( + "SELECT MIN ({0}) MIN_VALUE, MAX ({0}) MAX_VALUE FROM ({1})", + new String[]{ "\""+attribute+"\"", + schema + "." + "MINING_DATA_BUILD_V"} + ); + getMinMax(sqlQuery); + + System.out.println("\tMinimum and maximum values for:" + attribute + + " after clipping transformation."); + sqlQuery = MessageFormat.format( + "SELECT MIN ({0}) MIN_VALUE, MAX ({0}) MAX_VALUE FROM ({1})", + new String[]{ "\""+attribute+"\"", + schema + "." + xformResult} + ); + getMinMax(sqlQuery); + } + + private static void getMinMax(String sqlQuery) + { + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + Statement stmt = null; + ResultSet rs = null; + try{ + stmt = dbConn.createStatement(); + rs = stmt.executeQuery(sqlQuery); + while ( rs.next() ){ + String minValue = rs.getString("MIN_VALUE"); + String maxValue = rs.getString("MAX_VALUE"); + System.out.println( + "\t\tMin value=" + m_df.format(Double.parseDouble(minValue) ) + + ", Max value=" + m_df.format(Double.parseDouble(maxValue))); + } + } + catch(Exception e){ + System.out.println(e); + } + finally{ + try{rs.close(); stmt.close();} + catch(Exception e){} + } + } + + private static void clean() + { + java.sql.Connection dbConn = + ((OraConnection)m_dmeConn).getDatabaseConnection(); + + dropView( dbConn, "MINING_DATA_BINNED_EQW"); + dropView( dbConn, "MINING_DATA_BINNED_QTL"); + dropView( dbConn, "MINING_DATA_CLIP_TRIM"); + dropView( dbConn, "MINING_DATA_CLIP_WINS"); + dropView( dbConn, "MINING_DATA_BINNED_CUSTOM"); + dropView( dbConn, "MINING_DATA_NORMALIZE_MIN_MAX"); + dropView( dbConn, "MINING_DATA_NORMALIZE_Z_SCORE"); + } + + private static void dropView(java.sql.Connection dbConn, String viewName) + { + if ( dbConn == null ) + dbConn = ((OraConnection)m_dmeConn).getDatabaseConnection(); + + Statement stmt = null; + try + { + stmt = dbConn.createStatement(); + stmt.executeUpdate("DROP VIEW " + viewName); + } catch(SQLException anySqlExp) {}//Ignore + finally{ + try{stmt.close();} + catch(SQLException anySqlExp) {} + } + } + + /** + * This method stores the given task with the specified name in the DMS + * and submits the task for asynchronous execution in the DMS. After + * completing the task successfully it returns true. If there is a task + * failure, then it prints the error description and returns false. + * + * @param taskObj task object + * @param taskName name of the task + * + * @return boolean returns true when the task is successful + * @exception JDMException if task execution failed + */ + public static boolean executeTask(Task taskObj, String taskName) + throws JDMException { + boolean isTaskSuccess = false; + m_dmeConn.saveObject(taskName, taskObj, true); + ExecutionHandle execHandle = m_dmeConn.execute(taskName); + System.out.print("\n"+taskName + " is started, please wait. "); + //Wait for completion of the task + ExecutionStatus status = execHandle.waitForCompletion(Integer.MAX_VALUE); + //Check the status of the task after completion + isTaskSuccess = status.getState().equals(ExecutionState.success); + if( isTaskSuccess ) { + //Task completed successfully + System.out.println(taskName + " is successful.\n"); + } else {//Task failed + System.out.println(taskName + " is failed.\nFailure Description: " + + status.getDescription() + "\n" ); + } + return isTaskSuccess; + } + + /** + * Illustrates how to perform trimming type of clipping which involves + * removing the tail values of the attribute. + * + * @throws JDMException if transformation failed + */ + public static void clipDataTrim() throws JDMException + { + clipData(OraClippingType.trim, "MINING_DATA_CLIP_TRIM"); + } + + /** + * Illustrates how to perform winsorising type of clipping which involves + * setting the tail values of a particular attribute to some specified + * quantile of the data. + * + * @throws JDMException if transformation failed + */ + public static void clipDataWinsorize() throws JDMException + { + clipData(OraClippingType.winsorize, "MINING_DATA_CLIP_WINS"); + } + /** + * Illustrates how to perform data clipping + * + * @param clippingType type of clipping to perform + * @param xformResult name of the result transformation view + * @throws JDMException if transformation failed + */ + public static void clipData(OraClippingType clippingType, String xformResult) + throws JDMException + { + // Schema where the original data and resulting transformations reside + String schema = ( m_dmeConn.getConnectionSpec().getName() ).toUpperCase(); + + OraClippingTransform oct = m_xformFactory.createClippingTransform(); + oct.setTransformInputData(schema + "." + "MINING_DATA_BUILD_V"); + oct.setTransformOutputData(schema + "." + xformResult); + + // Specify the list of excluded attributes + String[] excludedList = new String[]{ + "CUST_ID", "CUST_GENDER" + }; + oct.setExcludeColumnList(excludedList); + + // Specify the type of clipping: trim of winsorize ( default is trimming). + oct.setClippingType(clippingType); + + // Specify the tail fraction as 3% of values on both ends + oct.setTailFraction(0.03); + + ArrayList xformList = new ArrayList(); + xformList.add(oct); + //Create a transformation sequence object + OraTransformationSequence xformSeq = + m_xformFactory.createTransformationSequence( + schema + "." + "MINING_DATA_BUILD_V", // name of the input data set + xformList, //List of transformations. In this case only one type of transformation i.e., supervised binning + schema + "." + xformResult // name of the transformation result + ); + String xformSeqName = "clp_" + clippingType.name() + "_xfSeq"; + m_dmeConn.saveObject(xformSeqName, xformSeq, true); + + OraTransformationTask xformTask = m_xformTaskFactory.create( + xformSeqName, false); + executeTask(xformTask, "xfromClip_jdm"); + + displayClippingResults( schema, xformResult, "AGE", clippingType); + } + + /** + * Illustrates how to perform Min-Max Normalization. The normalization + * definition for each attribute is computed based on the min and max + * values that are computed from the data. The values for shift and scale + * are computed to be shift = min, and scale = (max - min) respectively. + * + * @throws JDMException if transformation failed + */ + public static void normalizeMinMax() throws JDMException + { + normalizeData(OraNormalizeType.min_max, "MINING_DATA_NORMALIZE_MIN_MAX"); + } + + /** + * Illustrates how to perform Z-Score Normalization. The normalization + * definition for each attribute is computed based on the values for mean + * and standard deviation that are computed from the data. The values for + * shift and scale are computed to be shift = mean, and scale = standard + * deviation respectively. + * + * @throws JDMException if transformation failed + */ + public static void normalizeZScore() throws JDMException + { + normalizeData(OraNormalizeType.z_Score, "MINING_DATA_NORMALIZE_Z_SCORE"); + } + + /** + * Illustrates how to perform data normalization + * + * @param normalizeType type of normalization to perform + * @param xformResult name of the result transformation view + * @throws JDMException if transformation failed + */ + public static void normalizeData(OraNormalizeType normalizeType, String xformResult) + throws JDMException + { + // Schema where the original data and resulting transformations reside + String schema = ( m_dmeConn.getConnectionSpec().getName() ).toUpperCase(); + + OraNormalizeTransform ont = m_xformFactory.createNormalizeTransform( + normalizeType, + new Integer(6) + ); + + // Specify the list of excluded attributes + String[] excludedList = new String[]{ + "CUST_ID", "CUST_GENDER" + }; + ont.setExcludeColumnList(excludedList); + + ArrayList xformList = new ArrayList(); + xformList.add(ont); + //Create a transformation sequence object + OraTransformationSequence xformSeq = + m_xformFactory.createTransformationSequence( + schema + "." + "MINING_DATA_BUILD_V", // name of the input data set + xformList, //List of transformations. In this case only one type of transformation i.e., supervised binning + schema + "." + xformResult // name of the transformation result + ); + String xformSeqName = "nmz_" + normalizeType.name() + "_xfSeq"; + m_dmeConn.saveObject(xformSeqName, xformSeq, true); + + OraTransformationTask xformTask = m_xformTaskFactory.create( + xformSeqName, false); + executeTask(xformTask, "xformNormalize_jdm"); + displayNormalizeResults( schema, "AGE", normalizeType, xformResult); + } + + /** + * Shows results of the normalization for selected attribute + * + * @param schema schema where result transformation view resides + * @param attribute name of the attribute which was normalized + * @param normalizeType type of normalization performed + * @param xformResult name of the result transformation view + */ + public static void displayNormalizeResults(String schema, + String attribute, + OraNormalizeType normalizeType, + String xformResult) + { + System.out.println("\nShowing results of the normalization transformation"); + System.out.println("\tNormalize type: " + + ( true == normalizeType.equals(OraNormalizeType.min_max) ? "min_max" : "z_score") ); + System.out.println("\tMinimum and maximum values for:" + attribute + + " before normalize transformation"); + + String sqlQuery = MessageFormat.format( + "SELECT MIN ({0}) MIN_VALUE, MAX ({0}) MAX_VALUE FROM ({1})", + new String[]{ "\""+attribute+"\"", + schema + "." + "MINING_DATA_BUILD_V"} + ); + getMinMax(sqlQuery); + + System.out.println("\tMinimum and maximum values for:" + attribute + + " after normalize transformation"); + sqlQuery = MessageFormat.format( + "SELECT MIN ({0}) MIN_VALUE, MAX ({0}) MAX_VALUE FROM ({1})", + new String[]{ "\""+attribute+"\"", + schema + "." + xformResult} + ); + getMinMax(sqlQuery); + } + + private static void showBinDefinitionTableContents(String tableName, String tableType) + { + //Bin definition tables have 3 columns + java.sql.Connection dbConn = ((OraConnection)m_dmeConn).getDatabaseConnection(); + String sql = "SELECT * FROM " + tableName; + + try{ + Vector results = OraSQLUtils.execSqlQuery(dbConn, sql, null ); + System.out.println("The contents of the " + tableType + " bin definition table."); + System.out.println("\n\tCOL\t\tVAL\t\tBIN"); + for ( int row = 0 ; row < results.size(); row++ ) { + StringBuffer sb = new StringBuffer("\t"); + Object element = results.elementAt(row); + if ( element == null ) + throw new Exception("Failure reading " + tableType + + " table. Reason: data is null"); + if ( false == element instanceof Object[] ) + throw new Exception("Failure reading " + tableType + + " table. Wrong data format."); + Object[] singleRow = (Object[])element; + for ( int col = 0 ; col < singleRow.length; col++ ) { + if ( singleRow[col] != null && singleRow[col] instanceof BigDecimal ) + sb.append( m_df.format(singleRow[col]) + "\t\t"); + else + sb.append( (singleRow[col] != null ? singleRow[col].toString() : "") + + "\t\t"); + } + System.out.println(sb.toString()); + } + } + catch(Exception e){ + System.out.println("Failed to display the contents of the table: " + + tableName + ". Reason: "); + } + } + + private static OraAttributeBins[] incrementArray(OraAttributeBins[] srcArray, + OraAttributeBins[] newArray) + { + if ( newArray == null ) + return srcArray; + + // if final array has not been created yet, check + // wheather new array contains data + if ( srcArray == null ) { + if (newArray == null) + return null; + + // if the new array has data, allocate a new array, + // copies the newArray into the resultArray and returns resultArray + OraAttributeBins[] resultArray = new OraAttributeBins[newArray.length]; + System.arraycopy(newArray, 0, resultArray, 0, newArray.length); + return resultArray; + } + + //srcArray already has some data + OraAttributeBins[] resultArray = new OraAttributeBins[srcArray.length + + newArray.length]; + // copy original data into the result array + System.arraycopy(srcArray, 0, resultArray, 0, srcArray.length); + // copy the new data into the result array + System.arraycopy(newArray, 0, resultArray, srcArray.length, newArray.length); + return resultArray; + } +} diff --git a/epgdemo.sql b/epgdemo.sql new file mode 100644 index 0000000..9cb45a2 --- /dev/null +++ b/epgdemo.sql @@ -0,0 +1,80 @@ +Rem +Rem $Header: epgdemo.sql 02-nov-2006.11:39:35 rpang Exp $ +Rem +Rem epgdemo.sql +Rem +Rem Copyright (c) 2006, Oracle. All rights reserved. +Rem +Rem NAME +Rem epgdemo.sql - Demo program for the embedded PL/SQL gateway +Rem +Rem DESCRIPTION +Rem This is a sample program to demonstrate the usage of the embedded +Rem PL/SQL gateway. +Rem +Rem NOTES +Rem This demo requires Oracle XML DB installed and the demo account SCOTT. +Rem +Rem To execute this demo, you need to start the XML DB HTTP listener and +Rem to unlock the database account "anonymous". +Rem +Rem > sqlplus system/ +Rem +Rem SQL> Rem Start XML DB HTTP listener: +Rem SQL> exec dbms_xdb.setHttpPort(8080); +Rem +Rem SQL> Rem Unlock the database account "anonymous": +Rem SQL> alter user anonymous account unlock; +Rem +Rem Then, execute this demo script to set up the database access +Rem descriptor (DAD) and to create the demo program in the account SCOTT: +Rem +Rem SQL> @epgdemo.sql +Rem +Rem Then, open the URL http://:8080/demo/plsql/hello +Rem +Rem *** Security notes *** +Rem This demo requires the database account "anonymous" to be unlocked +Rem so that the demo program "hello" can be accessed from the browser +Rem without authentication. You should ensure that all XML DB repository +Rem resources and servlets which are not intended for unauthenticated +Rem access are properly secured. Please refer to the XML DB documentation +Rem on protecting its repository resources and servlets. +Rem ********************** +Rem +Rem MODIFIED (MM/DD/YY) +Rem rpang 11/02/06 - Created +Rem + +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 + +Rem Set up the database access descriptor (DAD) as SYSTEM + +begin + dbms_epg.create_dad('DemoDAD', '/demo/plsql/*'); + dbms_epg.set_dad_attribute('DemoDAD', 'database-username', 'SCOTT'); +end; +/ + +Rem Create the demo program as SCOTT + +connect scott/tiger + +begin + /* Authorize DemoDAD to use my schema and my privileges */ + dbms_epg.authorize_dad('DemoDAD'); +end; +/ + +create or replace procedure hello is +begin + /* Generate "Hello, World!" in HTML */ + htp.print('Hello, World!'); +end; +/ diff --git a/exfdemo.sql b/exfdemo.sql new file mode 100644 index 0000000..6e8bfc9 --- /dev/null +++ b/exfdemo.sql @@ -0,0 +1,718 @@ +Rem +Rem $Header: exfdemo.sql 16-sep-2003.10:14:13 ayalaman Exp $ +Rem +Rem exfdemo.sql +Rem +Rem Copyright (c) 2003, Oracle Corporation. All rights reserved. +Rem +Rem NAME +Rem exfdemo.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ayalaman 09/16/03 - ayalaman_quoted_names_bug +Rem ayalaman 08/27/03 - Created +Rem + +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 + +connect scott/tiger +set linesize 200; +column associated_table format a12; +column attribute format a15; +column attribute_exp format a13; +column attribute_set_name format a8; +column data_type format a12; +column expr_table format a10; +column expr_column format a10; +column expset_table format a10; +column expset_column format a10; +column index_name format a18; +column interest format a40; +column operator_list format a25; +column subexpression format a12; +column udf_name format a20; +column xmltype_attr format a10; + +/***************************************************************** + The tests in this file are organized as follows: + 1. Basic Functionality + 1.1 Creation of the attribute set + 1.2 Adding user-defined functions to the attribute set + 1.3 Creation of an Expression datatype column in a user table + 1.4 Multiple forms of EVALUATE operator + 2. Expression Filter Index (EE) + 2.1 Using Default index parameters + 2.2 Using Exact index parameters + 2.3 Using Expression Statistics + 3. EVALUATE operator used in joins + 3.1 Batch evaluation + 3.2 Active application using trigger + 4. Expressions defined for table data + 5. XPath predicates in expressions + 5.1 Use of XMLType attribute + 5.2 Indexing XPath expressions + 6. DML With EVALUATE Operator +******************************************************************/ +-------------------------- +--- 1. Basic functionality +-------------------------- + +-- 1.1 Creation of attribute set + +--- create the attribute set incrementally +BEGIN + dbms_expfil.create_attribute_set(attr_set => 'Car4Sale'); + + dbms_expfil.add_elementary_attribute (attr_set => 'Car4Sale', + attr_name => 'Model', + attr_type => 'VARCHAR2(20)'); + + dbms_expfil.add_elementary_attribute (attr_set => 'Car4Sale', + attr_name => 'Year', + attr_type => 'NUMBER'); + + dbms_expfil.add_elementary_attribute (attr_set => 'Car4Sale', + attr_name => 'Price', + attr_type => 'NUMBER'); + + dbms_expfil.add_elementary_attribute (attr_set => 'Car4Sale', + attr_name => 'Mileage', + attr_type => 'NUMBER'); +END; +/ + +select attribute_set_name, attribute, data_type + from user_expfil_attributes; + +exec dbms_expfil.drop_attribute_set (attr_set => 'Car4Sale'); + +--- create the same attribute set using an abstract type +CREATE OR REPLACE TYPE Car4Sale AS OBJECT + (Model VARCHAR2(20), + Year NUMBER, + Price NUMBER, + Mileage NUMBER); +/ + +BEGIN + dbms_expfil.create_attribute_set (attr_set => 'Car4Sale', + from_type => 'YES'); +END; +/ + +select attribute_set_name, attribute, data_type + from user_expfil_attributes; + +-- 1.2 Adding user-defined functions to the attribute set + +--- create the functions required in the expressions +CREATE or REPLACE FUNCTION HorsePower(Model VARCHAR2, Year VARCHAR2) + return NUMBER is +BEGIN + return 200; +END HorsePower; +/ + +CREATE or REPLACE FUNCTION CrashTestRating(Model VARCHAR2, Year VARCHAR2) + return NUMBER is +BEGIN + return 5; +END CrashTestRating; +/ + +--- add the functions to the attribute set so that they can be used +--- in the corresponding expressions +BEGIN + dbms_expfil.add_functions (attr_set => 'Car4Sale', + funcs_name => 'HorsePower'); + dbms_expfil.add_functions (attr_set => 'Car4Sale', + funcs_name => 'CrashTestRating'); +END; +/ + +select attribute_set_name, udf_name, object_type + from user_expfil_aset_functions; + +-- 1.3 Creation of an Expression datatype column in a user table + +--- create a table with a VARCHAR2 column to hold expressions -- +CREATE TABLE Consumer (CId NUMBER, + Zipcode NUMBER, + Phone VARCHAR2(12), + Interest VARCHAR2(200)); + +--- assign the attribute set to the VARCHAR2 column to convert it -- +--- into an expression column -- +BEGIN + dbms_expfil.assign_attribute_set (attr_set => 'Car4Sale', + expr_tab => 'Consumer', + expr_col => 'Interest'); +END; +/ + +select expr_table, expr_column, attribute_set + from user_expfil_expression_sets; + +--- insert data (with expressions) into the Consumer table -- +INSERT INTO Consumer VALUES (1, 32611, '917 768 4633', + 'Model=''Taurus'' and Price < 15000 and Mileage < 25000'); +INSERT INTO Consumer VALUES (2, 03060, '603 983 3464', + 'Model=''Mustang'' and Year > 1999 and Price < 20000'); +INSERT INTO Consumer VALUES (3, 03060, '603 484 7013', + 'HorsePower(Model, Year) > 200 and Price < 20000'); + + +-- 1.4 Multiple forms of EVALUATE operator to evaluate the expressions +--- string formatted data item +SELECT * FROM Consumer + WHERE EVALUATE (Consumer.Interest, 'Model =>''Mustang'', + Year => 2000, + Price => 18000, + Mileage => 22000') = 1; + +--- data item as an Anydata instance +SELECT * FROM Consumer + WHERE EVALUATE (Consumer.Interest, + AnyData.convertObject(Car4Sale('Mustang', + 2000, + 18000, + 22000))) = 1; + +--- string formatted data item generated by STATIC getVarchar API +SELECT * FROM Consumer + WHERE EVALUATE (Consumer.Interest, + Car4Sale.getVarchar('Mustang', + 2000, + 18000, + 22000)) = 1; + +--- string formatted data item generated by MEMBER getVarchar API +SELECT * FROM Consumer + WHERE EVALUATE (Consumer.Interest, + Car4Sale('Mustang', + 2000, + 18000, + 22000).getVarchar()) = 1; + +--- applying additional predicates in the same query +SELECT * FROM Consumer + WHERE Zipcode between 03060 and 03070 and + EVALUATE (Consumer.Interest, + Car4Sale.getVarchar('Mustang', + 2000, + 18000, + 22000)) = 1 + +----------------------------------------------------- +--- 2. Expression Filter indexes on Expression column +----------------------------------------------------- + +-- 2.1 Default parameters associated with the attribute set + +--- assign default index parameters to the attribute set +BEGIN + dbms_expfil.default_index_parameters ( + attr_set => 'Car4Sale', + attr_list => exf$attribute_list ( + exf$attribute (attr_name => 'Model', --- LHS for predicate group + attr_oper => exf$indexoper('='), + attr_indexed => 'TRUE'), --- indexed predicate group + exf$attribute (attr_name => 'Price', + attr_oper => exf$indexoper('all'), + attr_indexed => 'TRUE'), + exf$attribute (attr_name => 'HorsePower(Model, Year)', + attr_oper => exf$indexoper('=','<','>','>=','<='), + attr_indexed => 'FALSE') --- stored predicate group + )); +END; +/ + +select attribute_set_name, attribute, indexed, operator_list + from user_expfil_def_index_params; + +--- create the index using default parameters +CREATE INDEX InterestIndex ON Consumer (Interest) + INDEXTYPE IS EXFSYS.EXPFILTER; + +select index_name, subexpression, indexed, operator_list + from user_expfil_predtab_attributes; + +DROP INDEX InterestIndex; + +--- extend the default parameters at the time of index creation +CREATE INDEX InterestIndex ON Consumer (Interest) + INDEXTYPE IS EXFSYS.EXPFILTER PARAMETERS ( + 'ADD TO DEFAULTS STOREATTRS (CrashTestRating(Model, Year))'); + +select index_name, subexpression, indexed, operator_list + from user_expfil_predtab_attributes; + +DROP INDEX InterestIndex; + +-- 2.2 Exact index paremeters for each expression column + +--- associate the index parameters with the expression column by +--- deriving from defaults and fine tuning them +BEGIN + -- derive index parameters from defaults + dbms_expfil.index_parameters ( + expr_tab => 'Consumer', + expr_col => 'Interest', + attr_list => null, + operation => 'DEFAULT'); + + -- fine-tune the parameters by adding another stored attribute + dbms_expfil.index_parameters( + expr_tab => 'Consumer', + expr_col => 'Interest', + attr_list => exf$attribute_list ( + exf$attribute ( + attr_name => 'CrashTestRating(Model, Year)', + attr_oper => exf$indexoper('all'), + attr_indexed => 'FALSE')), + operation => 'ADD'); +END; +/ + +select expset_table, expset_column, attribute, indexed, operator_list + from user_expfil_index_params; + +-- create the index; uses the parameters associated with expression column +CREATE INDEX InterestIndex ON Consumer (Interest) + INDEXTYPE IS EXFSYS.EXPFILTER; + +select index_name, subexpression, indexed, operator_list + from user_expfil_predtab_attributes; + +DROP INDEX InterestIndex; + +-- 2.3 Using Expression Statistics for the expression column + +--- collect the expression set statistics -- +BEGIN + dbms_expfil.get_exprset_stats (expr_tab => 'Consumer', + expr_col => 'Interest'); +END; +/ + +select expr_table, expr_column, attribute_exp, pct_occurrence, + pct_eq_oper + from user_expfil_exprset_stats order by pct_occurrence, attribute_exp desc; + +--- clear the exact parameters so that we can use the statistics +BEGIN + -- derive index parameters from defaults + dbms_expfil.index_parameters ( + expr_tab => 'Consumer', + expr_col => 'Interest', + attr_list => null, + operation => 'CLEAR'); +END; +/ + +--- create the index using the statistics --- +CREATE INDEX InterestIndex ON Consumer (Interest) + INDEXTYPE IS EXFSYS.EXPFILTER PARAMETERS ( + 'STOREATTRS TOP 4 INDEXATTRS TOP 2'); + +select index_name, subexpression, indexed, operator_list + from user_expfil_predtab_attributes; + +-------------------------------------- +--- 3. EVALUATE Operator used in joins +-------------------------------------- + +--- 3.1 Batch evaluation of expression using joins + +--- Create a table to store information about cars --- +CREATE TABLE CarInventory OF Car4Sale; + +INSERT INTO CarInventory VALUES ('Mustang',2000, 18000,22000); +INSERT INTO CarInventory VALUES ('Mustang',2000, 18000,22000); +INSERT INTO CarInventory VALUES ('Taurus',1997, 14000,24500); + +--- Join the CarInventory with the Consumer table -- +SELECT Consumer.CId, Consumer.Interest, Car.Model + FROM Consumer, CarInventory Car + WHERE EVALUATE (Consumer.Interest, Car.getVarchar()) = 1; + +DROP TABLE CarInventory; + +--- A table not relying on the Car4Sale object type -- +CREATE TABLE inventory (Model VARCHAR2(20), + Year NUMBER, + Price NUMBER, + Mileage NUMBER); + +INSERT INTO Inventory VALUES ('Mustang',2000, 18000, 22000); +INSERT INTO Inventory VALUES ('Mustang',2000, 18000, 22000); +INSERT INTO Inventory VALUES ('Taurus',1997, 14000, 24500); + +--- simple join -- +SELECT Consumer.CId, Consumer.Interest, Inventory.Model + FROM Consumer, Inventory + WHERE EVALUATE (Consumer.Interest, + Car4Sale.getVarchar(Inventory.Model, + Inventory.Year, + Inventory.Price, + Inventory.Mileage)) = 1; + + +--- demand analysis for the cars in the inventory +SELECT DISTINCT Inventory.Model, count(*) as Demand + FROM Consumer, Inventory + WHERE EVALUATE (Consumer.Interest, + Car4Sale.getVarchar(Inventory.Model, + Inventory.Year, + Inventory.Price, + Inventory.Mileage)) = 1 + GROUP BY Inventory.Model + ORDER BY Demand DESC; + +truncate table Inventory; + +-- 3.2 Active application using trigger + +--- create a trigger on the inventory table to track new data +CREATE TRIGGER activechk AFTER insert OR update ON Inventory + FOR EACH ROW +DECLARE + cursor c1 (ditem VARCHAR2) is + SELECT CId, Phone FROM Consumer WHERE EVALUATE (Interest, ditem) = 1; + ditem VARCHAR2(200); +BEGIN + ditem := Car4Sale.getVarchar(:new.Model, :new.Year, :new.Price, :new.Mileage); + for cur in c1(ditem) loop + dbms_output.put_line(' For Model '||:new.Model||' Call '||cur.CId|| + ' @ '||cur.Phone); + end loop; +END; +/ + +set serveroutput on; +--- insert data into the inventory table +INSERT INTO Inventory VALUES ('Mustang',2000, 18000,22000); +INSERT INTO Inventory VALUES ('Mustang',2000, 18000,22000); +INSERT INTO Inventory VALUES ('Taurus',1997, 14000, 24500); + +set serveroutput off; + +drop table Inventory; +drop table Consumer; +exec dbms_expfil.drop_attribute_set (attr_set => 'Car4Sale'); +drop type Car4Sale; +drop function HorsePower; +drop function CrashTestRating; + +---------------------------------------------------------------- +--- 4. Expressions defined for table data (use of table aliases) +---------------------------------------------------------------- + +--- create an attribute set with two table alias attributes referring +--- to SCOTT schema's EMP and DEPT tables. + +BEGIN + dbms_expfil.create_attribute_set('hrdb'); + -- add elementary attributes to the Attribute Set -- + dbms_expfil.add_elementary_attribute('hrdb', 'hrmgr', 'VARCHAR2(20)'); + + -- define elementary attributes of EXF$TABLE_ALIAS type -- + dbms_expfil.add_elementary_attribute('hrdb', 'emp', + exf$table_alias('scott.emp')); + dbms_expfil.add_elementary_attribute('hrdb', 'dept', + exf$table_alias('scott.dept')); +END; +/ + +select attribute_set_name, attribute, data_type, associated_table + from user_expfil_attributes; + +--- create an expression column in a user table and configure it with +--- HEDB attribute set. +CREATE TABLE HRInterest (SubId number, Interest VARCHAR2(100)); + +BEGIN + dbms_expfil.assign_attribute_set('hrdb', 'HRInterest', 'Interest'); +END; +/ + +--- insert expressions referring to table data -- +INSERT INTO HRInterest VALUES (1, + 'hrmgr=''Greg'' and emp.job=''SALESMAN'' and emp.deptno = dept.deptno + and dept.loc = ''CHICAGO'''); +INSERT INTO HRInterest VALUES (2, + 'emp.job=''MANAGER'' and emp.sal < 2500'); + +--- create index for the expression column -- +CREATE INDEX HRIndex ON HRInterest (Interest) + INDEXTYPE IS EXFSYS.EXPFILTER PARAMETERS ( + 'STOREATTRS (emp.job, dept.loc, hrmgr) INDEXATTRS (emp.job, hrmgr)'); + +--- assign values for table alias attributes through joins -- +SELECT empno, job, sal, loc, SubId, Interest + FROM emp, dept, HRInterest + WHERE emp.deptno = dept.deptno and + EVALUATE(Interest, + hrdb.getVarchar('Greg',emp.rowid,dept.rowid)) = 1; + +SELECT empno, job, sal, loc, SubId, Interest + FROM emp, dept, HRInterest + WHERE emp.deptno = dept.deptno and emp.sal > 1400 and + EVALUATE(Interest, + hrdb.getVarchar('Greg',emp.rowid,dept.rowid)) = 1; + +drop table HRInterest; +exec dbms_expfil.drop_attribute_set('hrdb'); + +-------------------------------------- +--- 5. XPath predicates in expressions +-------------------------------------- + +--- 5.1 SYS.XMLType attribute in the attribute set +CREATE OR REPLACE TYPE Car4Sale AS OBJECT + (Model VARCHAR2(20), + Year NUMBER, + Price NUMBER, + Mileage NUMBER, + Details sys.XMLType); +/ + +BEGIN + dbms_expfil.create_attribute_set (attr_set => 'Car4Sale', + from_type => 'YES'); +END; +/ + +--- create expression column in a user table +CREATE TABLE Consumer (CId NUMBER, + Zipcode NUMBER, + Phone VARCHAR2(12), + Interest VARCHAR2(200)); + +BEGIN + dbms_expfil.assign_attribute_set (attr_set => 'Car4Sale', + expr_tab => 'Consumer', + expr_col => 'Interest'); +END; +/ + +--- insert expression with XPath predicates in the table +INSERT INTO Consumer VALUES (1, 32611, '917 768 4633', +'Model=''Taurus'' and Price < 15000 and Mileage < 25000 and +extract(Details, ''//stereo[@make="Koss"]'') is not null'); + +INSERT INTO Consumer VALUES (2, 03060, '603 983 3464', +'Model=''Mustang'' and Year > 1999 and Price < 20000 and +extract(Details, ''//stereo[@make="Koss" and /*/*/GPS/memory[text()="64MB"]]'') is not null'); + +INSERT INTO Consumer VALUES (3, 03060, '603 484 7013', +'Model=''Taurus'' and Price < 15000 and Mileage < 25000 and +existsNode(Details, ''//stereo[@make="Koss"]'') = 1'); + +--- evaluate the expressions for a data item -- +SELECT * FROM Consumer + WHERE EVALUATE (Consumer.Interest, + 'Model => ''Mustang'', + Year => 2000, + Price => 18000, + Mileage => 22000, + Details => + sys.XMLType(''
+ White + + CD + + 1FT + 64MB + + +
'')') = 1; + +SELECT * FROM Consumer + WHERE EVALUATE (Consumer.Interest, + AnyData.convertObject( + Car4Sale('Mustang', + 2000, + 18000, + 22000, + '
+ White + + CD + + 1FT + 64MB + + +
'))) = 1; + +--- 5.2 Indexing XPath expressions + +--- default index parameters associated with the attribute set +BEGIN + --- parameters for non-XMLType attributes + dbms_expfil.default_index_parameters( + attr_set => 'Car4Sale', + attr_list => exf$attribute_list ( + exf$attribute (attr_name => 'Model', + attr_oper => exf$indexoper('='), + attr_indexed => 'TRUE'), + exf$attribute (attr_name => 'Price', + attr_oper => exf$indexoper('all'), + attr_indexed => 'FALSE') + )); + + --- parameters for XMLType attributes + dbms_expfil.default_xpindex_parameters ( + attr_set => 'Car4Sale', + xmlt_attr => 'Details', --- XMLType Attribute + xptag_list => --- Tag list + exf$xpath_tags( + exf$xpath_tag(tag_name => 'stereo@make', --- XML Attribute + tag_indexed => 'TRUE', + tag_type => 'VARCHAR(15)'), --- value filter + exf$xpath_tag(tag_name => 'stereo', --- XML Element + tag_indexed => 'FALSE', + tag_type => null), --- positional filter + exf$xpath_tag(tag_name => 'memory', --- XML Element + tag_indexed => 'TRUE', + tag_type => 'VARCHAR(10)') --- value filter + )); +END; +/ + +select attribute_set_name, attribute, indexed, operator_list, xmltype_attr + from user_expfil_def_index_params; + +--- create the index using defaults -- +CREATE INDEX InterestIndex ON Consumer (Interest) + INDEXTYPE IS EXFSYS.EXPFILTER; + +select index_name, subexpression, indexed, operator_list, xptag_type, + xpfilter_type +from user_expfil_predtab_attributes; + +DROP INDEX InterestIndex; + +--- index paramters assigned to the expression column -- +BEGIN + -- Derive the index parameters from defaults -- + dbms_expfil.index_parameters ( + expr_tab => 'Consumer', + expr_col => 'Interest', + attr_list => null, + operation => 'DEFAULT'); + + -- fine-tune the XPath index parameters by adding another Tag -- + dbms_expfil.xpindex_parameters ( + expr_tab => 'Consumer', + expr_col => 'Interest', + xmlt_attr => 'Details', + xptag_list => + exf$xpath_tags ( + exf$xpath_tag(tag_name => 'GPS', + tag_indexed => 'TRUE', + tag_type => null)), + operation => 'ADD'); +END; +/ + +select expset_table, expset_column, attribute, indexed, operator_list, + xmltype_attr + from user_expfil_index_params; + +--- create the index using the parameters associated with the expr col. +CREATE INDEX InterestIndex ON Consumer (Interest) + INDEXTYPE IS EXFSYS.EXPFILTER; + +select index_name, subexpression, indexed, operator_list, xptag_type, + xpfilter_type +from user_expfil_predtab_attributes; + +SELECT * FROM Consumer + WHERE EVALUATE (Consumer.Interest, + 'Model => ''Mustang'', + Year => 2000, + Price => 18000, + Mileage => 22000, + Details => + sys.XMLType(''
+ White + + CD + + 1FT + 64MB + + +
'')') = 1; + +drop table Consumer; +exec dbms_expfil.drop_attribute_set('Car4Sale'); +drop type Car4Sale; + +--- 6. DML with EVALUATE Operator + +--- create the attribute set +CREATE OR REPLACE TYPE ITTicket AS OBJECT ( + Priority NUMBER, + Environment VARCHAR2(10), + Organization VARCHAR2(10)); +/ + +BEGIN + dbms_expfil.create_attribute_set(attr_set => 'ITTicket', + from_type => 'Yes'); +END; +/ + +--- create the table storing expressions +CREATE TABLE ITResource (RId NUMBER, + Duties VARCHAR2(100)); + +BEGIN +dbms_expfil.assign_attribute_set(attr_set => 'ITTicket', + expr_tab => 'ITResource', + expr_col => 'Duties'); +END; +/ + +INSERT INTO ITResource (RId, Duties) VALUES + (1, 'Priority <= 2 and Environment = ''NT'' and Organization = ''Research'''); + +INSERT INTO ITResource (RId, Duties) VALUES + (2, 'Priority = 1 and (Environment = ''UNIX'' or Environment = ''LINUX'') + and Organization = ''APPS'''); + +--- create the table for data items +CREATE TABLE ITProblem (PId NUMBER, + Description ITTicket, + AssignedTo NUMBER); + +insert into ITProblem values (1, ITTicket(2,'NT','Research'), NULL); +insert into ITProblem values (2, ITTicket(1,'UNIX','APPS'), NULL); + +--- Update the ITProblem to table to assign the tickets to appropriate +--- ITResource +UPDATE ITProblem p SET AssignedTo = + (SELECT RId FROM ITResource r + WHERE EVALUATE(r.Duties, p.Description.getVarchar()) = 1 and + rownum < 2) +WHERE AssignedTo is NULL; + +drop table itproblem; +drop table itresource; +exec dbms_expfil.drop_attribute_set('itticket'); +drop type itticket; + diff --git a/extdemo0.sql b/extdemo0.sql new file mode 100644 index 0000000..ed51bcc --- /dev/null +++ b/extdemo0.sql @@ -0,0 +1,34 @@ +rem +rem $Header: extdemo0.sql 14-jul-99.13:55:39 mjaeger Exp $ +rem +rem extdemo0.sql +rem +rem Copyright (c) 1998, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem extdemo0.sql - explain plan script +rem +rem DESCRIPTION +rem This file contains the SQL statements to print +rem the output of explain plan. +rem +rem NOTES +rem +rem +rem MODIFIED (MM/DD/YY) +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem hdnguyen 07/26/99 - sqlplus conversion +rem rmurthy 09/25/98 - minor changes +rem rmurthy 07/15/98 - extensibility - explain plan script +rem rmurthy 07/15/98 - Created + +SELECT operation operations, + decode(options, 'BY INDEX ROWID', 'BY ROWID', + 'BY USER ROWID', 'BY ROWID', + options) options, + object_name +FROM plan_table +ORDER BY id; + +TRUNCATE TABLE plan_table; + diff --git a/extdemo1.sql b/extdemo1.sql new file mode 100644 index 0000000..f67538f --- /dev/null +++ b/extdemo1.sql @@ -0,0 +1,2016 @@ +rem +rem $Header: extdemo1.sql 16-oct-2002.11:53:50 ayoaz Exp $ +rem +rem extdemo1.sql +rem +rem Copyright (c) 1998, 2002, Oracle Corporation. All rights reserved. +rem +rem NAME +rem extdemo1.sql - A power company example +rem +rem DESCRIPTION +rem This is an example of a data cartridge which uses +rem object types and the extensible indexing framework. +rem +rem NOTES +rem +rem MODIFIED (MM/DD/YY) +rem ayoaz 10/16/02 - add cardinality arg to ODCIArgDesc +rem ddas 03/12/01 - use 9i interfaces +rem rmurthy 03/09/01 - bug 1676437 - change call to extdemo0 +rem hdnguyen 02/15/01 - added order by to selects +rem ddas 02/10/01 - modify table data and cost functions +rem ddas 05/25/00 - 8.2 interface change +rem rmurthy 01/12/00 - add path name while calling utlxplan +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem hdnguyen 07/26/99 - sqlplus conversion +rem ddas 06/25/99 - extend example to use extensible optimizer +rem rmurthy 09/25/98 - add explain plans +rem rmurthy 07/15/98 - extensibility demo +rem rmurthy 07/15/98 - Created + +SET ECHO ON +CONNECT sys/knl_test7 AS sysdba; + +-- Clean up from any previous running of this procedure. +DROP USER PowerCartUser CASCADE; + +-- Create the user for schema objects. +CREATE USER PowerCartUser IDENTIFIED BY PowerCartUser; + +------------------------------------------------------------------- +-- INITIAL SET-UP +------------------------------------------------------------------- +-- Grant privileges -- +GRANT connect, resource to PowerCartUser; +GRANT create table to PowerCartUser; + +------------------------------------------------------------------- +-- CREATE POWERTYPE -- +------------------------------------------------------------------- +CONNECT PowerCartUser/PowerCartUser +set echo off +@'?/rdbms/admin/utlxplan.sql' +set echo on + +-- Create table for user-defined statistics +CREATE TABLE PowerCartUserStats ( + -- Table for which statistics are collected + tab VARCHAR2(30), + -- Column for which statistics are collected + col VARCHAR2(30), + -- Cell position + cpos NUMBER, + -- Minimum power demand for the given cell + lo NUMBER, + -- Maximum power demand for the given cell + hi NUMBER, + -- Number of (non-null) power demands for the given cell + nrows NUMBER +); + +-- Type used in the definition of PowerDemand_Typ + +CREATE OR REPLACE TYPE PowerGrid_Typ as VARRAY(100) of NUMBER; +/ +CREATE OR REPLACE TYPE NumTab_Typ as TABLE of NUMBER; +/ +-- The object type used for this example. Contains 3 +-- attributes that will be set by the 3 member procedures; +-- also a power demand grid (array) and the date/time for +-- the samplings (readings). + +CREATE OR REPLACE TYPE PowerDemand_Typ AS OBJECT ( + -- Total power demand for the grid + TotGridDemand NUMBER, + -- Call with maximum/minimum power demand for the grid + MaxCellDemand NUMBER, + MinCellDemand NUMBER, + -- Power grid: 10X10 array represented as Varray(100) + -- using previously defined PowerGrid_Typ + CellDemandValues PowerGrid_Typ, + -- Date/time for power-demand samplings: Every hour, + -- 100 power stations transmit their power demand + -- readings. + SampleTime DATE, + -- + -- Methods (Set...) for this type: + -- Total demand for the entire power grid for a + -- SampleTime: sets the value of TotGridDemand. + Member Procedure SetTotalDemand, + -- Maximum demand for the entire power grid for a + -- SampleTime: sets the value of MaxCellDemand. + Member Procedure SetMaxDemand, + -- Minimum demand for the entire power grid for a + -- SampleTime: sets the value of MinCellDemand. + Member Procedure SetMinDemand +); +/ +show errors; + +CREATE OR REPLACE TYPE BODY PowerDemand_Typ +IS + -- + -- Methods (Set...) for this type: + -- Total demand for the entire power grid for a + -- SampleTime: sets the value of TotGridDemand. + Member Procedure SetTotalDemand + IS + I BINARY_INTEGER; + Total NUMBER; + BEGIN + Total :=0; + I := CellDemandValues.FIRST; + WHILE I IS NOT NULL LOOP + Total := Total + CellDemandValues(I); + I := CellDemandValues.NEXT(I); + END LOOP; + TotGridDemand := Total; + END; + + -- Maximum demand for the entire power grid for a + -- SampleTime: sets the value of MaxCellDemand. + Member Procedure SetMaxDemand + IS + I BINARY_INTEGER; + Temp NUMBER; + BEGIN + I := CellDemandValues.FIRST; + Temp := CellDemandValues(I); + WHILE I IS NOT NULL LOOP + IF Temp < CellDemandValues(I) THEN + Temp := CellDemandValues(I); + END IF; + I := CellDemandValues.NEXT(I); + END LOOP; + MaxCellDemand := Temp; + END; + + -- Minimum demand for the entire power grid for a + -- SampleTime: sets the value of MinCellDemand. + Member Procedure SetMinDemand + IS + I BINARY_INTEGER; + Temp NUMBER; + BEGIN + I := CellDemandValues.FIRST; + Temp := CellDemandValues(I); + WHILE I IS NOT NULL LOOP + IF Temp > CellDemandValues(I) THEN + Temp := CellDemandValues(I); + END IF; + I := CellDemandValues.NEXT(I); + END LOOP; + MinCellDemand := Temp; + END; +END; +/ +show errors; + +------------------------------------------------------------------- +-- CREATE FUNCTIONS AND OPERATORS +------------------------------------------------------------------- + +CREATE FUNCTION Power_EqualsSpecific_Func( + object PowerDemand_Typ, cell NUMBER, value NUMBER) +RETURN NUMBER AS + BEGIN + IF cell <= object.CellDemandValues.LAST + THEN + IF (object.CellDemandValues(cell) = value) THEN + RETURN 1; + ELSE + RETURN 0; + END IF; + ELSE + RETURN NULL; + END IF; + END; +/ + +CREATE FUNCTION Power_GreaterThanSpecific_Func( + object PowerDemand_Typ, cell NUMBER, value NUMBER) +RETURN NUMBER AS + BEGIN + IF cell <= object.CellDemandValues.LAST + THEN + IF (object.CellDemandValues(cell) > value) THEN + RETURN 1; + ELSE + RETURN 0; + END IF; + ELSE + RETURN NULL; + END IF; + END; +/ + +CREATE FUNCTION Power_LessThanSpecific_Func( + object PowerDemand_Typ, cell NUMBER, value NUMBER) +RETURN NUMBER AS + BEGIN + IF cell <= object.CellDemandValues.LAST + THEN + IF (object.CellDemandValues(cell) < value) THEN + RETURN 1; + ELSE + RETURN 0; + END IF; + ELSE + RETURN NULL; + END IF; + END; +/ + +CREATE FUNCTION Power_EqualsAny_Func( + object PowerDemand_Typ, value NUMBER) +RETURN NUMBER AS + idx NUMBER; + BEGIN + FOR idx IN object.CellDemandValues.FIRST..object.CellDemandValues.LAST LOOP + IF (object.CellDemandValues(idx) = value) THEN + RETURN 1; + END IF; + END LOOP; + + RETURN 0; + END; +/ + +CREATE FUNCTION Power_GreaterThanAny_Func( + object PowerDemand_Typ, value NUMBER) +RETURN NUMBER AS + idx NUMBER; + BEGIN + FOR idx IN object.CellDemandValues.FIRST..object.CellDemandValues.LAST LOOP + IF (object.CellDemandValues(idx) > value) THEN + RETURN 1; + END IF; + END LOOP; + + RETURN 0; + END; +/ + +CREATE FUNCTION Power_LessThanAny_Func( + object PowerDemand_Typ, value NUMBER) +RETURN NUMBER AS + idx NUMBER; + BEGIN + FOR idx IN object.CellDemandValues.FIRST..object.CellDemandValues.LAST LOOP + IF (object.CellDemandValues(idx) < value) THEN + RETURN 1; + END IF; + END LOOP; + + RETURN 0; + END; +/ + + +CREATE OPERATOR Power_Equals BINDING(PowerDemand_Typ, NUMBER, NUMBER) + RETURN NUMBER USING Power_EqualsSpecific_Func; +CREATE OPERATOR Power_GreaterThan BINDING(PowerDemand_Typ, NUMBER, NUMBER) + RETURN NUMBER USING Power_GreaterThanSpecific_Func; +CREATE OPERATOR Power_LessThan BINDING(PowerDemand_Typ, NUMBER, NUMBER) + RETURN NUMBER USING Power_LessThanSpecific_Func; + +CREATE OPERATOR Power_EqualsAny BINDING(PowerDemand_Typ, NUMBER) + RETURN NUMBER USING Power_EqualsAny_Func; +CREATE OPERATOR Power_GreaterThanAny BINDING(PowerDemand_Typ, NUMBER) + RETURN NUMBER USING Power_GreaterThanAny_Func; +CREATE OPERATOR Power_LessThanAny BINDING(PowerDemand_Typ, NUMBER) + RETURN NUMBER USING Power_LessThanAny_Func; + +------------------------------------------------------------------- +-- Create package used by ODCIIndexGetMetadata +------------------------------------------------------------------- +CREATE OR REPLACE PACKAGE power_pkg AS + FUNCTION getversion(idxschema IN VARCHAR2, idxname IN VARCHAR2, + newblock OUT PLS_INTEGER) RETURN VARCHAR2; + PROCEDURE checkversion (version IN VARCHAR2); +END power_pkg; +/ +SHOW ERRORS; + +CREATE OR REPLACE PACKAGE BODY power_pkg AS + +-- iterate is a package level variable used to maintain state across calls +-- by export in this session. + +iterate NUMBER := 0; + +FUNCTION getversion(idxschema IN VARCHAR2, idxname IN VARCHAR2, + newblock OUT PLS_INTEGER) RETURN VARCHAR2 IS + +BEGIN + +-- We are generating only one PL/SQL block consisting of one line of code. + newblock := 1; + + IF iterate = 0 + THEN +-- Increment iterate so we'll know we're done next time we're called. + iterate := iterate + 1; + +-- Return a string that calls checkversion with a version 'V1.0' +-- Note that export adds the surrounding BEGIN/END pair to form the anon. +-- block... we don't have to. + + RETURN 'power_pkg.checkversion(''V1.0'');'; + ELSE +-- reset iterate for next index + iterate := 0; +-- Return a 0-length string; we won't be called again for this index. + RETURN ''; + END IF; +END getversion; + +PROCEDURE checkversion (version IN VARCHAR2) IS + + wrong_version EXCEPTION; + +BEGIN + IF version != 'V1.0' THEN + RAISE wrong_version; + END IF; +END checkversion; + +END power_pkg; +/ +SHOW ERRORS; + +------------------------------------------------------------------- +-- CREATE INDEXTYPE IMPLEMENTATION TYPE +------------------------------------------------------------------- +CREATE OR REPLACE TYPE power_idxtype_im AS OBJECT +( + curnum NUMBER, + STATIC FUNCTION ODCIGetInterfaces(ifclist OUT sys.ODCIObjectList) + RETURN NUMBER, + STATIC FUNCTION ODCIIndexCreate (ia sys.odciindexinfo, parms VARCHAR2, + env sys.ODCIEnv) + RETURN NUMBER, + STATIC FUNCTION ODCIIndexDrop(ia sys.odciindexinfo, + env sys.ODCIEnv) RETURN NUMBER, + STATIC FUNCTION ODCIIndexStart(sctx IN OUT power_idxtype_im, + ia sys.odciindexinfo, + op sys.odciPredInfo, qi sys.ODCIQueryInfo, + strt NUMBER, stop NUMBER, + cmppos NUMBER, cmpval NUMBER, env sys.ODCIEnv) RETURN NUMBER, + STATIC FUNCTION ODCIIndexStart(sctx IN OUT power_idxtype_im, + ia sys.odciindexinfo, + op sys.odciPredInfo, qi sys.ODCIQueryInfo, + strt NUMBER, stop NUMBER, + cmpval NUMBER, env sys.ODCIEnv) RETURN NUMBER, + MEMBER FUNCTION ODCIIndexFetch(nrows NUMBER, + rids OUT sys.odciridlist, env sys.ODCIEnv) + RETURN NUMBER, + MEMBER FUNCTION ODCIIndexClose(env sys.ODCIEnv) RETURN NUMBER, + STATIC FUNCTION ODCIIndexInsert(ia sys.odciindexinfo, rid VARCHAR2, + newval PowerDemand_Typ, env sys.ODCIEnv) RETURN NUMBER, + STATIC FUNCTION ODCIIndexDelete(ia sys.odciindexinfo, rid VARCHAR2, + oldval PowerDemand_Typ, env sys.ODCIEnv) RETURN NUMBER, + STATIC FUNCTION ODCIIndexUpdate(ia sys.odciindexinfo, rid VARCHAR2, + oldval PowerDemand_Typ, newval PowerDemand_Typ, env sys.ODCIEnv) + RETURN NUMBER, + STATIC FUNCTION ODCIIndexGetMetadata(ia sys.odciindexinfo, + expversion VARCHAR2, newblock OUT PLS_INTEGER, env sys.ODCIEnv) + RETURN VARCHAR2 +); +/ +show errors; + +create or replace type body power_idxtype_im +is + STATIC FUNCTION ODCIGetInterfaces(ifclist OUT sys.ODCIObjectList) + return number is + BEGIN + ifclist := sys.ODCIObjectList(sys.ODCIObject('SYS','ODCIINDEX2')); + return ODCIConst.Success; + END ODCIGetInterfaces; + + STATIC FUNCTION ODCIIndexCreate (ia sys.odciindexinfo, + parms VARCHAR2, env sys.ODCIEnv) + RETURN NUMBER + is + i INTEGER; + r ROWID; + p NUMBER; + v NUMBER; + stmt1 VARCHAR2(1000); + stmt2 VARCHAR2(1000); + stmt3 VARCHAR2(1000); + cnum1 INTEGER; + cnum2 INTEGER; + cnum3 INTEGER; + junk NUMBER; + BEGIN + -- Construct the SQL statement. + stmt1 := 'CREATE TABLE ' || + ia.IndexSchema || '.' || ia.IndexName || '_pidx' || + '( r ROWID, cpos NUMBER, cval NUMBER)'; + + -- Dump the SQL statement. + dbms_output.put_line('ODCIIndexCreate>>>>>'); + sys.ODCIIndexInfoDump(ia); + dbms_output.put_line('ODCIIndexCreate>>>>>'||stmt1); + + -- Execute the statement. + cnum1 := dbms_sql.open_cursor; + dbms_sql.parse(cnum1, stmt1, dbms_sql.native); + junk := dbms_sql.execute(cnum1); + dbms_sql.close_cursor(cnum1); + + -- Now populate the table. + stmt2 := ' INSERT INTO '|| + ia.IndexSchema || '.' || ia.IndexName || '_pidx' || + ' SELECT :rr, ROWNUM, column_value FROM THE' || + ' (SELECT CAST (P.'|| ia.IndexCols(1).ColName || + '.CellDemandValues AS NumTab_Typ)' || + ' FROM ' || ia.IndexCols(1).TableSchema || '.' || + ia.IndexCols(1).TableName || ' P' || + ' WHERE P.ROWID = :rr)'; + + -- Execute the statement. + dbms_output.put_line('ODCIIndexCreate>>>>>'||stmt2); + + -- Parse the statement. + cnum2 := dbms_sql.open_cursor; + dbms_sql.parse(cnum2, stmt2, dbms_sql.native); + + stmt3 := 'SELECT ROWID FROM '|| + ia.IndexCols(1).TableSchema || '.' || ia.IndexCols(1).TableName; + dbms_output.put_line('ODCIIndexCreate>>>>>'||stmt3); + cnum3 := dbms_sql.open_cursor; + dbms_sql.parse(cnum3, stmt3, dbms_sql.native); + dbms_sql.define_column_rowid(cnum3, 1, r); + junk := dbms_sql.execute(cnum3); + + WHILE dbms_sql.fetch_rows(cnum3) > 0 LOOP + -- Get column values of the row. -- + dbms_sql.column_value_rowid(cnum3, 1, r); + -- Bind the row into the cursor for the next insert. -- + dbms_sql.bind_variable_rowid(cnum2, ':rr', r); + junk := dbms_sql.execute(cnum2); + END LOOP; + + dbms_sql.close_cursor(cnum2); + dbms_sql.close_cursor(cnum3); + RETURN ODCICONST.SUCCESS; + END; + + STATIC FUNCTION ODCIIndexDrop(ia sys.odciindexinfo, env sys.ODCIEnv) + RETURN NUMBER is + stmt VARCHAR2(1000); + cnum INTEGER; + junk INTEGER; + BEGIN + -- Construct the SQL statement. + stmt := 'drop table ' || ia.IndexSchema || '.' || ia.IndexName || '_pidx'; + + dbms_output.put_line('ODCIIndexDrop>>>>>'); + sys.ODCIIndexInfoDump(ia); + dbms_output.put_line('ODCIIndexDrop>>>>>'||stmt); + + -- Execute the statement. + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + + RETURN ODCICONST.SUCCESS; + END; + + -- This definition of ODCIIndexStart is for queries on a specific + -- cell. (The next definition is for queries on any cell.) + STATIC FUNCTION ODCIIndexStart(sctx IN OUT power_idxtype_im, + ia sys.odciindexinfo, + op sys.odciPredInfo, qi sys.ODCIQueryInfo, + strt NUMBER, stop NUMBER, + cmppos NUMBER, cmpval NUMBER, env sys.ODCIEnv) RETURN NUMBER is + cnum INTEGER; + rid ROWID; + nrows INTEGER; + relop VARCHAR2(2); + stmt VARCHAR2(1000); + BEGIN + dbms_output.put_line('ODCIIndexStart>>>>>'); + sys.ODCIIndexInfoDump(ia); + sys.ODCIPredInfoDump(op); + dbms_output.put_line('start key : '||strt); + dbms_output.put_line('stop key : '||stop); + dbms_output.put_line('compare position : '||cmppos); + dbms_output.put_line('compare value : '||cmpval); + + -- Take care of some error cases. + -- The only predicates in which operators can appear are + -- op() = 1 OR op() = 0 + if (strt != 1) and (strt != 0) then + raise_application_error(-20101, 'Incorrect predicate for operator'); + END if; + + if (stop != 1) and (stop != 0) then + raise_application_error(-20101, 'Incorrect predicate for operator'); + END if; + + -- Generate the SQL statement to be executed. + -- First, figure out the relational operator needed for the statement. + -- Take into account the operator name and the start and stop keys. + -- For now, the start and stop keys can both be 1 (= TRUE) or + -- both be 0 (= FALSE). + if op.ObjectName = 'POWER_EQUALS' then + if strt = 1 then + relop := '='; + else + relop := '!='; + end if; + elsif op.ObjectName = 'POWER_LESSTHAN' then + if strt = 1 then + relop := '<'; + else + relop := '>='; + end if; + elsif op.ObjectName = 'POWER_GREATERTHAN' then + if strt = 1 then + relop := '>'; + else + relop := '<='; + end if; + else + raise_application_error(-20101, 'Unsupported operator'); + end if; + + stmt := 'select r from '||ia.IndexSchema||'.'||ia.IndexName||'_pidx'|| + ' where cpos '|| '=' ||''''||cmppos||''''|| + ' and cval '||relop||''''||cmpval||''''; + + dbms_output.put_line('ODCIIndexStart>>>>>' || stmt); + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + dbms_sql.define_column_rowid(cnum, 1, rid); + nrows := dbms_sql.execute(cnum); + + -- Set context as the cursor number. + sctx := power_idxtype_im(cnum); + + -- Return success. + RETURN ODCICONST.SUCCESS; + END; + + -- This definition of ODCIIndexStart is for queries on any + -- cell. (The preceding definition was for queries on a + -- specific cell.) + STATIC FUNCTION ODCIIndexStart(sctx IN OUT power_idxtype_im, + ia sys.odciindexinfo, + op sys.odciPredInfo, qi sys.ODCIQueryInfo, + strt NUMBER, stop NUMBER, + cmpval NUMBER, env sys.ODCIEnv) RETURN NUMBER is + cnum INTEGER; + rid ROWID; + nrows INTEGER; + relop VARCHAR2(2); + stmt VARCHAR2(1000); + BEGIN + dbms_output.put_line('ODCIIndexStart>>>>>'); + sys.ODCIIndexInfoDump(ia); + sys.ODCIPredInfoDump(op); + dbms_output.put_line('start key : '||strt); + dbms_output.put_line('stop key : '||stop); + dbms_output.put_line('compare value : '||cmpval); + + -- Take care of some error cases. + -- The only predicates in which btree operators can appear are + -- op() = 1 OR op() = 0 + if (strt != 1) and (strt != 0) then + raise_application_error(-20101, 'Incorrect predicate for operator'); + END if; + + if (stop != 1) and (stop != 0) then + raise_application_error(-20101, 'Incorrect predicate for operator'); + END if; + + -- Generate the SQL statement to be executed. + -- First, figure out the relational operator needed for the statement. + -- Take into account the operator name and the start and stop keys. + -- For now, the start and stop keys can both be 1 (= TRUE) or + -- both be 0 (= FALSE). + if op.ObjectName = 'POWER_EQUALSANY' then + relop := '='; + elsif op.ObjectName = 'POWER_LESSTHANANY' then + relop := '<'; + elsif op.ObjectName = 'POWER_GREATERTHANANY' then + relop := '>'; + else + raise_application_error(-20101, 'Unsupported operator'); + end if; + + -- This statement returns the qualifying rows for the TRUE case. + stmt := 'select distinct r from ' || + ia.IndexSchema || '.' || ia.IndexName || '_pidx' || + ' where cval ' || relop || '''' || cmpval || ''''; + -- In the FALSE case, we need to find the complement of the rows. + if (strt = 0) then + stmt := 'select distinct r from ' || + ia.IndexSchema || '.' || ia.IndexName||'_pidx' || + ' minus '||stmt; + end if; + + dbms_output.put_line('ODCIIndexStart>>>>>' || stmt); + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + dbms_sql.define_column_rowid(cnum, 1, rid); + nrows := dbms_sql.execute(cnum); + + -- Set context as the cursor number. + sctx := power_idxtype_im(cnum); + + -- Return success. + RETURN ODCICONST.SUCCESS; + END; + + MEMBER FUNCTION ODCIIndexFetch(nrows NUMBER, rids OUT sys.odciridlist, + env sys.ODCIEnv) + RETURN NUMBER is + cnum INTEGER; + idx INTEGER := 1; + rlist sys.odciridlist := sys.odciridlist(); + done boolean := FALSE; + BEGIN + dbms_output.put_line('ODCIIndexFetch>>>>>'); + dbms_output.put_line('Nrows : '||round(nrows)); + + cnum := self.curnum; + + WHILE not done LOOP + if idx > nrows then + done := TRUE; + else + rlist.extend; + if dbms_sql.fetch_rows(cnum) > 0 then + dbms_sql.column_value_rowid(cnum, 1, rlist(idx)); + idx := idx + 1; + else + rlist(idx) := null; + done := TRUE; + END if; + END if; + END LOOP; + + rids := rlist; + RETURN ODCICONST.SUCCESS; + END; + + MEMBER FUNCTION ODCIIndexClose(env sys.ODCIEnv) RETURN NUMBER is + cnum INTEGER; + BEGIN + dbms_output.put_line('ODCIIndexClose>>>>>'); + + cnum := self.curnum; + dbms_sql.close_cursor(cnum); + RETURN ODCICONST.SUCCESS; + END; + + STATIC FUNCTION ODCIIndexInsert(ia sys.odciindexinfo, rid VARCHAR2, + newval PowerDemand_Typ, env sys.ODCIEnv) + RETURN NUMBER as + cid INTEGER; + i BINARY_INTEGER; + nrows INTEGER; + stmt VARCHAR2(1000); + BEGIN + dbms_output.put_line(' '); + dbms_output.put_line('ODCIIndexInsert>>>>>'|| + ' TotGridDemand= '||newval.TotGridDemand || + ' MaxCellDemand= '||newval.MaxCellDemand || + ' MinCellDemand= '||newval.MinCellDemand) ; + sys.ODCIIndexInfoDump(ia); + + -- Construct the statement. + stmt := ' INSERT INTO ' || + ia.IndexSchema || '.' || ia.IndexName || '_pidx' || + ' VALUES (:rr, :pos, :val)'; + + -- Execute the statement. + dbms_output.put_line('ODCIIndexInsert>>>>>'||stmt); + -- Parse the statement. + cid := dbms_sql.open_cursor; + dbms_sql.parse(cid, stmt, dbms_sql.native); + dbms_sql.bind_variable_rowid(cid, ':rr', rid); + + -- Iterate over the rows of the Varray and insert them. + i := newval.CellDemandValues.FIRST; + WHILE i IS NOT NULL LOOP + -- Bind the row into the cursor for insert. + dbms_sql.bind_variable(cid, ':pos', i); + dbms_sql.bind_variable(cid, ':val', newval.CellDemandValues(i)); + -- Execute. + nrows := dbms_sql.execute(cid); + dbms_output.put_line('ODCIIndexInsert>>>>>('|| + 'RID' ||' , '|| + i || ' , '|| + newval.CellDemandValues(i)|| ')'); + i := newval.CellDemandValues.NEXT(i); + END LOOP; + dbms_sql.close_cursor(cid); + RETURN ODCICONST.SUCCESS; + END ODCIIndexInsert; + + STATIC FUNCTION ODCIIndexDelete(ia sys.odciindexinfo, rid VARCHAR2, + oldval PowerDemand_Typ, env sys.ODCIEnv) + RETURN NUMBER as + cid INTEGER; + stmt VARCHAR2(1000); + nrows INTEGER; + BEGIN + dbms_output.put_line(' '); + dbms_output.put_line('ODCIIndexDelete>>>>>'|| + ' TotGridDemand= '||oldval.TotGridDemand || + ' MaxCellDemand= '||oldval.MaxCellDemand || + ' MinCellDemand= '||oldval.MinCellDemand) ; + sys.ODCIIndexInfoDump(ia); + + -- Construct the statement. + stmt := ' DELETE FROM ' || + ia.IndexSchema || '.' || ia.IndexName || '_pidx' || + ' WHERE r=:rr'; + dbms_output.put_line('ODCIIndexDelete>>>>>'||stmt); + + -- Parse and execute the statement. + cid := dbms_sql.open_cursor; + dbms_sql.parse(cid, stmt, dbms_sql.native); + dbms_sql.bind_variable_rowid(cid, ':rr', rid); + nrows := dbms_sql.execute(cid); + dbms_sql.close_cursor(cid); + + RETURN ODCICONST.SUCCESS; + END ODCIIndexDelete; + + STATIC FUNCTION ODCIIndexUpdate(ia sys.odciindexinfo, rid VARCHAR2, + oldval PowerDemand_Typ, newval PowerDemand_Typ, env sys.ODCIEnv) + RETURN NUMBER as + cid INTEGER; + cid2 INTEGER; + stmt VARCHAR2(1000); + stmt2 VARCHAR2(1000); + nrows INTEGER; + i NUMBER; + BEGIN + dbms_output.put_line(' '); + dbms_output.put_line('ODCIIndexUpdate>>>>> Old'|| + ' TotGridDemand= '||oldval.TotGridDemand || + ' MaxCellDemand= '||oldval.MaxCellDemand || + ' MinCellDemand= '||oldval.MinCellDemand) ; + dbms_output.put_line('ODCIIndexUpdate>>>>> New'|| + ' TotGridDemand= '||newval.TotGridDemand || + ' MaxCellDemand= '||newval.MaxCellDemand || + ' MinCellDemand= '||newval.MinCellDemand) ; + sys.ODCIIndexInfoDump(ia); + + -- Delete old entries. + stmt := ' DELETE FROM ' || + ia.IndexSchema || '.' || ia.IndexName || '_pidx' || + ' WHERE r=:rr'; + dbms_output.put_line('ODCIIndexUpdate>>>>>'||stmt); + + -- Parse and execute the statement. + cid := dbms_sql.open_cursor; + dbms_sql.parse(cid, stmt, dbms_sql.native); + dbms_sql.bind_variable_rowid(cid, ':rr', rid); + nrows := dbms_sql.execute(cid); + dbms_sql.close_cursor(cid); + + -- Insert new entries. + stmt2 := ' INSERT INTO ' || + ia.IndexSchema || '.' || ia.IndexName || '_pidx' || + ' VALUES (:rr, :pos, :val)'; + dbms_output.put_line('ODCIIndexUpdate>>>>>'||stmt2); + + -- Parse and execute the statement. + cid2 := dbms_sql.open_cursor; + dbms_sql.parse(cid2, stmt2, dbms_sql.native); + dbms_sql.bind_variable_rowid(cid2, ':rr', rid); + + -- Iterate over the rows of the Varray and insert them. + i := newval.CellDemandValues.FIRST; + WHILE i IS NOT NULL LOOP + -- Bind the row into the cursor for insert. + dbms_sql.bind_variable(cid2, ':pos', i); + dbms_sql.bind_variable(cid2, ':val', newval.CellDemandValues(i)); + nrows := dbms_sql.execute(cid2); + dbms_output.put_line('ODCIIndexUpdate>>>>>('|| + 'RID' || ' , '|| + i || ' , '|| + newval.CellDemandValues(i)|| ')'); + i := newval.CellDemandValues.NEXT(i); + END LOOP; + dbms_sql.close_cursor(cid2); + + RETURN ODCICONST.SUCCESS; + END ODCIIndexUpdate; + + STATIC FUNCTION ODCIIndexGetMetadata(ia sys.odciindexinfo, + expversion VARCHAR2, newblock OUT PLS_INTEGER, env sys.ODCIEnv) + RETURN VARCHAR2 is + BEGIN + -- Let getversion do all the work since it has to maintain + -- state across calls. + + RETURN power_pkg.getversion (ia.IndexSchema, ia.IndexName, newblock); + + EXCEPTION + WHEN OTHERS THEN + RAISE; + + END ODCIIndexGetMetaData; + +END; +/ + +show errors; +------------------------------------------------------------------- +-- CREATE INDEXTYPE +------------------------------------------------------------------- +CREATE OR REPLACE INDEXTYPE power_idxtype +FOR + Power_Equals(PowerDemand_Typ, NUMBER, NUMBER), + Power_GreaterThan(PowerDemand_Typ, NUMBER, NUMBER), + Power_LessThan(PowerDemand_Typ, NUMBER, NUMBER), + Power_EqualsAny(PowerDemand_Typ, NUMBER), + Power_GreaterThanAny(PowerDemand_Typ, NUMBER), + Power_LessThanAny(PowerDemand_Typ, NUMBER) +USING power_idxtype_im; + +------------------------------------------------------------------- +-- Create table and populate it -- +------------------------------------------------------------------- +CREATE TABLE PowerDemand_Tab ( + -- Region for which these power demand readings apply + region NUMBER, + -- Values for each "sampling" time (for a given hour) + sample PowerDemand_Typ +); + +-- The next INSERT statements "cheat" by supplying +-- only 5 grid values (instead of 100). + +-- INSERT statements are for region 1 to get enough timestamps +-- for a moving average using the Time Series cartridge. +-- (Time Series cartridge tests are in a separate file.) + +declare + i integer; +begin + i := 0; + + while i < 2000 loop + INSERT INTO PowerDemand_Tab VALUES( + 1, + PowerDemand_Typ(NULL, NULL, NULL, + PowerGrid_Typ(i,i+1,i+2,i+3,i+4),SYSDATE)); + + i := i+5; + END LOOP; +end; +/ + +-- Also insert some rows for region 2. + +INSERT INTO PowerDemand_Tab VALUES(2, + PowerDemand_Typ(NULL, NULL, NULL, PowerGrid_Typ(9,8,11,16,5), + to_date('02-01-1998 01','MM-DD-YYYY HH')) +); + +INSERT INTO PowerDemand_Tab VALUES(2, + PowerDemand_Typ(NULL, NULL, NULL, PowerGrid_Typ(9,8,11,20,5), + to_date('02-01-1998 02','MM-DD-YYYY HH')) +); + + +DECLARE +CURSOR c1 IS SELECT Sample FROM PowerDemand_Tab FOR UPDATE; +s PowerDemand_Typ; +BEGIN + OPEN c1; + LOOP + FETCH c1 INTO s; + EXIT WHEN c1%NOTFOUND; + s.SetTotalDemand; + s.SetMaxDemand; + s.SetMinDemand; + dbms_output.put_line(s.TotGridDemand); + dbms_output.put_line(s.MaxCellDemand); + dbms_output.put_line(s.MinCellDemand); + UPDATE PowerDemand_Tab SET Sample = s WHERE CURRENT of c1; + END LOOP; + CLOSE c1; +END; +/ + +------------------------------------------------------------------- +-- CREATE GENERIC FUNCTION TO COMPUTE SELECTIVITY OF PREDICATE +------------------------------------------------------------------- + +CREATE FUNCTION get_selectivity(relop VARCHAR2, value NUMBER, + lo NUMBER, hi NUMBER, ndv NUMBER) + RETURN NUMBER AS + sel NUMBER := NULL; +BEGIN + -- This function computes the selectivity (as a percentage) + -- of a predicate + -- col + -- where is one of: =, !=, <, <=, >, >= + -- is one of: 0, 1 + -- lo and hi are the minimum and maximum values of the column in + -- the table. This function performs a simplistic estimation of the + -- selectivity by assulog that the range of distinct values of + -- the column is distributed uniformly in the range lo..hi and that + -- each distinct value occurs nrows/(hi-lo+1) times (where nrows is + -- the number of rows). + + IF ndv IS NULL OR ndv <= 0 THEN + RETURN 0; + END IF; + + -- col != + IF relop = '!=' THEN + IF value between lo and hi THEN + sel := 1 - 1/ndv; + ELSE + sel := 1; + END IF; + + -- col = + ELSIF relop = '=' THEN + IF value between lo and hi THEN + sel := 1/ndv; + ELSE + sel := 0; + END IF; + + -- col >= + ELSIF relop = '>=' THEN + IF lo = hi THEN + IF value <= lo THEN + sel := 1; + ELSE + sel := 0; + END IF; + ELSIF value between lo and hi THEN + sel := (hi-value)/(hi-lo) + 1/ndv; + ELSIF value < lo THEN + sel := 1; + ELSE + sel := 0; + END IF; + + -- col < + ELSIF relop = '<' THEN + IF lo = hi THEN + IF value > lo THEN + sel := 1; + ELSE + sel := 0; + END IF; + ELSIF value between lo and hi THEN + sel := (value-lo)/(hi-lo); + ELSIF value < lo THEN + sel := 0; + ELSE + sel := 1; + END IF; + + -- col <= + ELSIF relop = '<=' THEN + IF lo = hi THEN + IF value >= lo THEN + sel := 1; + ELSE + sel := 0; + END IF; + ELSIF value between lo and hi THEN + sel := (value-lo)/(hi-lo) + 1/ndv; + ELSIF value < lo THEN + sel := 0; + ELSE + sel := 1; + END IF; + + -- col > + ELSIF relop = '>' THEN + IF lo = hi THEN + IF value < lo THEN + sel := 1; + ELSE + sel := 0; + END IF; + ELSIF value between lo and hi THEN + sel := (hi-value)/(hi-lo); + ELSIF value < lo THEN + sel := 1; + ELSE + sel := 0; + END IF; + + END IF; + + RETURN least(100, ceil(100*sel)); + +END; +/ + +------------------------------------------------------------------- +-- CREATE STATISTICS IMPLEMENTATION TYPE +------------------------------------------------------------------- +CREATE OR REPLACE TYPE power_statistics AS OBJECT +( + curnum NUMBER, + STATIC FUNCTION ODCIGetInterfaces(ifclist OUT sys.ODCIObjectList) + RETURN NUMBER, + STATIC FUNCTION ODCIStatsCollect(col sys.ODCIColInfo, + options sys.ODCIStatsOptions, rawstats OUT RAW, env sys.ODCIEnv) + RETURN NUMBER, + STATIC FUNCTION ODCIStatsDelete(col sys.ODCIColInfo, + statistics OUT RAW, env sys.ODCIEnv) + RETURN NUMBER, + STATIC FUNCTION ODCIStatsCollect(ia sys.ODCIIndexInfo, + options sys.ODCIStatsOptions, rawstats OUT RAW, env sys.ODCIEnv) + RETURN NUMBER, + STATIC FUNCTION ODCIStatsDelete(ia sys.ODCIIndexInfo, + statistics OUT RAW, env sys.ODCIEnv) + RETURN NUMBER, + STATIC FUNCTION ODCIStatsSelectivity(pred sys.ODCIPredInfo, + sel OUT NUMBER, args sys.ODCIArgDescList, strt NUMBER, stop NUMBER, + object PowerDemand_Typ, cell NUMBER, value NUMBER, env sys.ODCIEnv) + RETURN NUMBER, + PRAGMA restrict_references(ODCIStatsSelectivity, WNDS, WNPS), + STATIC FUNCTION ODCIStatsSelectivity(pred sys.ODCIPredInfo, + sel OUT NUMBER, args sys.ODCIArgDescList, strt NUMBER, stop NUMBER, + object PowerDemand_Typ, value NUMBER, env sys.ODCIEnv) + RETURN NUMBER, + PRAGMA restrict_references(ODCIStatsSelectivity, WNDS, WNPS), + STATIC FUNCTION ODCIStatsIndexCost(ia sys.ODCIIndexInfo, + sel NUMBER, cost OUT sys.ODCICost, qi sys.ODCIQueryInfo, + pred sys.ODCIPredInfo, args sys.ODCIArgDescList, + strt NUMBER, stop NUMBER, cmppos NUMBER, cmpval NUMBER, env sys.ODCIEnv) + RETURN NUMBER, + PRAGMA restrict_references(ODCIStatsIndexCost, WNDS, WNPS), + STATIC FUNCTION ODCIStatsIndexCost(ia sys.ODCIIndexInfo, + sel NUMBER, cost OUT sys.ODCICost, qi sys.ODCIQueryInfo, + pred sys.ODCIPredInfo, args sys.ODCIArgDescList, + strt NUMBER, stop NUMBER, cmpval NUMBER, env sys.ODCIEnv) RETURN NUMBER, + PRAGMA restrict_references(ODCIStatsIndexCost, WNDS, WNPS), + STATIC FUNCTION ODCIStatsFunctionCost(func sys.ODCIFuncInfo, + cost OUT sys.ODCICost, args sys.ODCIArgDescList, + object PowerDemand_Typ, cell NUMBER, value NUMBER, env sys.ODCIEnv) + RETURN NUMBER, + PRAGMA restrict_references(ODCIStatsFunctionCost, WNDS, WNPS), + STATIC FUNCTION ODCIStatsFunctionCost(func sys.ODCIFuncInfo, + cost OUT sys.ODCICost, args sys.ODCIArgDescList, + object PowerDemand_Typ, value NUMBER, env sys.ODCIEnv) RETURN NUMBER, + PRAGMA restrict_references(ODCIStatsFunctionCost, WNDS, WNPS) +); +/ +show errors; + +CREATE OR REPLACE TYPE BODY power_statistics +IS + STATIC FUNCTION ODCIGetInterfaces(ifclist OUT sys.ODCIObjectList) + RETURN NUMBER IS + BEGIN + ifclist := sys.ODCIObjectList(sys.ODCIObject('SYS','ODCISTATS2')); + RETURN ODCIConst.Success; + END ODCIGetInterfaces; + + STATIC FUNCTION ODCIStatsCollect(col sys.ODCIColInfo, + options sys.ODCIStatsOptions, + rawstats OUT RAW, env sys.ODCIEnv) + RETURN NUMBER IS + cnum INTEGER; + stmt VARCHAR2(1000); + junk INTEGER; + + cval NUMBER; + colname VARCHAR2(30) := rtrim(ltrim(col.colName, '"'), '"'); + statsexists BOOLEAN := FALSE; + pdemands PowerDemand_Tab%ROWTYPE; + user_defined_stats PowerCartUserStats%ROWTYPE; + CURSOR c1(tname VARCHAR2, cname VARCHAR2) IS + SELECT * FROM PowerCartUserStats + WHERE tab = tname + AND col = cname; + CURSOR c2 IS + SELECT * FROM PowerDemand_Tab; + + BEGIN + sys.ODCIColInfoDump(col); + sys.ODCIStatsOptionsDump(options); + + IF (col.TableSchema IS NULL OR col.TableName IS NULL + OR col.ColName IS NULL) THEN + RETURN ODCIConst.Error; + END IF; + + dbms_output.put_line('ODCIStatsCollect>>>>>'); + dbms_output.put_line('**** Analyzing column ' + || col.TableSchema + || '.' || col.TableName + || '.' || col.ColName); + + -- Check if statistics exist for this column + FOR user_defined_stats IN c1(col.TableName, colname) LOOP + statsexists := TRUE; + EXIT; + END LOOP; + + IF not statsexists THEN + -- column statistics don't exist; create entries for + -- each of the 100 cells + cnum := dbms_sql.open_cursor; + FOR i in 1..100 LOOP + stmt := 'INSERT INTO PowerCartUserStats VALUES( ' + || '''' || col.TableName || ''', ' + || '''' || colname || ''', ' + || to_char(i) || ', ' + || 'NULL, NULL, NULL)'; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + END LOOP; + dbms_sql.close_cursor(cnum); + ELSE + -- column statistics exist; initialize to NULL + cnum := dbms_sql.open_cursor; + stmt := 'UPDATE PowerCartUserStats' + || ' SET lo = NULL, hi = NULL, nrows = NULL' + || ' WHERE tab = ' || col.TableName + || ' AND col = ' || colname; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + END IF; + + -- For each cell position, the following statistics are collected: + -- maximum value + -- minimum value + -- number of rows (excluding NULLs) + cnum := dbms_sql.open_cursor; + FOR i in 1..100 LOOP + FOR pdemands IN c2 LOOP + IF i BETWEEN pdemands.sample.CellDemandValues.FIRST AND + pdemands.sample.CellDemandValues.LAST THEN + cval := pdemands.sample.CellDemandValues(i); + stmt := 'UPDATE PowerCartUserStats SET ' + || 'lo = least(' || 'NVL(' || to_char(cval) || ', lo), ' + || 'NVL(' || 'lo, ' || to_char(cval) || ')), ' + || 'hi = greatest(' || 'NVL(' || to_char(cval) || ', hi), ' + || 'NVL(' || 'hi, ' || to_char(cval) || ')), ' + || 'nrows = decode(nrows, NULL, decode(' + || to_char(cval) || ', NULL, NULL, 1), decode(' + || to_char(cval) || ', NULL, nrows, nrows+1)) ' + || 'WHERE cpos = ' || to_char(i) + || ' AND tab = ''' || col.TableName || '''' + || ' AND col = ''' || colname || ''''; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + END IF; + END LOOP; + END LOOP; + dbms_sql.close_cursor(cnum); + + rawstats := NULL; + + return ODCIConst.Success; + + END; + + STATIC FUNCTION ODCIStatsDelete(col sys.ODCIColInfo, statistics OUT RAW, + env sys.ODCIEnv) + RETURN NUMBER IS + cnum INTEGER; + stmt VARCHAR2(1000); + junk INTEGER; + + colname VARCHAR2(30) := rtrim(ltrim(col.colName, '"'), '"'); + statsexists BOOLEAN := FALSE; + user_defined_stats PowerCartUserStats%ROWTYPE; + CURSOR c1(tname VARCHAR2, cname VARCHAR2) IS + SELECT * FROM PowerCartUserStats + WHERE tab = tname + AND col = cname; + BEGIN + sys.ODCIColInfoDump(col); + + IF (col.TableSchema IS NULL OR col.TableName IS NULL + OR col.ColName IS NULL) THEN + RETURN ODCIConst.Error; + END IF; + + dbms_output.put_line('ODCIStatsDelete>>>>>'); + dbms_output.put_line('**** Analyzing (delete) column ' + || col.TableSchema + || '.' || col.TableName + || '.' || col.ColName); + + -- Check if statistics exist for this column + FOR user_defined_stats IN c1(col.TableName, colname) LOOP + statsexists := TRUE; + EXIT; + END LOOP; + + -- If user-defined statistics exist, delete them + IF statsexists THEN + stmt := 'DELETE FROM PowerCartUserStats' + || ' WHERE tab = ''' || col.TableName || '''' + || ' AND col = ''' || colname || ''''; + cnum := dbms_sql.open_cursor; + dbms_output.put_line('ODCIStatsDelete>>>>>'); + dbms_output.put_line('ODCIStatsDelete>>>>>' || stmt); + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + END IF; + + RETURN ODCIConst.Success; + END; + + STATIC FUNCTION ODCIStatsCollect (ia sys.ODCIIndexInfo, + options sys.ODCIStatsOptions, rawstats OUT RAW, env sys.ODCIEnv) + RETURN NUMBER IS + cnum INTEGER; + stmt VARCHAR2(1000); + junk INTEGER; + BEGIN + -- To analyze a domain index, simply analyze the table that + -- implements the index + + sys.ODCIIndexInfoDump(ia); + sys.ODCIStatsOptionsDump(options); + + stmt := 'ANALYZE TABLE ' + || ia.IndexSchema || '.' || ia.IndexName || '_pidx' + || ' COMPUTE STATISTICS'; + + dbms_output.put_line('**** Analyzing index ' + || ia.IndexSchema || '.' || ia.IndexName); + dbms_output.put_line('SQL Statement: ' || stmt); + + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + + rawstats := NULL; + + RETURN ODCIConst.Success; + END; + + STATIC FUNCTION ODCIStatsDelete(ia sys.ODCIIndexInfo, + statistics OUT RAW, env sys.ODCIEnv) + RETURN NUMBER IS + cnum INTEGER; + stmt VARCHAR2(1000); + junk INTEGER; + BEGIN + -- To delete statistics for a domain index, simply delete the + -- statistics for the table implementing the index + + sys.ODCIIndexInfoDump(ia); + + stmt := 'ANALYZE TABLE ' + || ia.IndexSchema || '.' || ia.IndexName || '_pidx' + || ' DELETE STATISTICS'; + + dbms_output.put_line('**** Analyzing (delete) index ' + || ia.IndexSchema || '.' || ia.IndexName); + dbms_output.put_line('SQL Statement: ' || stmt); + + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + + RETURN ODCIConst.Success; + END; + + STATIC FUNCTION ODCIStatsSelectivity(pred sys.ODCIPredInfo, + sel OUT NUMBER, args sys.ODCIArgDescList, strt NUMBER, stop NUMBER, + object PowerDemand_Typ, cell NUMBER, value NUMBER, env sys.ODCIEnv) + RETURN NUMBER IS + fname varchar2(30); + relop varchar2(2); + lo NUMBER; + hi NUMBER; + nrows NUMBER; + colname VARCHAR2(30); + statsexists BOOLEAN := FALSE; + stats PowerCartUserStats%ROWTYPE; + CURSOR c1(cell NUMBER, tname VARCHAR2, cname VARCHAR2) IS + SELECT * FROM PowerCartUserStats + WHERE cpos = cell + AND tab = tname + AND col = cname; + BEGIN + -- compute selectivity only when predicate is of the form: + -- fn(col, , ) + -- In all other cases, return an error and let the optimizer + -- make a guess. We also assume that the function "fn" has + -- a return value of 0, 1, or NULL. + + -- start value + IF (args(1).ArgType != ODCIConst.ArgLit AND + args(1).ArgType != ODCIConst.ArgNull) THEN + RETURN ODCIConst.Error; + END IF; + + -- stop value + IF (args(2).ArgType != ODCIConst.ArgLit AND + args(2).ArgType != ODCIConst.ArgNull) THEN + RETURN ODCIConst.Error; + END IF; + + -- first argument of function + IF (args(3).ArgType != ODCIConst.ArgCol) THEN + RETURN ODCIConst.Error; + END IF; + + -- second argument of function + IF (args(4).ArgType != ODCIConst.ArgLit AND + args(4).ArgType != ODCIConst.ArgNull) THEN + RETURN ODCIConst.Error; + END IF; + + -- third argument of function + IF (args(5).ArgType != ODCIConst.ArgLit AND + args(5).ArgType != ODCIConst.ArgNull) THEN + RETURN ODCIConst.Error; + END IF; + + colname := rtrim(ltrim(args(3).colName, '"'), '"'); + + -- Check if the statistics table exists (we are using a + -- user-defined table to store the user-defined statistics). + -- Get user-defined statistics: MIN, MAX, NROWS + FOR stats IN c1(cell, args(3).TableName, colname) LOOP + -- Get user-defined statistics: MIN, MAX, NROWS + lo := stats.lo; + hi := stats.hi; + nrows := stats.nrows; + statsexists := TRUE; + EXIT; + END LOOP; + + -- If no user-defined statistics were collected, return error + IF not statsexists THEN + RETURN ODCIConst.Error; + END IF; + + -- selectivity is 0 for "fn(col, , ) < 0" + IF (stop = 0 AND + bitand(pred.Flags, ODCIConst.PredIncludeStop) = 0) THEN + sel := 0; + RETURN ODCIConst.Success; + END IF; + + -- selectivity is 0 for "fn(col, , ) > 1" + IF (strt = 1 AND + bitand(pred.Flags, ODCIConst.PredIncludeStart) = 0) THEN + sel := 0; + RETURN ODCIConst.Success; + END IF; + + -- selectivity is 100% for "fn(col, , ) >= 0" + IF (strt = 0 AND + bitand(pred.Flags, ODCIConst.PredExactMatch) = 0 AND + bitand(pred.Flags, ODCIConst.PredIncludeStart) > 0) THEN + sel := 100; + RETURN ODCIConst.Success; + END IF; + + -- selectivity is 100% for "fn(col, , ) <= 1" + IF (stop = 1 AND + bitand(pred.Flags, ODCIConst.PredExactMatch) = 0 AND + bitand(pred.Flags, ODCIConst.PredIncludeStop) > 0) THEN + sel := 100; + RETURN ODCIConst.Success; + END IF; + + -- get function name + IF bitand(pred.Flags, ODCIConst.PredObjectFunc) > 0 THEN + fname := pred.ObjectName; + ELSE + fname := pred.MethodName; + END IF; + + -- convert prefix relational operator to infix; + -- e.g., "Power_EqualsSpecific_Func(col, , ) = 1" + -- becomes "col[] = " + + -- Power_EqualsSpecific_Func(col, , ) = 0 + -- Power_EqualsSpecific_Func(col, , ) <= 0 + -- Power_EqualsSpecific_Func(col, , ) < 1 + -- can be transformed to + -- col[] != + IF (fname LIKE upper('Power_Equals%') AND + (stop = 0 OR + (stop = 1 AND + bitand(pred.Flags, ODCIConst.PredIncludeStop) = 0))) THEN + relop := '!='; + + -- Power_LessThanSpecific_Func(col, , ) = 0 + -- Power_LessThanSpecific_Func(col, , ) <= 0 + -- Power_LessThanSpecific_Func(col, , ) < 1 + -- can be transformed to + -- col[] >= + ELSIF (fname LIKE upper('Power_LessThan%') AND + (stop = 0 OR + (stop = 1 AND + bitand(pred.Flags, ODCIConst.PredIncludeStop) = 0))) THEN + relop := '>='; + + -- Power_GreaterThanSpecific_Func(col, , ) = 0 + -- Power_GreaterThanSpecific_Func(col, , ) <= 0 + -- Power_GreaterThanSpecific_Func(col, , ) < 1 + -- can be transformed to + -- col[] <= + ELSIF (fname LIKE upper('Power_GreaterThan%') AND + (stop = 0 OR + (stop = 1 AND + bitand(pred.Flags, ODCIConst.PredIncludeStop) = 0))) THEN + relop := '<='; + + -- Power_EqualsSpecific_Func(col, , ) = 1 + -- Power_EqualsSpecific_Func(col, , ) >= 1 + -- Power_EqualsSpecific_Func(col, , ) > 0 + -- can be transformed to + -- col[] = + ELSIF (fname LIKE upper('Power_Equals%') AND + (strt = 1 OR + (strt = 0 AND + bitand(pred.Flags, ODCIConst.PredIncludeStart) = 0))) THEN + relop := '='; + + -- Power_LessThanSpecific_Func(col, , ) = 1 + -- Power_LessThanSpecific_Func(col, , ) >= 1 + -- Power_LessThanSpecific_Func(col, , ) > 0 + -- can be transformed to + -- col[] < + ELSIF (fname LIKE upper('Power_LessThan%') AND + (strt = 1 OR + (strt = 0 AND + bitand(pred.Flags, ODCIConst.PredIncludeStart) = 0))) THEN + relop := '<'; + + -- Power_GreaterThanSpecific_Func(col, , ) = 1 + -- Power_GreaterThanSpecific_Func(col, , ) >= 1 + -- Power_GreaterThanSpecific_Func(col, , ) > 0 + -- can be transformed to + -- col[] > + ELSIF (fname LIKE upper('Power_GreaterThan%') AND + (strt = 1 OR + (strt = 0 AND + bitand(pred.Flags, ODCIConst.PredIncludeStart) = 0))) THEN + relop := '>'; + + ELSE + RETURN ODCIConst.Error; + + END IF; + + sel := get_selectivity(relop, value, lo, hi, nrows); + RETURN ODCIConst.Success; + END; + + STATIC FUNCTION ODCIStatsSelectivity(pred sys.ODCIPredInfo, + sel OUT NUMBER, args sys.ODCIArgDescList, strt NUMBER, stop NUMBER, + object PowerDemand_Typ, value NUMBER, env sys.ODCIEnv) + RETURN NUMBER IS + cellsel NUMBER; + i NUMBER; + specsel NUMBER; + newargs sys.ODCIArgDescList + := sys.ODCIArgDescList(NULL, NULL, NULL, + NULL, NULL); + BEGIN + -- To compute selectivity for the ANY functions, call the + -- selectivity function for the SPECIFIC functions. For example, + -- the selectivity of the ANY predicate + -- + -- Power_EqualsAnyFunc(object, value) = 1 + -- + -- is computed as + -- + -- 1 - (1-s[1])(1-s[2])...(1-s[100]) + -- + -- where s[i] is the selectivity of the SPECIFIC predicate + -- + -- Power_EqualsSpecific_Func(object, i, value) = 1 + -- + + sel := 1; + newargs(1) := args(1); + newargs(2) := args(2); + newargs(3) := args(3); + newargs(4) := sys.ODCIArgDesc(ODCIConst.ArgLit, NULL, NULL, NULL, + NULL, NULL, NULL); + newargs(5) := args(4); + FOR i in 1..100 LOOP + cellsel := NULL; + specsel := power_statistics.ODCIStatsSelectivity(pred, cellsel, + newargs, strt, stop, object, i, value, env); + IF specsel = ODCIConst.Success THEN + sel := sel * (1 - cellsel/100); + END IF; + END LOOP; + + sel := (1 - sel)*100; + RETURN ODCIConst.Success; + END; + + STATIC FUNCTION ODCIStatsIndexCost(ia sys.ODCIIndexInfo, + sel NUMBER, cost OUT sys.ODCICost, qi sys.ODCIQueryInfo, + pred sys.ODCIPredInfo, args sys.ODCIArgDescList, + strt NUMBER, stop NUMBER, cmppos NUMBER, cmpval NUMBER, env sys.ODCIEnv) + RETURN NUMBER IS + BEGIN + -- This is the cost for queries on a specific cell; simply + -- use the cost for queries on any cell. + RETURN ODCIStatsIndexCost(ia, sel, cost, qi, pred, args, + strt, stop, cmpval, env); + END; + + STATIC FUNCTION ODCIStatsIndexCost(ia sys.ODCIIndexInfo, + sel NUMBER, cost OUT sys.ODCICost, qi sys.ODCIQueryInfo, + pred sys.ODCIPredInfo, args sys.ODCIArgDescList, + strt NUMBER, stop NUMBER, cmpval NUMBER, env sys.ODCIEnv) + RETURN NUMBER IS + ixtable VARCHAR2(40); + numblocks NUMBER := NULL; + get_table user_tables%ROWTYPE; + CURSOR c1(tab VARCHAR2) IS + SELECT * FROM user_tables WHERE table_name = tab; + BEGIN + -- This is the cost for queries on any cell. + + -- To compute the cost of a domain index, multiply the + -- number of blocks in the table implementing the index + -- with the selectivity + + -- Return if we don't have predicate selectivity + IF sel IS NULL THEN + RETURN ODCIConst.Error; + END IF; + + cost := sys.ODCICost(NULL, NULL, NULL, NULL); + + -- Get name of table implementing the domain index + ixtable := ia.IndexName || '_pidx'; + + -- Get number of blocks in domain index + FOR get_table IN c1(upper(ixtable)) LOOP + numblocks := get_table.blocks; + EXIT; + END LOOP; + + IF numblocks IS NULL THEN + -- Exit if there are no user-defined statistics for the index + RETURN ODCIConst.Error; + END IF; + + cost.CPUCost := ceil(400*(sel/100)*numblocks); + cost.IOCost := ceil(1.5*(sel/100)*numblocks); + RETURN ODCIConst.Success; + END; + + STATIC FUNCTION ODCIStatsFunctionCost(func sys.ODCIFuncInfo, + cost OUT sys.ODCICost, args sys.ODCIArgDescList, + object PowerDemand_Typ, cell NUMBER, value NUMBER, env sys.ODCIEnv) + RETURN NUMBER IS + BEGIN + -- This is the cost for functions on a specific cell; simply + -- use the cost for functions on any cell. + RETURN ODCIStatsFunctionCost(func, cost, args, object, value, env); + END; + + STATIC FUNCTION ODCIStatsFunctionCost(func sys.ODCIFuncInfo, + cost OUT sys.ODCICost, args sys.ODCIArgDescList, + object PowerDemand_Typ, value NUMBER, env sys.ODCIEnv) + RETURN NUMBER IS + fname VARCHAR2(30); + BEGIN + cost := sys.ODCICost(NULL, NULL, NULL, NULL); + + -- Get function name + IF bitand(func.Flags, ODCIConst.ObjectFunc) > 0 THEN + fname := func.ObjectName; + ELSE + fname := func.MethodName; + END IF; + + IF fname LIKE upper('Power_LessThan%') THEN + cost.CPUCost := 5000; + cost.IOCost := 0; + RETURN ODCIConst.Success; + ELSIF fname LIKE upper('Power_Equals%') THEN + cost.CPUCost := 7000; + cost.IOCost := 0; + RETURN ODCIConst.Success; + ELSIF fname LIKE upper('Power_GreaterThan%') THEN + cost.CPUCost := 5000; + cost.IOCost := 0; + RETURN ODCIConst.Success; + ELSE + RETURN ODCIConst.Error; + END IF; + END; + +END; +/ +show errors; + +-- Associate statistics type with types, indextypes, and functions +ASSOCIATE STATISTICS WITH TYPES PowerDemand_Typ USING power_statistics; +ASSOCIATE STATISTICS WITH INDEXTYPES power_idxtype USING power_statistics; +ASSOCIATE STATISTICS WITH FUNCTIONS + Power_EqualsSpecific_Func, + Power_GreaterThanSpecific_Func, + Power_LessThanSpecific_Func, + Power_EqualsAny_Func, + Power_GreaterThanAny_Func, + Power_LessThanAny_Func + USING power_statistics; + +-- Analyze the table +ANALYZE TABLE PowerDemand_Tab COMPUTE STATISTICS; + +-- Verify that user-defined statistics were collected +SELECT tab tablename, col colname, cpos, lo, hi, nrows +FROM PowerCartUserStats +WHERE nrows IS NOT NULL +ORDER BY cpos; + +-- Delete the statistics +ANALYZE TABLE PowerDemand_Tab DELETE STATISTICS; + +-- Verify that user-defined statistics were deleted +SELECT tab tablename, col colname, cpos, lo, hi, nrows +FROM PowerCartUserStats +WHERE nrows IS NOT NULL +ORDER BY cpos; + +-- Re-analyze the table +ANALYZE TABLE PowerDemand_Tab COMPUTE STATISTICS; + +-- Verify that user-defined statistics were re-collected +SELECT tab tablename, col colname, cpos, lo, hi, nrows +FROM PowerCartUserStats +WHERE nrows IS NOT NULL +ORDER BY cpos; + +-- Examine the values. +SELECT region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + ORDER BY 1,4,3; + + +------------------------------------------------------------------- +-- Query, referencing the functions. +------------------------------------------------------------------- + +SELECT P.Region, P.Sample.TotGridDemand ,P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_EqualsSpecific_Func(P.Sample,2,10) = 1; + +SELECT P.Region, P.Sample.TotGridDemand ,P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_EqualsSpecific_Func(P.Sample,2,8) = 1 + ORDER BY 1,2; + +SET SERVEROUTPUT ON SIZE 999999 + +------------------------------------------------------------------- +-- Query, referencing the operators (without index) +------------------------------------------------------------------- + +EXPLAIN PLAN FOR +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,2,211) = 1; +set echo off +@@extdemo0 +set echo on + +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,2,211) = 1; + +EXPLAIN PLAN FOR +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,1,10) = 1; +set echo off +@@extdemo0 +set echo on + +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,1,10) = 1; + +EXPLAIN PLAN FOR +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,2,9) = 1; +set echo off +@@extdemo0 +set echo on + +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,2,9) = 1; + +EXPLAIN PLAN FOR +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,2,8) = 1; +set echo off +@@extdemo0 +set echo on + +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,2,8) = 1 + ORDER BY 1,2; + +EXPLAIN PLAN FOR +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_EqualsAny(P.Sample,9) = 1; +set echo off +@@extdemo0 +set echo on + +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_EqualsAny(P.Sample,9) = 1 + ORDER BY 1,2; + +EXPLAIN PLAN FOR +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_GreaterThanAny(P.Sample,10) = 0; +set echo off +@@extdemo0 +set echo on + +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_GreaterThanAny(P.Sample,10) = 0 + ORDER BY 1,2; + +EXPLAIN PLAN FOR +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_LessThanAny(P.Sample,10) = 1; +set echo off +@@extdemo0 +set echo on + +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_LessThanAny(P.Sample,10) = 1 + ORDER BY 1,2; + +------------------------------------------------------------------- +-- CREATE INDEX +------------------------------------------------------------------- +CREATE INDEX PowerIndex ON PowerDemand_Tab(Sample) + INDEXTYPE IS power_idxtype parameters('test'); + +-- Analyze the index +ANALYZE INDEX PowerIndex COMPUTE STATISTICS; + +------------------------------------------------------------------- +-- Query, referencing the operators (with index) +------------------------------------------------------------------- +EXPLAIN PLAN FOR +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,2,211) = 1; +set echo off +@@extdemo0 +set echo on + +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,2,211) = 1; + +EXPLAIN PLAN FOR +SELECT P.Region, P.Sample.TotGridDemand ,P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,1,10) = 1; +set echo off +@@extdemo0 +set echo on + +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,1,10) = 1; + +EXPLAIN PLAN FOR +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_EqualsAny(P.Sample,9) = 1; +set echo off +@@extdemo0 +set echo on + +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_EqualsAny(P.Sample,9) = 1 + ORDER BY 1,2; + +EXPLAIN PLAN FOR +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_GreaterThanAny(P.Sample,4) = 0; +set echo off +@@extdemo0 +set echo on + +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_GreaterThanAny(P.Sample,4) = 0; + +EXPLAIN PLAN FOR +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_LessThanAny(P.Sample,5) = 1; +set echo off +@@extdemo0 +set echo on + +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_LessThanAny(P.Sample,5) = 1; + +---------------------------------------------------------------- +-- Test incremental inserts. -- +---------------------------------------------------------------- +INSERT INTO PowerDemand_Tab VALUES( + 3, + PowerDemand_Typ(NULL, NULL, NULL, PowerGrid_Typ(9,8,10,6,5), + to_date('02-01-1998 01','MM-DD-YYYY HH')) +); + +SET ECHO ON +SET SERVEROUTPUT ON SIZE 999999 + +declare +CURSOR c1 IS SELECT Sample FROM PowerDemand_Tab WHERE Region=3 + FOR UPDATE; +s PowerDemand_Typ; +BEGIN + OPEN c1; + LOOP + FETCH c1 INTO s; + EXIT WHEN c1%NOTFOUND; + s.SetTotalDemand; + s.SetMaxDemand; + s.SetMinDemand; + dbms_output.put_line(s.TotGridDemand); + dbms_output.put_line(s.MaxCellDemand); + dbms_output.put_line(s.MinCellDemand); + UPDATE PowerDemand_Tab SET Sample = s WHERE CURRENT OF c1; + END LOOP; + CLOSE c1; +END; +/ + +-- This should return one more row. +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,2,8) = 1 + ORDER BY 1,2; + +---------------------------------------------------------------- +-- Test incremental deletes. -- +---------------------------------------------------------------- +DELETE FROM PowerDemand_Tab WHERE Region=3; + +-- This should return one less row than the preceding SELECT. +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,2,8) = 1 + ORDER BY 1,2; + +---------------------------------------------------------------- +-- Test incremental updates. -- +---------------------------------------------------------------- +INSERT INTO PowerDemand_Tab VALUES(4, + PowerDemand_Typ(NULL, NULL, NULL, PowerGrid_Typ(61,8,12,9,3), + to_date('02-01-1998 01','MM-DD-YYYY HH')) +); + +declare +CURSOR c1 IS SELECT Sample FROM PowerDemand_Tab WHERE Region=4 + FOR UPDATE; +s PowerDemand_Typ; +BEGIN + OPEN c1; + LOOP + FETCH c1 INTO s; + EXIT WHEN c1%NOTFOUND; + s.SetTotalDemand; + s.SetMaxDemand; + s.SetMinDemand; + dbms_output.put_line(s.TotGridDemand); + dbms_output.put_line(s.MaxCellDemand); + dbms_output.put_line(s.MinCellDemand); + UPDATE PowerDemand_Tab SET Sample = s WHERE CURRENT OF c1; + END LOOP; + CLOSE c1; +END; +/ + +-- This SELECT should return one more row than the next SELECT. +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,2,8) = 1 + ORDER BY 1,2; + +-- Now change cell 2's value to 7 (was 8) for the row that was +-- just inserted (region 4, 1:00 AM on 02-Feb-1998). + +UPDATE PowerDemand_Tab t +SET + t.Sample = PowerDemand_Typ(NULL, NULL, NULL, + PowerGrid_Typ(54,7,12,9,3), + to_date('02-01-1998 01','MM-DD-YYYY HH')) +WHERE + t.Region=4 and + t.sample.sampletime = to_date('02-01-1998 01','MM-DD-YYYY HH'); + +declare +CURSOR c1 IS SELECT Sample FROM PowerDemand_Tab WHERE Region=4 + FOR UPDATE; +s PowerDemand_Typ; +BEGIN + OPEN c1; + LOOP + FETCH c1 INTO s; + EXIT WHEN c1%NOTFOUND; + s.SetTotalDemand; + s.SetMaxDemand; + s.SetMinDemand; + dbms_output.put_line(s.TotGridDemand); + dbms_output.put_line(s.MaxCellDemand); + dbms_output.put_line(s.MinCellDemand); + UPDATE PowerDemand_Tab SET Sample = s WHERE CURRENT OF c1; + END LOOP; + CLOSE c1; +END; +/ + +-- This SELECT should return one less row than the preceding SELECT. +SELECT P.Region, P.Sample.TotGridDemand, P.Sample.MaxCellDemand, + P.Sample.MinCellDemand + FROM PowerDemand_Tab P + WHERE Power_Equals(P.Sample,2,8) = 1 + ORDER BY 1,2; + +-- Delete the row that was added for region 4. +DELETE FROM PowerDemand_Tab WHERE Region=4; + +-- Cleanup +CONNECT sys/knl_test7 AS sysdba; +DROP USER PowerCartUser CASCADE; + diff --git a/extdemo2.c b/extdemo2.c new file mode 100644 index 0000000..c62b983 --- /dev/null +++ b/extdemo2.c @@ -0,0 +1,730 @@ +#ifdef RCSID +static char *RCSid = + "$Header: extdemo2.c 05-apr-2005.06:32:23 yhu Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1998, 2005, Oracle. All rights reserved. +*/ + +/* + + NAME + extdemo2.c - Extensible Indexing example implemented as C routines + + DESCRIPTION + This file contains the definitions of the DML and Query routines + for the extensible indexing example that implements a simple btree + (sbtree). See extdemo2.sql for the SQL script that defines the + indextype. + + PUBLIC FUNCTION(S) + qxiqtbs - QXIQT Btree Start routine + qxiqtbf - QXIQT Btree Fetch routine + qxiqtbc - QXIQT Btree Close routine + qxiqtbi - QXIQT Btree Insert routine + qxiqtbd - QXIQT Btree Delete routine + qxiqtbu - QXIQT Btree Update routine + + PRIVATE FUNCTION(S) + qxiqtbe - QXIQT error reporting routine + + NOTES + + + MODIFIED (MM/DD/YY) + yhu 04/04/05 - #4184410: fix porting exceptions in HP VMS + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + spsundar 10/21/98 - fix ODCIIndexInsert routine + rmurthy 06/16/98 - Creation + +*/ + +#ifndef EXTDEMO2_ORACLE +# include "extdemo2.h" +#endif +#include +#include + +/*--------------------------------------------------------------------------- + TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + PUBLIC FUNCTIONS + ---------------------------------------------------------------------------*/ + +/* ODCIIndexInsert function */ +OCINumber *qxiqtbi(ctx, ix, ix_ind, rid, rid_ind, + newval, newval_ind) +OCIExtProcContext *ctx; +ODCIIndexInfo *ix; +ODCIIndexInfo_ind *ix_ind; +char *rid; +short rid_ind; +char *newval; +short newval_ind; +{ + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCIStmt *stmthp = (OCIStmt *) 0; /* statement handle */ + OCIBind *bndp = (OCIBind *) 0; /* bind handle */ + OCIBind *bndp1 = (OCIBind *) 0; /* bind handle */ + + int retval = (int)ODCI_SUCCESS; /* return from this function */ + OCINumber *rval = (OCINumber *)0; + ub4 key; /* key value set in "self" */ + + char insstmt[2000]; /* sql insert statement */ + + /* allocate memory for OCINumber first */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + + /* Get oci handles */ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /****************************** + * Construct insert Statement * + ******************************/ + + sprintf(insstmt, + "INSERT into %s.%s_sbtree values (:newval, :mrid)", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName)); + + /**************************************** + * Parse and Execute Create Statement * + ****************************************/ + + /* allocate stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleAlloc((dvoid *)envhp, + (dvoid **)&stmthp, + (ub4)OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0))) + return(rval); + + /* prepare the statement */ + if (qxiqtce(ctx, errhp, OCIStmtPrepare(stmthp, errhp, (text *)insstmt, + (ub4)strlen(insstmt), OCI_NTV_SYNTAX, + OCI_DEFAULT))) + return(rval); + + + + /* Set up bind for newval */ + if (qxiqtce(ctx, errhp, OCIBindByPos(stmthp, &bndp, errhp, (ub4)1, + (dvoid *)newval, + (sb4)(strlen(newval)+1), + (ub2)SQLT_STR, (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Set up bind for rid */ + if (qxiqtce(ctx, errhp, OCIBindByPos(stmthp, &bndp, errhp, (ub4)2, + (dvoid *)rid, + (sb4)(strlen(rid)+1), + (ub2)SQLT_STR, (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + + /* Execute statement */ + if (qxiqtce(ctx, errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, + (ub4)0, (OCISnapshot *)NULL, + (OCISnapshot *)NULL, + (ub4)OCI_DEFAULT))) + return(rval); + + return(rval); +} + +/* ODCIIndexDelete function */ +OCINumber *qxiqtbd(ctx, ix, ix_ind, rid, rid_ind, + oldval, oldval_ind) +OCIExtProcContext *ctx; +ODCIIndexInfo *ix; +ODCIIndexInfo_ind *ix_ind; +char *rid; +short rid_ind; +char *oldval; +short oldval_ind; +{ + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCIStmt *stmthp = (OCIStmt *) 0; /* statement handle */ + OCIBind *bndp = (OCIBind *) 0; /* bind handle */ + OCIBind *bndp1 = (OCIBind *) 0; /* bind handle */ + + int retval = (int)ODCI_SUCCESS; /* return from this function */ + OCINumber *rval = (OCINumber *)0; + ub4 key; /* key value set in "self" */ + + char delstmt[2000]; /* sql insert statement */ + + /* Get oci handles */ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /****************************** + * Construct delete Statement * + ******************************/ + + sprintf(delstmt, + "DELETE FROM %s.%s_sbtree WHERE f2 = :rr", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName)); + + /**************************************** + * Parse and Execute delete Statement * + ****************************************/ + + /* allocate stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleAlloc((dvoid *)envhp, + (dvoid **)&stmthp, + (ub4)OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0))) + return(rval); + + /* prepare the statement */ + if (qxiqtce(ctx, errhp, OCIStmtPrepare(stmthp, errhp, (text *)delstmt, + (ub4)strlen(delstmt), OCI_NTV_SYNTAX, + OCI_DEFAULT))) + return(rval); + + + + /* Set up bind for rid */ + if (qxiqtce(ctx, errhp, OCIBindByPos(stmthp, &bndp, errhp, (ub4)1, + (dvoid *)rid, + (sb4)(strlen(rid)+1), + (ub2)SQLT_STR, (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + + /* Execute statement */ + if (qxiqtce(ctx, errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, + (ub4)0, (OCISnapshot *)NULL, + (OCISnapshot *)NULL, + (ub4)OCI_DEFAULT))) + return(rval); + + return(rval); +} + +/* ODCIIndexUpdate function */ +OCINumber *qxiqtbu(ctx, ix, ix_ind, rid, rid_ind, + oldval, oldval_ind, newval, newval_ind) +OCIExtProcContext *ctx; +ODCIIndexInfo *ix; +ODCIIndexInfo_ind *ix_ind; +char *rid; +short rid_ind; +char *oldval; +short oldval_ind; +char *newval; +short newval_ind; +{ + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCIStmt *stmthp = (OCIStmt *) 0; /* statement handle */ + OCIBind *bndp = (OCIBind *) 0; /* bind handle */ + OCIBind *bndp1 = (OCIBind *) 0; /* bind handle */ + + int retval = (int)ODCI_SUCCESS; /* return from this function */ + OCINumber *rval = (OCINumber *)0; + ub4 key; /* key value set in "self" */ + + char updstmt[2000]; /* sql insert statement */ + + /* Get oci handles */ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /****************************** + * Construct update Statement * + ******************************/ + + sprintf(updstmt, + "UPDATE %s.%s_sbtree SET f1 = :newval, f2 = :rr WHERE f1 = :oldval", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName)); + + /**************************************** + * Parse and Execute Create Statement * + ****************************************/ + + /* allocate stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleAlloc((dvoid *)envhp, + (dvoid **)&stmthp, + (ub4)OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0))) + return(rval); + + /* prepare the statement */ + if (qxiqtce(ctx, errhp, OCIStmtPrepare(stmthp, errhp, (text *)updstmt, + (ub4)strlen(updstmt), OCI_NTV_SYNTAX, + OCI_DEFAULT))) + return(rval); + + + /* Set up bind for newval */ + if (qxiqtce(ctx, errhp, OCIBindByPos(stmthp, &bndp, errhp, (ub4)1, + (dvoid *)newval, + (sb4)(strlen(newval)+1), + (ub2)SQLT_STR, (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Set up bind for rid */ + if (qxiqtce(ctx, errhp, OCIBindByPos(stmthp, &bndp, errhp, (ub4)2, + (dvoid *)rid, + (sb4)(strlen(rid)+1), + (ub2)SQLT_STR, (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Set up bind for oldval */ + if (qxiqtce(ctx, errhp, OCIBindByPos(stmthp, &bndp, errhp, (ub4)3, + (dvoid *)oldval, + (sb4)(strlen(oldval)+1), + (ub2)SQLT_STR, (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Execute statement */ + if (qxiqtce(ctx, errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, + (ub4)0, (OCISnapshot *)NULL, + (OCISnapshot *)NULL, + (ub4)OCI_DEFAULT))) + return(rval); + + return(rval); +} + +/* ODCIIndexStart function */ +OCINumber *qxiqtbs(ctx, sctx, sctx_ind, ix, ix_ind, pr, pr_ind, qy, qy_ind, + strt, strt_ind, stop, stop_ind, cmpval, cmpval_ind) +OCIExtProcContext *ctx; +qxiqtim *sctx; +qxiqtin *sctx_ind; +ODCIIndexInfo *ix; +dvoid *ix_ind; +ODCIPredInfo *pr; +dvoid *pr_ind; +ODCIQueryInfo *qy; +dvoid *qy_ind; +OCINumber *strt; +short strt_ind; +OCINumber *stop; +short stop_ind; +char *cmpval; +short cmpval_ind; +{ + sword status; + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCISession *usrhp = (OCISession *) 0; /* user handle */ + qxiqtcx *icx = (qxiqtcx *) 0; /* state to be saved for later calls */ + + int strtval; /* start bound */ + int stopval; /* stop bound */ + + int errnum = 29400; /* choose some oracle error number */ + char errmsg[512]; /* error message buffer */ + size_t errmsglen; /* Length of error message */ + + char relop[3]; /* relational operator used in sql stmt */ + char selstmt[2000]; /* sql select statement */ + + int retval = (int)ODCI_SUCCESS; /* return from this function */ + OCINumber *rval = (OCINumber *)0; + ub4 key; /* key value set in "sctx" */ + + /* Get oci handles */ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /* get the user handle */ + if (qxiqtce(ctx, errhp, OCIAttrGet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)&usrhp, (ub4 *)0, + (ub4)OCI_ATTR_SESSION, + errhp))) + return(rval); + + + /**********************************************/ + /* Allocate memory to hold index scan context */ + /**********************************************/ + if (qxiqtce(ctx, errhp, OCIMemoryAlloc((dvoid *)usrhp, errhp, + (dvoid **)&icx, + OCI_DURATION_STATEMENT, + (ub4)(sizeof(qxiqtcx)), + OCI_MEMORY_CLEARED))) + return(rval); + + icx->stmthp = (OCIStmt *)0; + icx->defnp = (OCIDefine *)0; + icx->bndp = (OCIBind *)0; + + /***********************************/ + /* Check that the bounds are valid */ + /***********************************/ + /* convert from oci numbers to native numbers */ + if (qxiqtce(ctx, errhp, OCINumberToInt(errhp, strt, + sizeof(strtval), OCI_NUMBER_SIGNED, + (dvoid *)&strtval))) + return(rval); + if (qxiqtce(ctx, errhp, OCINumberToInt(errhp, stop, + sizeof(stopval), + OCI_NUMBER_SIGNED, (dvoid *)&stopval))) + return(rval); + + /* verify that strtval/stopval are both either 0 or 1 */ + if (!(((strtval == 0) && (stopval == 0)) || + ((strtval == 1) && (stopval == 1)))) + { + strcpy(errmsg, (char *)"Incorrect predicate for sbtree operator"); + errmsglen = (size_t)strlen(errmsg); + if (OCIExtProcRaiseExcpWithMsg(ctx, errnum, (text *)errmsg, errmsglen) + != OCIEXTPROC_SUCCESS) + /* Use cartridge error services here */; + return(rval); + } + + /*********************************************/ + /* Generate the SQL statement to be executed */ + /*********************************************/ + if (memcmp((dvoid *)OCIStringPtr(envhp, pr->ObjectName), (dvoid *)"EQ", 2) + == 0) + if (strtval == 1) + strcpy(relop, (char *)"="); + else + strcpy(relop, (char *)"!="); + else if (memcmp((dvoid *)OCIStringPtr(envhp, pr->ObjectName), (dvoid *)"LT", + 2) == 0) + if (strtval == 1) + strcpy(relop, (char *)"<"); + else + strcpy(relop, (char *)">="); + else + if (strtval == 1) + strcpy(relop, (char *)">"); + else + strcpy(relop, (char *)"<="); + + sprintf(selstmt, "select f2 from %s.%s_sbtree where f1 %s :val", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName), relop); + + /***********************************/ + /* Parse, bind, define and execute */ + /***********************************/ + /* allocate stmt handle */ + if (qxiqtce(ctx, errhp, + OCIHandleAlloc((dvoid *)envhp, (dvoid **)&(icx->stmthp), + (ub4)OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0))) + return(rval); + /* prepare the statement */ + if (qxiqtce(ctx, errhp, OCIStmtPrepare(icx->stmthp, errhp, (text *)selstmt, + (ub4)strlen(selstmt), OCI_NTV_SYNTAX, + OCI_DEFAULT))) + return(rval); + + /* Set up bind */ + if (qxiqtce(ctx, errhp, + OCIBindByPos(icx->stmthp, &(icx->bndp), errhp, (ub4)1, + (dvoid *)cmpval, + (sb4)(strlen(cmpval)+1), + (ub2)SQLT_STR, (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Set up define */ + if (qxiqtce(ctx, errhp, OCIDefineByPos(icx->stmthp, &(icx->defnp), errhp, + (ub4)1, (dvoid *)(icx->ridp), + (sb4) sizeof(icx->ridp), + (ub2)SQLT_STR, (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)OCI_DEFAULT))) + return(rval); + + /* execute */ + if (qxiqtce(ctx, errhp, OCIStmtExecute(svchp, icx->stmthp, errhp, (ub4)0, + (ub4)0, (OCISnapshot *)NULL, + (OCISnapshot *)NULL, + (ub4)OCI_DEFAULT))) + return(rval); + + /************************************/ + /* Set index context to be returned */ + /************************************/ + /* generate a key */ + if (qxiqtce(ctx, errhp, OCIContextGenerateKey((dvoid *)usrhp, errhp, &key))) + return(rval); + /* set the memory address of the struct to be saved in the context */ + if (qxiqtce(ctx, errhp, OCIContextSetValue((dvoid *)usrhp, errhp, + OCI_DURATION_STATEMENT, + (ub1 *)&key, (ub1)sizeof(key), + (dvoid *)icx))) + return(rval); + /* set the key as the member of "sctx" */ + if (qxiqtce(ctx, errhp, OCIRawAssignBytes(envhp, errhp, (ub1 *)&key, + (ub4)sizeof(key), + &(sctx->sctx_qxiqtim)))) + return(rval); + + sctx_ind->atomic_qxiqtin = OCI_IND_NOTNULL; + sctx_ind->scind_qxiqtin = OCI_IND_NOTNULL; + + return(rval); +} + + +/* ODCIIndexFetch function */ +OCINumber *qxiqtbf(ctx, self, self_ind, nrows, nrows_ind, rids, rids_ind) +OCIExtProcContext *ctx; +qxiqtim *self; +qxiqtin *self_ind; +OCINumber *nrows; +short nrows_ind; +OCIArray **rids; +short *rids_ind; +{ + sword status; + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCISession *usrhp = (OCISession *) 0; /* user handle */ + qxiqtcx *icx = (qxiqtcx *) 0; /* state to be saved for later calls */ + + int idx = 1; + int nrowsval; + + OCIArray *ridarrp = *rids; /* rowid collection */ + OCIString *ridstr = (OCIString *)0; + + int done = 0; + int retval = (int)ODCI_SUCCESS; + OCINumber *rval = (OCINumber *)0; + + ub1 *key; /* key to retrieve context */ + ub4 keylen; /* length of key */ + + /*******************/ + /* Get OCI handles */ + /*******************/ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, + OCINumberFromInt(errhp, (dvoid *)&retval, sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /* get the user handle */ + if (qxiqtce(ctx, errhp, OCIAttrGet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)&usrhp, (ub4 *)0, + (ub4)OCI_ATTR_SESSION, errhp))) + return(rval); + + /********************************/ + /* Retrieve context from key */ + /********************************/ + key = OCIRawPtr(envhp, self->sctx_qxiqtim); + keylen = OCIRawSize(envhp, self->sctx_qxiqtim); + + if (qxiqtce(ctx, errhp, OCIContextGetValue((dvoid *)usrhp, errhp, + key, (ub1)keylen, + (dvoid **)&(icx)))) + return(rval); + + /* get value of nrows */ + if (qxiqtce(ctx, errhp, OCINumberToInt(errhp, nrows, sizeof(nrowsval), + OCI_NUMBER_SIGNED, (dvoid *)&nrowsval))) + return(rval); + + /****************/ + /* Fetch rowids */ + /****************/ + while (!done) + { + if (idx > nrowsval) + done = 1; + else + { + status = OCIStmtFetch(icx->stmthp, errhp, (ub4)1, (ub2) 0, + (ub4)OCI_DEFAULT); + if (status == OCI_NO_DATA) + { + short col_ind = OCI_IND_NULL; + /* have to create dummy oci string */ + OCIStringAssignText(envhp, errhp, (text *)"dummy", + (ub2)5, &ridstr); + /* append null element to collection */ + if (qxiqtce(ctx, errhp, OCICollAppend(envhp, errhp,(dvoid *)ridstr, + (dvoid *)&col_ind, + (OCIColl *)ridarrp))) + return(rval); + done = 1; + } + else if (status == OCI_SUCCESS) + { + OCIStringAssignText(envhp, errhp, (text *)icx->ridp, + (ub2)18, (OCIString **)&ridstr); + /* append rowid to collection */ + if (qxiqtce(ctx, errhp, OCICollAppend(envhp, errhp, (dvoid *)ridstr, + (dvoid *)0, (OCIColl *)ridarrp))) + return(rval); + idx++; + } + else if (qxiqtce(ctx, errhp, status)) + return(rval); + } + } + + /* free ridstr finally */ + if (ridstr && + (qxiqtce(ctx, errhp, OCIStringResize(envhp, errhp, (ub4)0, + &ridstr)))) + return(rval); + + *rids_ind = OCI_IND_NOTNULL; + + return(rval); +} + + +/* ODCIIndexClose function */ +OCINumber *qxiqtbc(ctx, self, self_ind) +OCIExtProcContext *ctx; +qxiqtim *self; +qxiqtin *self_ind; +{ + sword status; + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCISession *usrhp = (OCISession *) 0; /* user handle */ + qxiqtcx *icx = (qxiqtcx *) 0; /* state to be saved for later calls */ + + int retval = (int) ODCI_SUCCESS; + OCINumber *rval = (OCINumber *)0; + + ub1 *key; /* key to retrieve context */ + ub4 keylen; /* length of key */ + + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /* get the user handle */ + if (qxiqtce(ctx, errhp, OCIAttrGet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)&usrhp, (ub4 *)0, + (ub4)OCI_ATTR_SESSION, errhp))) + return(rval); + + /********************************/ + /* Retrieve context using key */ + /********************************/ + key = OCIRawPtr(envhp, self->sctx_qxiqtim); + keylen = OCIRawSize(envhp, self->sctx_qxiqtim); + + if (qxiqtce(ctx, errhp, OCIContextGetValue((dvoid *)usrhp, errhp, + key, (ub1)keylen, + (dvoid **)&(icx)))) + return(rval); + + /* Free handles and memory */ + if (qxiqtce(ctx, errhp, OCIHandleFree((dvoid *)icx->stmthp, + (ub4)OCI_HTYPE_STMT))) + return(rval); + + if (qxiqtce(ctx, errhp, OCIMemoryFree((dvoid *)usrhp, errhp, (dvoid *)icx))) + return(rval); + + return(rval); +} + + +/*--------------------------------------------------------------------------- + PRIVATE FUNCTIONS + ---------------------------------------------------------------------------*/ +static int qxiqtce(ctx, errhp, status) +OCIExtProcContext *ctx; +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + int errnum = 29400; /* choose some oracle error number */ + int rc = 0; + + switch (status) + { + case OCI_SUCCESS: + rc = 0; + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4)1, (text *)NULL, &errcode, + errbuf, (ub4)sizeof(errbuf), OCI_HTYPE_ERROR); + OCIExtProcRaiseExcpWithMsg(ctx, errnum, errbuf, strlen((char *)errbuf)); + rc = 1; + break; + default: + (void) sprintf((char *)errbuf, "Warning - some error\n"); + OCIExtProcRaiseExcpWithMsg(ctx, errnum, errbuf, strlen((char *)errbuf)); + rc = 1; + break; + } + return (rc); +} + +/* end of file extdemo2.c */ + diff --git a/extdemo2.h b/extdemo2.h new file mode 100644 index 0000000..cc22b0d --- /dev/null +++ b/extdemo2.h @@ -0,0 +1,167 @@ +/* + * $Header: extdemo2.h 14-jul-99.12:48:29 mjaeger Exp $ + */ + +/* Copyright (c) 1998, 1999, Oracle Corporation. All rights reserved. +*/ + +/* + NAME + extdemo2.h - Extensible Indexing example implemented as C routines + + DESCRIPTION + This file contains the definitions of the DML and Query routines + for the extensible indexing example that implements a simple btree + (sbtree). See extdemo2.sql for the SQL script that defines the + indextype. + + RELATED DOCUMENTS + + INSPECTION STATUS + Inspection date: + Inspection status: + Estimated increasing cost defects per page: + Rule sets: + + ACCEPTANCE REVIEW STATUS + Review date: + Review status: + Reviewers: + + PUBLIC FUNCTION(S) + qxiqtbs - QXIQT Btree Start routine + qxiqtbf - QXIQT Btree Fetch routine + qxiqtbc - QXIQT Btree Close routine + qxiqtbi - QXIQT Btree Insert routine + qxiqtbd - QXIQT Btree Delete routine + qxiqtbu - QXIQT Btree Update routine + + PRIVATE FUNCTION(S) + qxiqtbe - QXIQT error reporting routine + + EXAMPLES + + NOTES + + + MODIFIED (MM/DD/YY) + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + hdnguyen 04/02/99 - merged khackel fix in + khackel 02/03/99 - WIN32COMMON: added dllexport for public functions + rmurthy 06/16/98 - Creation + +*/ + + +#ifndef EXTDEMO2_ORACLE +# define EXTDEMO2_ORACLE + +#ifndef OCI_ORACLE +# include +#endif +#ifndef ODCI_ORACLE +# include +#endif + +/*--------------------------------------------------------------------------- + PUBLIC TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + +#ifdef WIN32COMMON +#define DLLEXPORT __declspec(dllexport) +#else +#define DLLEXPORT +#endif + +/* index scan context - should be stored in "statement" duration memory + * and used by start, fetch and close routines. + */ +struct qxiqtcx +{ + OCIStmt *stmthp; + OCIDefine *defnp; + OCIBind *bndp; + char ridp[19]; +}; +typedef struct qxiqtcx qxiqtcx; + +/* The index implementation type is an ADT with a single RAW attribute + * which will be used to store the context key value. + * C mapping of the implementation type : + */ +struct qxiqtim +{ + OCIRaw *sctx_qxiqtim; +}; +typedef struct qxiqtim qxiqtim; + +struct qxiqtin +{ + short atomic_qxiqtin; + short scind_qxiqtin; +}; +typedef struct qxiqtin qxiqtin; + +/*--------------------------------------------------------------------------- + PUBLIC FUNCTIONS + ---------------------------------------------------------------------------*/ +/* ODCIIndexStart */ +OCINumber DLLEXPORT *qxiqtbs(/*_ OCIExtProcContext *ctx, + struct qxiqtim *sctx, struct qxiqtin *sctx_ind, + ODCIIndexInfo *ix, dvoid *ix_ind, + ODCIPredInfo *pr, dvoid *pr_ind, + ODCIQueryInfo *qy, dvoid *qy_ind, + OCINumber *strt, short strt_ind, + OCINumber *stop, short stop_ind, + char *cmpval, short cmpval_ind _*/); + +/* ODCIIndexFetch */ +OCINumber DLLEXPORT *qxiqtbf(/*_ OCIExtProcContext *ctx, + struct qxiqtim *self, struct qxiqtin *self_ind, + OCINumber *nrows, short nrows_ind, + OCIArray **rids, short *rids_ind _*/); + +/* ODCIIndexClose */ +OCINumber DLLEXPORT *qxiqtbc(/*_ OCIExtProcContext *ctx, + struct qxiqtim *self, struct qxiqtin *self_ind _*/); + +/* ODCIIndexInsert */ +OCINumber DLLEXPORT *qxiqtbi(/*_ OCIExtProcContext *ctx, + ODCIIndexInfo *ix, + ODCIIndexInfo_ind *ix_ind, + char *rid, + short rid_ind, + char *newval, + short newval_ind _*/); + +/* ODCIIndexDelete */ +OCINumber DLLEXPORT *qxiqtbd(/*_ OCIExtProcContext *ctx, + ODCIIndexInfo *ix, + ODCIIndexInfo_ind *ix_ind, + char *rid, + short rid_ind, + char *oldval, + short oldval_ind _*/); + +/* ODCIIndexUpdate */ +OCINumber DLLEXPORT *qxiqtbu(/*_ OCIExtProcContext *ctx, + ODCIIndexInfo *ix, + ODCIIndexInfo_ind *ix_ind, + char *rid, + short rid_ind, + char *oldval, + short oldval_ind, + char *newval, + short newval_ind _*/); + +/*--------------------------------------------------------------------------- + PRIVATE FUNCTIONS + ---------------------------------------------------------------------------*/ +static int qxiqtce(/*_ OCIExtProcContext *ctx, OCIError *errhp, + sword status _*/); + +#endif /* EXTDEMO2_ORACLE */ diff --git a/extdemo2.sql b/extdemo2.sql new file mode 100644 index 0000000..332ee11 --- /dev/null +++ b/extdemo2.sql @@ -0,0 +1,421 @@ +rem +rem $Header: extdemo2.sql 09-mar-2001.14:56:24 rmurthy Exp $ +rem +rem extdemo2.sql +rem +rem Copyright (c) 1998, 1999,, 2000 Oracle Corporation. All rights reserved. +rem +rem NAME +rem extdemo2.sql - An extensible indexing example +rem implemented as C routines +rem +rem DESCRIPTION +rem This file demonstrates the definition and usage of a simple +rem btree indextype whose routines are implemented as C callouts. +rem The C routines are in the file extdemo2.c +rem The header file is extdemo2.h +rem +rem The foll. steps should have been done before running +rem this script. +rem 1. Compile the C file (i.e make -f demo_rdbms.mk demos) +rem 2. Create a user named extdemo2 with password extdemo2 +rem 3. Create a library in extdemo2 schema called extdemo2l +rem which points to the compiled extdemo2.c +rem +rem The design of the indextype is as follows : +rem +rem The sbtree indextype implemented here will support the evaluation +rem of three user-defined operators : gt(Greater Than), lt(Less Than) +rem and eq(EQuals). These operators can operate on the operands of +rem VARCHAR2 datatype. +rem To simplify the implementation of the indextype, we will store +rem the index data in a regular table. +rem Thus, our code merely translates operations on the SB-tree into +rem operations on the table storing the index data. +rem When a user creates a SB-tree index, we will create a table +rem consisting of the indexed column and a rowid column. Inserts into +rem the base table will cause appropriate insertions into the index table. +rem Deletes and updates are handled similarly. +rem When the SB-tree is queried based on a user-defined operator (one +rem of gt, lt and eq), we will fire off an appropriate query against +rem the index table to retrieve all the satisfying rows and return them. +rem +rem MODIFIED (MM/DD/YY) +rem rmurthy 03/09/01 - bug 1676437 - change call to extdemo0 +rem rmurthy 01/13/00 - add path name while calling utlxplan +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem hdnguyen 07/26/99 - sqlplus conversion +rem hdnguyen 06/15/99 - modified step 1 to add compile instruction +rem rmurthy 09/25/98 - Created + +--------------------------------------------------------------------- +-- SIMPLE B-TREE Index Method Implemented as C Callouts -- +--------------------------------------------------------------------- + +connect extdemo2/extdemo2 +set echo off +@'?/rdbms/admin/utlxplan.sql' +set echo on + +-- CREATE FUNCTIONAL IMPLEMENTATIONS for operators + +create function bt_eq(a varchar2, b varchar2) return number as +begin + if a = b then + return 1; + else + return 0; + end if; +end; +/ +show errors + +create function bt_lt(a varchar2, b varchar2) return number as +begin + if a < b then + return 1; + else + return 0; + end if; +end; +/ +show errors + +create function bt_gt(a varchar2, b varchar2) return number as +begin + if a > b then + return 1; + else + return 0; + end if; +end; +/ +show errors + +-- CREATE BTREE OPERATORS + +create operator eq binding (varchar2, varchar2) return number using bt_eq; + +create operator lt binding (varchar2, varchar2) return number using bt_lt; + +create operator gt binding (varchar2, varchar2) return number using bt_gt; + + +-- CREATE INDEXTYPE IMPLEMENTATION TYPE +create type sbtree_im as object +( + scanctx RAW(4), + static function ODCIGetInterfaces(ifclist OUT sys.ODCIObjectList) + return NUMBER, + static function ODCIIndexCreate (ia sys.odciindexinfo, parms varchar2) + return number, + static function ODCIIndexDrop(ia sys.odciindexinfo) return number, + STATIC FUNCTION odciindexinsert(ia sys.odciindexinfo, rid VARCHAR2, + newval VARCHAR2) + RETURN NUMBER, + STATIC FUNCTION odciindexdelete(ia sys.odciindexinfo, rid VARCHAR2, + oldval VARCHAR2) + RETURN NUMBER, + STATIC FUNCTION odciindexupdate(ia sys.odciindexinfo, rid VARCHAR2, + oldval VARCHAR2, newval VARCHAR2) + RETURN NUMBER, + static function ODCIIndexStart(sctx IN OUT sbtree_im, ia sys.odciindexinfo, + op sys.odciPredInfo, qi sys.ODCIQueryInfo, + strt number, stop number, + cmpval varchar2) return number, + member function ODCIIndexFetch(nrows number, rids OUT sys.odciridlist) + return number, + member function ODCIIndexClose return number +); +/ +show errors + + +--------------------------------- +-- CREATE IMPLEMENTATION UNIT -- +--------------------------------- + +-- CREATE TYPE BODY +create or replace type body sbtree_im +is + static function ODCIGetInterfaces(ifclist OUT sys.ODCIObjectList) + return number is + begin + ifclist := sys.ODCIObjectList(sys.ODCIObject('SYS','ODCIINDEX1')); + return ODCIConst.Success; + end ODCIGetInterfaces; + + static function ODCIIndexCreate (ia sys.odciindexinfo, parms varchar2) + return number + is + i integer; + stmt varchar2(1000); + cnum integer; + junk integer; + begin + -- construct the sql statement + stmt := 'create table ' || ia.IndexSchema || '.' || + ia.IndexName || '_sbtree' || + '( f1 , f2 ) as select ' || + ia.IndexCols(1).ColName || ', ROWID from ' || + ia.IndexCols(1).TableSchema || '.' || ia.IndexCols(1).TableName; + + dbms_output.put_line('CREATE'); + dbms_output.put_line(stmt); + + -- execute the statement + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + + return ODCIConst.Success; + end; + + static function ODCIIndexDrop(ia sys.odciindexinfo) return number is + stmt varchar2(1000); + cnum integer; + junk integer; + begin + -- construct the sql statement + stmt := 'drop table ' || ia.IndexSchema || '.' || ia.IndexName || '_sbtree'; + + dbms_output.put_line('DROP'); + dbms_output.put_line(stmt); + + -- execute the statement + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + + return ODCIConst.Success; + end; + + STATIC FUNCTION odciindexinsert(ia sys.odciindexinfo, rid VARCHAR2, + newval VARCHAR2) + RETURN NUMBER AS external + name "qxiqtbi" + library extdemo2l + WITH context + parameters ( + context, + ia, + ia indicator struct, + rid, + rid indicator, + newval, + newval indicator, + RETURN ocinumber + ); + + STATIC FUNCTION odciindexdelete(ia sys.odciindexinfo, rid VARCHAR2, + oldval VARCHAR2) + RETURN NUMBER AS external + name "qxiqtbd" + library extdemo2l + WITH context + parameters ( + context, + ia, + ia indicator struct, + rid, + rid indicator, + oldval, + oldval indicator, + RETURN ocinumber + ); + + STATIC FUNCTION odciindexupdate(ia sys.odciindexinfo, rid VARCHAR2, + oldval VARCHAR2, newval VARCHAR2) + RETURN NUMBER AS external + name "qxiqtbu" + library extdemo2l + WITH context + parameters ( + context, + ia, + ia indicator struct, + rid, + rid indicator, + oldval, + oldval indicator, + newval, + newval indicator, + RETURN ocinumber + ); + + static function ODCIIndexStart(sctx in out sbtree_im, ia sys.odciindexinfo, + op sys.odciPredInfo, + qi sys.ODCIQueryInfo, + strt number, + stop number, + cmpval varchar2) + return number as external + name "qxiqtbs" + library extdemo2l + with context + parameters ( + context, + sctx, + sctx INDICATOR STRUCT, + ia, + ia INDICATOR STRUCT, + op, + op INDICATOR STRUCT, + qi, + qi INDICATOR STRUCT, + strt, + strt INDICATOR, + stop, + stop INDICATOR, + cmpval, + cmpval INDICATOR, + return OCINumber + ); + + member function ODCIIndexFetch(nrows number, rids OUT sys.odciridlist) + return number as external + name "qxiqtbf" + library extdemo2l + with context + parameters ( + context, + self, + self INDICATOR STRUCT, + nrows, + nrows INDICATOR, + rids, + rids INDICATOR, + return OCINumber + ); + + member function ODCIIndexClose return number as external + name "qxiqtbc" + library extdemo2l + with context + parameters ( + context, + self, + self INDICATOR STRUCT, + return OCINumber + ); + +end; +/ +show errors + +--------------------- +-- CREATE INDEXTYPE +--------------------- + +create indextype sbtree +for +eq(varchar2, varchar2), +lt(varchar2, varchar2), +gt(varchar2, varchar2) +using sbtree_im; + +-------------------------- +-- USAGE EXAMPLES -- +-------------------------- +set serveroutput on size 20000 + +---------------- +-- CREATE TABLE +---------------- + +create table t1 (f1 number, f2 varchar2(200)); +insert into t1 values (1, 'ravi'); +insert into t1 values (3, 'murthy'); +commit; + +----------------- +-- CREATE INDEX +----------------- + +create index it1 on t1(f2) indextype is sbtree parameters('test'); + +------------ +-- QUERIES +------------ + +explain plan for +select * from t1 where eq(f2, 'ravi') = 1; +set echo off +@@extdemo0 +set echo on +select * from t1 where eq(f2, 'ravi') = 1; + +explain plan for +select * from t1 where gt(f2, 'aaa') = 1; +set echo off +@@extdemo0 +set echo on +select * from t1 where gt(f2, 'aaa') = 1; + +explain plan for +select * from t1 where lt(f2, 'aaa') = 1; +set echo off +@@extdemo0 +set echo on +select * from t1 where lt(f2, 'aaa') = 1; + +explain plan for +select * from t1 where lt(f2, 'aaa') = 0; +set echo off +@@extdemo0 +set echo on +select * from t1 where lt(f2, 'aaa') = 0; + +----------- +-- INSERTS +----------- + +INSERT INTO t1 VALUES (6, 'cheuk'); +INSERT INTO t1 VALUES (7, 'chau'); +explain plan for +select * from t1 where eq(f2, 'cheuk') = 1; +set echo off +@@extdemo0 +set echo on +select * from t1 where eq(f2, 'cheuk') = 1; + +----------- +-- DELETES +----------- + +DELETE FROM t1 WHERE f2 = 'ravi'; +explain plan for +select * from t1 where eq(f2, 'ravi') = 1; +set echo off +@@extdemo0 +set echo on +select * from t1 where eq(f2, 'ravi') = 1; + +----------- +-- UPDATES +----------- + +UPDATE t1 SET f2 = 'Nipun' WHERE f1 = 3; +explain plan for +select * from t1 where eq(f2, 'Nipun') = 1; +set echo off +@@extdemo0 +set echo on +select * from t1 where eq(f2, 'Nipun') = 1; + +------------ +-- CLEANUPS +------------ + +drop index it1; +drop table t1; +drop indextype sbtree; +drop type sbtree_im; +drop operator eq; +drop operator lt; +drop operator gt; +drop function bt_eq; +drop function bt_lt; +drop function bt_gt; diff --git a/extdemo3.java b/extdemo3.java new file mode 100644 index 0000000..0a1dc8b --- /dev/null +++ b/extdemo3.java @@ -0,0 +1,408 @@ +/* $Header: extdemo3.java 30-mar-2006.18:37:53 yhu Exp $ */ + +/* Copyright (c) 1999, 2006, Oracle. All rights reserved. */ + +/* + DESCRIPTION + extdemo3.java - class that implements the ODCIIndex methods. + This class was originally generated using JPUB based + on the type that extensible index is based on. The + methods were implemented after the class was generated. + + PRIVATE CLASSES + + NOTES + + MODIFIED (MM/DD/YY) + yhu 03/30/06 - remove dependencies on classes12 + hdnguyen 08/10/01 - case sensitive fixes due to 9.0.2 regen of ODCIs + rshaikh 06/23/99 - create + rshaikh 06/23/99 - Creation + */ + +/** + * @version $Header: extdemo3.java 30-mar-2006.18:37:53 yhu Exp $ + * @author rshaikh + * @since release specific 8.1.6 + */ +import java.sql.SQLException; +import java.sql.Connection; +import oracle.jdbc.OracleTypes; +import oracle.sql.ORAData; +import oracle.sql.ORADataFactory; +import oracle.sql.Datum; +import oracle.sql.STRUCT; +import oracle.jpub.runtime.MutableStruct; + +import java.lang.*; +import java.sql.*; +import oracle.*; +import oracle.sql.*; +import oracle.jdbc.*; +import sqlj.runtime.ref.DefaultContext; +import sqlj.runtime.ConnectionContext; +import oracle.ODCI.*; +import oracle.CartridgeServices.*; + +public class extdemo3 implements ORAData, ORADataFactory +{ + public static final String _SQL_NAME = "EXTDEMO.EXTDEMO3"; + public static final int _SQL_TYPECODE = OracleTypes.STRUCT; + + final static java.math.BigDecimal SUCCESS = new java.math.BigDecimal("0"); + final static java.math.BigDecimal ERROR = new java.math.BigDecimal("1"); + final static int TRUE = 1; + final static int FALSE = 0; + + /* connection management */ + protected DefaultContext __tx = null; + protected Connection __onn = null; + public void setConnectionContext(DefaultContext ctx) throws SQLException + { release(); __tx = ctx; } + public DefaultContext getConnectionContext() throws SQLException + { if (__tx==null) + { __tx = (__onn==null) ? DefaultContext.getDefaultContext() : new DefaultContext(__onn); } + return __tx; + }; + public Connection getConnection() throws SQLException + { return (__onn==null) ? ((__tx==null) ? null : __tx.getConnection()) : __onn ; } + public void release() throws SQLException + { if (__tx!=null && __onn!=null) __tx.close(ConnectionContext.KEEP_CONNECTION ); + __onn = null; __tx = null; + } + + protected MutableStruct _struct; + + private static int[] _sqlType = { 4 }; + private static ORADataFactory[] _factory = new ORADataFactory[1]; + protected static final extdemo3 _extdemo3Factory = new extdemo3(false); + + public static ORADataFactory getORADataFactory() + { return _extdemo3Factory; } + + /* constructor */ + protected extdemo3(boolean init) + { if (init) _struct = new MutableStruct(new Object[1], _sqlType, _factory); } + public extdemo3() + { this(true); __tx = DefaultContext.getDefaultContext(); } + public extdemo3(DefaultContext c) throws SQLException + { this(true); __tx = c; } + public extdemo3(Connection c) throws SQLException + { this(true); __onn = c; } + + /* ORAData interface */ + public Datum toDatum(Connection c) throws SQLException + { + if (__tx!=null && __onn!=c) release(); + __onn = c; + return _struct.toDatum(c, _SQL_NAME); + } + + /* ORADataFactory interface */ + public ORAData create(Datum d, int sqlType) throws SQLException + { return create(null, d, sqlType); } + public void setFrom(extdemo3 o) throws SQLException + { release(); _struct = o._struct; __tx = o.__tx; __onn = o.__onn; } + protected void setValueFrom(extdemo3 o) { _struct = o._struct; } + protected ORAData create(extdemo3 o, Datum d, int sqlType) throws SQLException + { + if (d == null) { if (o!=null) { o.release(); }; return null; } + if (o == null) o = new extdemo3(false); + o._struct = new MutableStruct((STRUCT) d, _sqlType, _factory); + o.__onn = ((STRUCT) d).getJavaSqlConnection(); + return o; + } + + /* accessor methods */ + public Integer getScanctx() throws SQLException + { return (Integer) _struct.getAttribute(0); } + + public void setScanctx(Integer scanctx) throws SQLException + { _struct.setAttribute(0, scanctx); } + + // ODCIIndexStart + public static java.math.BigDecimal ODCIStart(extdemo3 sctx[], + ODCIIndexInfo ia, ODCIPredInfo op, + ODCIQueryInfo qi, + java.math.BigDecimal strt, java.math.BigDecimal stop, + String cmpval) + throws java.sql.SQLException + { + String relop; + String selstmt; + int key; + extdemo3a sbtctx; // cntxt obj that holds the ResultSet and Statement + PreparedStatement ps; + OracleResultSet rset; + + Connection conn = + sqlj.runtime.RuntimeContext.getRuntime().getDefaultConnection(); + + + CallableStatement cstmt = conn.prepareCall + ("{CALL dbms_output.put_line(\'Start \')}"); + cstmt.executeUpdate(); + + //*********************************** + //* Check that the bounds are valid * + //*********************************** + // verify that strtval/stopval are both either 0 or 1 + if (!(((strt.intValue() == 0) && (stop.intValue() == 0)) || + ((strt.intValue() == 1) && (stop.intValue() == 1)))) + { + // throw Application_Error + System.out.println("incorrect predicate for btree operator"); + return ERROR; + } + + String s = new String("start key: "+ strt.intValue() + " stop key: " + + stop.intValue() + " compare value: " + cmpval); + cstmt = conn.prepareCall + ("{CALL dbms_output.put_line(?)}"); + cstmt.setString(1, s); + cstmt.executeUpdate(); + + //********************************************* + //* Generate the SQL statement to be executed * + //********************************************* + if ((op.getObjectName()).equals("EQ")){ + if (strt.intValue() == 1) + relop = new String("="); + else + relop = new String("!="); + }else if ((op.getObjectName()).equals("LT")){ + if (strt.intValue() == 1) + relop = new String("<"); + else + relop = new String(">="); + }else{ + if (strt.intValue() == 1) + relop = new String(">"); + else + relop = new String("<="); + } + + selstmt = new String("select ROWIDTOCHAR(f2) from " + + ia.getIndexSchema() + + "." + + ia.getIndexName() + + "_sbtree where f1 " + + relop + " '" + cmpval + "'"); + cstmt = conn.prepareCall + ("{CALL dbms_output.put_line(?)}"); + cstmt.setString(1, selstmt); + cstmt.executeUpdate(); + + + ps = conn.prepareStatement(selstmt); + rset = (OracleResultSet) ps.executeQuery(); + + // set result set in ContextManager. This stores away the + // ResultSet and the Statement handle so that they can + // be used to fetch the rowids and cleanup at a later time. + sbtctx = new extdemo3a(rset, ps); + sctx[0] = new extdemo3(); + + try{ + key = ContextManager.setContext((Object)sbtctx); + }catch (CountException ce) { + System.out.println("ContextManager CountException error"); + return ERROR; + } + + System.out.println("ContextManager key=" + key); + + // set the key into the self argument so that we can retrieve the + // context with this key later. + sctx[0].setScanctx(new Integer(key)); + + return SUCCESS; + } + + // ODCIIndexFetch + public java.math.BigDecimal ODCIFetch( + java.math.BigDecimal nrows, + ODCIRidList rids[]) + throws java.sql.SQLException + { + extdemo3a sbtctx; // cntxt obj that holds the ResultSet and Statement + OracleResultSet rset; + String rid; + int idx = 1; + int done = FALSE; + String[] rlist = new String[nrows.intValue()]; + int key = getScanctx().intValue(); + + Connection conn = + sqlj.runtime.RuntimeContext.getRuntime().getDefaultConnection(); + CallableStatement cstmt = conn.prepareCall + ("{CALL dbms_output.put_line(\'Fetch \')}"); + cstmt.executeUpdate(); + + String s = new String("nrows : " + nrows); + cstmt = conn.prepareCall + ("{CALL dbms_output.put_line(?)}"); + cstmt.setString(1, s); + cstmt.executeUpdate(); + + System.out.println("ContextManager key=" + key); + + // Get the resultSet back from the ContextManager using the key + try{ + sbtctx= (extdemo3a)ContextManager.getContext(key); + }catch(InvalidKeyException ike){ + System.out.println("ContextManager InvalidKeyException"); + return ERROR; + } + rset = (OracleResultSet)(sbtctx.getRs()); + + //*************** + // Fetch rowids * + //*************** + for(int i=0; done != TRUE; i++) + { + if (idx > nrows.intValue()){ + done = TRUE; + }else { + if (rset.next()){ + // append rowid to collection + rid = rset.getString(1); + rlist[i] = new String(rid); + idx++; + }else{ + // append null rowid to collection + rlist[i] = null; + done = TRUE; + } + } + } + + // Since rids is an out parameter we need to set the ODCIRidList + // object into the first position to be passed out. + rids[0] = new ODCIRidList(rlist); + + return SUCCESS; + } + + // ODCIIndexClose + public java.math.BigDecimal ODCIClose() + throws java.sql.SQLException + { + extdemo3a sbtctx; // contxt obj that holds the ResultSet and Statement + OracleResultSet rset; + PreparedStatement ps; + System.out.println("in odciclose"); + + int key = getScanctx().intValue(); + System.out.println("in odciclose2"); + + Connection conn = + sqlj.runtime.RuntimeContext.getRuntime().getDefaultConnection(); + CallableStatement cstmt = conn.prepareCall + ("{CALL dbms_output.put_line(\'Close\')}"); + cstmt.executeUpdate(); + + System.out.println("key=" + key); + + // Get the resultSet and statement back from the ContextManager + // so that we can close them. + try{ + sbtctx = (extdemo3a)ContextManager.clearContext(key); + }catch(InvalidKeyException ike){ + System.out.println("ContextManager InvalidKeyException"); + return ERROR; + } + + rset = (OracleResultSet)sbtctx.getRs(); + ps = (PreparedStatement)sbtctx.getStmt(); + rset.close(); + ps.close(); + + return SUCCESS; + } + + // ODCIIndexInsert + public static java.math.BigDecimal ODCIInsert( + ODCIIndexInfo ia, String rid, String newval) + throws java.sql.SQLException + { + String insstmt; + + Connection conn = + sqlj.runtime.RuntimeContext.getRuntime().getDefaultConnection(); + CallableStatement cstmt = conn.prepareCall + ("{CALL dbms_output.put_line(\'Insert\')}"); + cstmt.executeUpdate(); + + /****************************** + * Construct insert Statement * + ******************************/ + insstmt = new String("INSERT into " + + ia.getIndexSchema() + "." + ia.getIndexName() + +"_sbtree values ('" + newval + "','" + rid + "')" ); + + Statement stmt = conn.createStatement(); + stmt.executeUpdate(insstmt); + stmt.close(); + + return SUCCESS; + } + + // ODCIIndexDelete + public static java.math.BigDecimal ODCIDelete( + ODCIIndexInfo ia, String rid, String oldval) + throws java.sql.SQLException + { + + String delstmt; + + Connection conn = + sqlj.runtime.RuntimeContext.getRuntime().getDefaultConnection(); + CallableStatement cstmt = conn.prepareCall + ("{CALL dbms_output.put_line(\'Delete\')}"); + cstmt.executeUpdate(); + + /****************************** + * Construct delete Statement * + ******************************/ + delstmt = new String("DELETE from " + + ia.getIndexSchema() + "." + ia.getIndexName() + +"_sbtree where f1= '" + oldval +"'" ); + + Statement stmt = conn.createStatement(); + stmt.executeUpdate(delstmt); + stmt.close(); + + return SUCCESS; + } + + // ODCIIndexUpdate + public static java.math.BigDecimal ODCIUpdate( + ODCIIndexInfo ia, String rid, String oldval, + String newval) + throws java.sql.SQLException + { + String updstmt; + + Connection conn = + sqlj.runtime.RuntimeContext.getRuntime().getDefaultConnection(); + CallableStatement cstmt = conn.prepareCall + ("{CALL dbms_output.put_line(\'Update\')}"); + cstmt.executeUpdate(); + + /****************************** + * Construct update Statement * + ******************************/ + updstmt = new String("UPDATE " + + ia.getIndexSchema() + "." + ia.getIndexName() + +"_sbtree SET f1= '" + newval + "' WHERE f1 = '" + + oldval +"'"); + + Statement stmt = conn.createStatement(); + stmt.executeUpdate(updstmt); + stmt.close(); + + return SUCCESS; + } + +} diff --git a/extdemo3.sql b/extdemo3.sql new file mode 100644 index 0000000..149717b --- /dev/null +++ b/extdemo3.sql @@ -0,0 +1,313 @@ +Rem +Rem $Header: extdemo3.sql 09-mar-2001.14:56:30 rmurthy Exp $ +Rem +Rem extdemo3.sql +Rem +Rem Copyright (c) Oracle Corporation 1999, 2000. All Rights Reserved. +Rem +rem NAME +rem extdemo3.sql - An extensible indexing example +rem implemented as Java callouts. +rem +rem DESCRIPTION +rem This file demonstrates the definition and usage of a simple +rem btree indextype whose routines are implemented as Java callouts. +rem +rem The Java methods are in the file extdemo3.java +rem The associated context class is in extdemo3a.java +rem +rem The foll. steps should have been done before running +rem this script. +rem 1. Compile the Java files +rem (i.e javac extdemo3a.java, javac extdemo3.java . Make +rem sure that the ORACLE_HOME/rdbms/jlib/ODCI.jar and +rem ORACLE_HOME/rdbms/jlib/CartridgeServices.jar files are in +rem your classpath and that these files have been loaded into the +rem database in SYS schema) +rem 2. Create a user named extdemo with password extdemo +rem 3. Grant create any directory privilege to extdemo +rem 3. Create a directory in extdemo schema called vmtestdir +rem which points to the directory containing the compiled +rem extdemo3.class and extdemo3a.class +rem +rem The design of the indextype is as follows : +rem +rem The sbtree indextype implemented here will support the evaluation +rem of three user-defined operators : gt(Greater Than), lt(Less Than) +rem and eq(EQuals). These operators can operate on the operands of +rem VARCHAR2 datatype. +rem To simplify the implementation of the indextype, we will store +rem the index data in a regular table. +rem Thus, our code merely translates operations on the SB-tree into +rem operations on the table storing the index data. +rem When a user creates a SB-tree index, we will create a table +rem consisting of the indexed column and a rowid column. Inserts into +rem the base table will cause appropriate insertions into the index table. +rem Deletes and updates are handled similarly. +rem When the SB-tree is queried based on a user-defined operator (one +rem of gt, lt and eq), we will fire off an appropriate query against +rem the index table to retrieve all the satisfying rows and return them. +Rem +Rem MODIFIED (MM/DD/YY) +Rem rmurthy 03/09/01 - bug 1676437 - change call to extdemo0 +Rem hdnguyen 11/14/00 - fixed connect internal +Rem rmurthy 01/12/00 - add path name while calling utlxplan +Rem hdnguyen 09/16/99 - Use extdemo0 +Rem rshaikh 09/13/99 - Created +Rem + +--------------------------------------------------------------------- +-- SIMPLE B-TREE Index Method Implemented as Trusted Callouts -- +--------------------------------------------------------------------- +connect extdemo/extdemo +set echo off +@'?/rdbms/admin/utlxplan.sql' +set echo on + +-- CREATE FUNCTIONAL IMPLEMENTATIONS for operators + +create function bt_eq(a varchar2, b varchar2) return number as +begin + if a = b then + return 1; + else + return 0; + end if; +end; +/ +show errors + +create function bt_lt(a varchar2, b varchar2) return number as +begin + if a < b then + return 1; + else + return 0; + end if; +end; +/ +show errors + +create function bt_gt(a varchar2, b varchar2) return number as +begin + if a > b then + return 1; + else + return 0; + end if; +end; +/ +show errors + +-- CREATE BTREE OPERATORS + +create operator eq binding (varchar2, varchar2) return number using bt_eq; + +create operator lt binding (varchar2, varchar2) return number using bt_lt; + +create operator gt binding (varchar2, varchar2) return number using bt_gt; + + +-- CREATE INDEXTYPE IMPLEMENTATION TYPE +create or replace type extdemo3 as object +( + scanctx integer, + static function ODCIGetInterfaces(ifclist OUT sys.ODCIObjectList) return NUMBER, + static function ODCIIndexCreate (ia sys.odciindexinfo, parms varchar2) return number, + static function ODCIIndexDrop(ia sys.odciindexinfo) return number, + + STATIC FUNCTION odciindexinsert(ia sys.odciindexinfo, rid VARCHAR2, + newval VARCHAR2) + RETURN NUMBER AS LANGUAGE JAVA NAME + 'extdemo3.ODCIInsert(oracle.ODCI.ODCIIndexInfo, java.lang.String, + java.lang.String) return java.math.BigDecimal', + + STATIC FUNCTION odciindexdelete(ia sys.odciindexinfo, rid VARCHAR2, + oldval VARCHAR2) + RETURN NUMBER AS LANGUAGE JAVA NAME + 'extdemo3.ODCIDelete(oracle.ODCI.ODCIIndexInfo, java.lang.String, + java.lang.String) return java.math.BigDecimal', + + STATIC FUNCTION odciindexupdate(ia sys.odciindexinfo, rid VARCHAR2, + oldval VARCHAR2, newval VARCHAR2) + RETURN NUMBER AS LANGUAGE JAVA NAME + 'extdemo3.ODCIUpdate(oracle.ODCI.ODCIIndexInfo, java.lang.String, + java.lang.String, java.lang.String) return + java.math.BigDecimal', + + static function ODCIIndexStart(sctx in out extdemo3, ia sys.odciindexinfo, + op sys.odciPredInfo, + qi sys.ODCIQueryInfo, + strt number, + stop number, + cmpval varchar2) + RETURN NUMBER AS LANGUAGE JAVA NAME + 'extdemo3.ODCIStart(extdemo3[], oracle.ODCI.ODCIIndexInfo, + oracle.ODCI.ODCIPredInfo, + oracle.ODCI.ODCIQueryInfo, java.math.BigDecimal, + java.math.BigDecimal, + java.lang.String) return java.math.BigDecimal', + + member function ODCIIndexFetch(nrows number, rids OUT sys.odciridlist) + return number as LANGUAGE JAVA NAME + 'extdemo3.ODCIFetch(java.math.BigDecimal, + oracle.ODCI.ODCIRidList[]) return java.math.BigDecimal', + + member function ODCIIndexClose return number as LANGUAGE JAVA NAME + 'extdemo3.ODCIClose() return java.math.BigDecimal' + +); +/ +show errors + + +CREATE OR REPLACE JAVA CLASS USING BFILE (vmtestdir, 'extdemo3a.class') +/ +CREATE OR REPLACE JAVA CLASS USING BFILE (vmtestdir, 'extdemo3.class') +/ + +ALTER JAVA CLASS "extdemo3a" RESOLVE; +ALTER JAVA CLASS "extdemo3" RESOLVE; + + + + +--------------------------------- +-- CREATE IMPLEMENTATION UNIT -- +--------------------------------- + +-- CREATE TYPE BODY +create or replace type body extdemo3 +is + static function ODCIGetInterfaces(ifclist OUT sys.ODCIObjectList) + return number is + begin + ifclist := sys.ODCIObjectList(sys.ODCIObject('SYS','ODCIINDEX1')); + return ODCIConst.Success; + end ODCIGetInterfaces; + + static function ODCIIndexCreate (ia sys.odciindexinfo, parms varchar2) return number + is + i integer; + stmt varchar2(1000); + cnum integer; + junk integer; + begin + -- construct the sql statement + stmt := 'create table ' || ia.IndexSchema || '.' || + ia.IndexName || '_sbtree' || + '( f1 , f2 ) as select ' || + ia.IndexCols(1).ColName || ', ROWID from ' || + ia.IndexCols(1).TableSchema || '.' || ia.IndexCols(1).TableName; + + dbms_output.put_line('CREATE'); + dbms_output.put_line(stmt); + + -- execute the statement + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + + return ODCIConst.Success; + end; + + static function ODCIIndexDrop(ia sys.odciindexinfo) return number is + stmt varchar2(1000); + cnum integer; + junk integer; + begin + -- construct the sql statement + stmt := 'drop table ' || ia.IndexSchema || '.' || ia.IndexName || '_sbtree'; + + dbms_output.put_line('DROP'); + dbms_output.put_line(stmt); + + -- execute the statement + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + + return ODCIConst.Success; + end; + +end; +/ +show errors + +-------------------------- +-- USAGE EXAMPLES -- +-------------------------- + +-- CREATE INDEXTYPE +connect / as sysdba +grant create library to EXTDEMO; +grant create any directory to EXTDEMO; +grant create any operator, create indextype, create table to EXTDEMO; +connect extdemo/extdemo +set serveroutput on + +create indextype sbtree +for +eq(varchar2, varchar2), +lt(varchar2, varchar2), +gt(varchar2, varchar2) +using extdemo3; + +create table t1 (f1 number, f2 varchar2(200)); +insert into t1 values (1, 'ravi'); +insert into t1 values (3, 'murthy'); +commit; + +create index it1 on t1(f2) indextype is sbtree parameters('test'); + +-- query +explain plan for +select * from t1 where eq(f2, 'ravi') = 1; +set echo off +@@extdemo0 +set echo on + +select * from t1 where eq(f2, 'ravi') = 1; + +explain plan for +select * from t1 where gt(f2, 'aaa') = 1; +set echo off +@@extdemo0 +set echo on + +select * from t1 where gt(f2, 'aaa') = 1; + +-- INSERT TESTS +-- BUG 687446 +INSERT INTO t1 VALUES (6, 'cheuk'); +INSERT INTO t1 VALUES (7, 'chau'); + +-- query from index table +SELECT f1 FROM it1_sbtree; + +-- DELETE TEST +DELETE FROM t1 WHERE f2 = 'ravi'; + +-- query from index table +SELECT f1 FROM it1_sbtree; + +-- UPDATE TEST +UPDATE t1 SET f2 = 'Nipun' WHERE f1 = 3; + +-- query from index table +SELECT f1 FROM it1_sbtree; + +-- DROP TEST +drop table t1; + +describe t1; +describe it1; +describe it1_sbtree; + +drop index it1; +describe it1; +describe it1_sbtree; + + diff --git a/extdemo3a.java b/extdemo3a.java new file mode 100644 index 0000000..a57d393 --- /dev/null +++ b/extdemo3a.java @@ -0,0 +1,56 @@ +/* $Header: extdemo3a.java 30-mar-2006.18:38:05 yhu Exp $ */ + +/* Copyright (c) 1999, 2006, Oracle. All rights reserved. */ + +/* + DESCRIPTION + extdemo3a.java - class that holds the ResultSet and PreparedStatment + to be stored in CartridgeServices context + + MODIFIED (MM/DD/YY) + yhu 03/30/06 - remove dependencies on classes12 + rshaikh 06/24/99 - + rshaikh 06/23/99 - create + rshaikh 06/23/99 - Creation + */ + +/** + * @version $Header: extdemo3a.java 30-mar-2006.18:38:05 yhu Exp $ + * @author rshaikh + * @since release specific (what release of product did this appear in) + */ +import java.sql.SQLException; +import java.sql.Connection; +import oracle.jdbc.OracleTypes; +import oracle.sql.ORAData; +import oracle.sql.ORADataFactory; +import oracle.sql.Datum; +import oracle.sql.STRUCT; +import oracle.jpub.runtime.MutableStruct; + +import java.lang.*; +import java.sql.*; +import oracle.*; +import oracle.sql.*; +import oracle.jdbc.*; +import sqlj.runtime.ref.DefaultContext; +import sqlj.runtime.ConnectionContext; + +public class extdemo3a +{ + OracleResultSet rs; + PreparedStatement stmt; + + public extdemo3a(OracleResultSet r, PreparedStatement s) + { + rs=r; + stmt=s; + } + + public OracleResultSet getRs(){ return rs;} + public PreparedStatement getStmt() {return stmt;} + public void setRs(OracleResultSet r) {rs=r;} + public void setStmt(PreparedStatement s) {stmt=s;} + +} + diff --git a/extdemo4.c b/extdemo4.c new file mode 100644 index 0000000..ae58be3 --- /dev/null +++ b/extdemo4.c @@ -0,0 +1,788 @@ +#ifdef RCSID +static char *RCSid = + "$Header: extdemo4.c 08-feb-2001.18:14:54 ayoaz Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) Oracle Corporation 1998, 2000. All Rights Reserved. */ + +/* + + NAME + extdemo4.c - User Defined Aggregates using C safe callouts + using external context + + DESCRIPTION + See extdemo4.sql for the definition of the implementation type. + + NOTES + The implementation type contains two attributes, key and aggCtx. + Normally, the key will contains a value which identifes the + memory in extproc, where the aggregation context is stored, and + the aggCtx attribute will be NULL. + In certain situations, such as parallel aggregation, it is neccessary + to send the aggregation context from one slave to another, so + the external aggregation context will be "wrapped" into the + aggCtx attribute of the implementation type instance, and the key + will be set to NULL. So when the implementation type instance ("self") + is returned to the server, it will contain the actual aggregation + context in it. + Therefore, each of the ODCIAggregate routines has to check if the + aggregation context is in-line or out-of-line by checking the + "key" attribute. If it not NULL, than the key value is used to + access the externally stored context. If it is NULL, than external + memory is allocated and the context is copied from the aggCtx + attribute to the external memory, and the key identifying the external + memory is stored in the implementation type instance. This is done by + the GetExtAggCtx function. + + After retrieving the context, each of ODCIAggregate functions + calls the equivalent do_xxx function with the aggregation context + as the first argument (e.g. ODCIAggregateIterate calls do_iterate). + Therefore, the do_xxx functions only deal with actually implementing + the aggregation logic, using the aggregation context as a C struct, + without having to deal with the logic of retrieving the aggregation + context. + + The do_wrap and do_unwrap functions translate the aggregation context + from its OCI representation to a user-defined C representation. + In this example, the OCI representation of the aggregation context + is AggCtx_t, which represents the context as a x-y coordinate + stored as Oracle numbers (OCINumber). The C representation is + ExtAggCtx_t, which represents the context as x-y coordinate stored + as C doubles. If the context doesn't have to be transferred between + slaves, the context will always be stored externally as a user-defined C + struct (in extproc's memory), so these functions will not be called. + + All the other do_xxx (do_init, do_iterate, do_terminate, do_merge + and do_delete) only deal with context in its external format + (ExtAggCtx_t) which makes it simpler and faster to do the aggregation. + + MODIFIED (MM/DD/YY) + ayoaz 02/08/01 - Merged ayoaz_udag_demo + ayoaz 02/06/01 - Creation + +*/ + +#include "extdemo4.h" +#include + +/*------------------------------------------------------------------------ + PRIVATE TYPES AND CONSTANTS + ----------------------------------------------------------------------*/ + +/* The external context (stored in extproc's process memory) */ + +struct ExtAggCtx_t +{ + double x; + double y; +}; +typedef struct ExtAggCtx_t ExtAggCtx_t; + +/*-----------------------------------------------------------------------*/ + +/* OCI Handles */ + +struct Handles_t +{ + OCIExtProcContext* extProcCtx; + OCIEnv* envhp; + OCISvcCtx* svchp; + OCIError* errhp; + OCISession* usrhp; +}; +typedef struct Handles_t Handles_t; + +/*------------------------------------------------------------------------- + PRIVATE FUNCTIONS PROTOTYPES + -----------------------------------------------------------------------*/ + +static int GetHandles(OCIExtProcContext* extProcCtx, Handles_t* handles); + +/* + NAME: + GetHandles - get the various OCI handles + PARAMETERS: + extProcCtx (IN) - external procedure context + handles (OUT) - struct which contains the OCI handles + DESCRIPTION: + This function retrieves the OCI environment, service, error and + user handles using the external procedure context, and returns + then via the handles parameter. + RETURN: + Zero on success, -1 in case of error. +*/ + +/*-----------------------------------------------------------------------*/ + +static ExtAggCtx_t* GetExtAggCtx(Handles_t* handles, + Imp_t* self, Imp_Ind_t* self_ind); + +/* + NAME: + GetExtAggCtx - retrieve the external context + PARAMETERS: + handles (IN) - OCI handles + self (IN) - pointer to the self (implementation type instance) + self_ind (IN) - indicator struct for self + DESCRIPTION: + This function returns a pointer to the external representation + of the context, by retrieving it using the key attribute in self, + or allocating the external context and "unwrapping" the aggCtx within + the self into the external context. + RETURN: + Pointer to external context, or NULL in case of error. +*/ + +/*-----------------------------------------------------------------------*/ + +static int ChkErr(Handles_t* handles, sword status); + +/* + NAME: + ChkErr - check the error code, and register exception if neccessary + PARAMETERS: + handles (IN) - OCI handles + sword (IN) - error code + DESCRIPTION: + This function checks the input error code, and if it indicates + an OCI error, it registers an exception with the appropriate message. + RETURN: + Zero if there was no error, -1 in case of error. +*/ + +/*-----------------------------------------------------------------------*/ + +static int do_init(Handles_t* handles, ExtAggCtx_t* extAggCtx); +/* + NAME: + do_init - initialize the aggregation context + PARAMETERS: + handles (IN) - OCI handles + extAggCtx (OUT) - aggregation context + DESCRIPTION: + This function initializes the contents of the aggregation context, + to the (0,0) coordinates. + RETURN: + Zero on success, -1 in case of error. +*/ + +/*-----------------------------------------------------------------------*/ + +static int do_iterate(Handles_t* handles, ExtAggCtx_t* extAggCtx, + Vector_t* arg, Vector_Ind_t* arg_ind); +/* + NAME: + do_iterate - update the aggregation context with a new value + PARAMETERS: + handles (IN) - OCI handles + extAggCtx (IN/OUT) - aggregation context + arg (IN) - the vector to add + arg_ind (IN) - the vector's indicator struct + DESCRIPTION: + This function updates the aggregation context according by adding + the vector to the current coordinates in the aggregation context. + RETURN: + Zero on success, -1 in case of error. +*/ + +/*-----------------------------------------------------------------------*/ + +static int do_terminate(Handles_t* handles, ExtAggCtx_t* extAggCtx, + Vector_t* result, Vector_Ind_t* result_ind); +/* + NAME: + do_terminate - calculate aggregation result + PARAMETERS: + handles (IN) - OCI handles + extAggCtx (IN) - aggregation context + result (OUT) - the result vector + result_ind (OUT) - the result vector indicator struct + DESCRIPTION: + This function returns the sum as a vector, by translating the + current coordinates in the aggregation context into a vector. + RETURN: + Zero on success, -1 in case of error. +*/ + +/*-----------------------------------------------------------------------*/ + +static int do_merge(Handles_t* handles, ExtAggCtx_t* extAggCtx, + ExtAggCtx_t* extAggCtx2); +/* + NAME: + do_merge - merge two aggregation contexts + PARAMETERS: + handles (IN) - OCI handles + extAggCtx (IN/OUT) - aggregation context + extAggCtx2 (IN) - second aggregation context + DESCRIPTION: + Add the coordinates of the second context into the current context. + RETURN: + Zero on success, -1 in case of error. +*/ + +/*-----------------------------------------------------------------------*/ + +static int do_delete(Handles_t* handles, ExtAggCtx_t* extAggCtx, + Vector_t* arg, Vector_Ind_t* arg_ind); +/* + NAME: + do_delete - update the aggregation context by removing a value + PARAMETERS: + handles (IN) - OCI handles + extAggCtx (IN/OUT) - aggregation context + arg (IN) - the vector to subtract + arg_ind (IN) - the vector's indicator struct + DESCRIPTION: + This function updates the aggregation context according by subtracting + the vector from the coordinates in the aggregation context. + RETURN: + Zero on success, -1 in case of error. +*/ + +/*-----------------------------------------------------------------------*/ + +static int do_wrap(Handles_t* handles, ExtAggCtx_t* extAggCtx, + AggCtx_t* aggCtx, AggCtx_Ind_t* aggCtx_ind); +/* + NAME: + do_wrap - translate the external context into an OCI aggr. context. + PARAMETERS: + handles (IN) - OCI handles + extAggCtx (IN) - aggregation context (external) + aggCtx (OUT) - embedded OCI aggregation context + aggCtx_ind (OUT) - indicator of the embedded OCI aggregation context + DESCRIPTION: + This function translates the external context into the OCI aggregation + context (which is embedded in the implementation type instance). + RETURN: + Zero on success, -1 in case of error. +*/ + +/*-----------------------------------------------------------------------*/ + +static int do_unwrap(Handles_t* handles, ExtAggCtx_t* extAggCtx, + AggCtx_t* aggCtx, AggCtx_Ind_t* aggCtx_ind); +/* + NAME: + do_unwrap - translate the OCI aggregation context into external context + PARAMETERS: + handles (IN) - OCI handles + extAggCtx (OUT) - aggregation context (external) + aggCtx (IN) - embedded OCI aggregation context + aggCtx_ind (IN) - indicator of the embedded OCI aggregation context + DESCRIPTION: + This function translates the OCI aggregation context into the + an external context. + RETURN: + Zero on success, -1 in case of error. +*/ + +/*------------------------------------------------------------------------- + PUBLIC FUNCTIONS + -----------------------------------------------------------------------*/ + +/* ODCIAggregateInitialize function */ + +int Initialize(OCIExtProcContext* extProcCtx, + Imp_t* self, Imp_Ind_t* self_ind) +{ + Handles_t handles; + ExtAggCtx_t* extAggCtx; + ub4 key; + + /* Get OCI handles */ + if (GetHandles(extProcCtx, &handles)) + return ODCI_ERROR; + + /* Set up self */ + if (self_ind->_atomic==OCI_IND_NULL) + { + self_ind->_atomic = OCI_IND_NOTNULL; + self_ind->key = OCI_IND_NULL; + self_ind->aggCtx._atomic = OCI_IND_NULL; + } + + /* Get context */ + extAggCtx=GetExtAggCtx(&handles,self,self_ind); + if (!extAggCtx) return ODCI_ERROR; + + /* Initialize context */ + if (do_init(&handles, extAggCtx)) + return ODCI_ERROR; + + return ODCI_SUCCESS; +} + +/*-----------------------------------------------------------------------*/ + +/* ODCIAggregateIterate function */ + +int Iterate(OCIExtProcContext* extProcCtx, + Imp_t* self, Imp_Ind_t* self_ind, + Vector_t* arg, Vector_Ind_t* arg_ind) +{ + Handles_t handles; + ExtAggCtx_t* extAggCtx; + + /* Get OCI handles */ + if (GetHandles(extProcCtx, &handles)) + return ODCI_ERROR; + + /* Get context */ + extAggCtx=GetExtAggCtx(&handles,self,self_ind); + if (!extAggCtx) return ODCI_ERROR; + + if (do_iterate(&handles,extAggCtx,arg,arg_ind)) + return ODCI_ERROR; + + return ODCI_SUCCESS; +} + +/*-----------------------------------------------------------------------*/ + +/* ODCIAgregateTerminate */ + +int Terminate(OCIExtProcContext* extProcCtx, + Imp_t* self, Imp_Ind_t* self_ind, + Vector_t* result, Vector_Ind_t* result_ind, + OCINumber* flags, OCIInd flags_ind) +{ + Handles_t handles; + ExtAggCtx_t* extAggCtx; + int flags_val=0; + + /* Get OCI handles */ + if (GetHandles(extProcCtx, &handles)) + return ODCI_ERROR; + + /* Get context */ + extAggCtx=GetExtAggCtx(&handles,self,self_ind); + if (!extAggCtx) return ODCI_ERROR; + + if (do_terminate(&handles,extAggCtx,result,result_ind)) + return ODCI_ERROR; + + /* get the flags parameter velue */ + if (flags_ind==OCI_IND_NOTNULL) + { + if (ChkErr(&handles, OCINumberToInt(handles.errhp, flags, + sizeof(flags_val), OCI_NUMBER_SIGNED, + &flags_val))) + return ODCI_ERROR; + } + + /* Free external context memory (unless ODCI_AGGREGATE_REUSE_CTX is set) */ + if ((flags_val && ODCI_AGGREGATE_REUSE_CTX)==0) + { + if (ChkErr(&handles, OCIMemoryFree((dvoid*)handles.usrhp, + handles.errhp, (dvoid*) extAggCtx))) + return ODCI_ERROR; + + self_ind->key=OCI_IND_NULL; + } + + return ODCI_SUCCESS; +} + +/*-----------------------------------------------------------------------*/ + +/* ODCIAggregateMerge */ + +int Merge(OCIExtProcContext* extProcCtx, + Imp_t* self, Imp_Ind_t* self_ind, + Imp_t* sctx2, Imp_Ind_t* sctx2_ind) +{ + Handles_t handles; + ExtAggCtx_t* extAggCtx; + ExtAggCtx_t* extAggCtx2; + + /* Get OCI handles */ + if (GetHandles(extProcCtx, &handles)) + return ODCI_ERROR; + + /* Get 1st external context */ + extAggCtx=GetExtAggCtx(&handles,self,self_ind); + if (!extAggCtx) return ODCI_ERROR; + + /* Get 2nd external context */ + extAggCtx2=GetExtAggCtx(&handles,sctx2,sctx2_ind); + if (!extAggCtx2) return ODCI_ERROR; + + if (do_merge(&handles,extAggCtx,extAggCtx2)) + return ODCI_ERROR; + + /* Free the 2nd external context memory */ + if (sctx2_ind->key == OCI_IND_NOTNULL) + { + if (ChkErr(&handles, OCIMemoryFree((dvoid *)handles.usrhp, + handles.errhp, (dvoid *)extAggCtx2))) + return ODCI_ERROR; + } + + return ODCI_SUCCESS; +} + +/*-----------------------------------------------------------------------*/ + +/* ODCIAggregateDelete function */ + +int Delete(OCIExtProcContext* extProcCtx, + Imp_t* self, Imp_Ind_t* self_ind, + Vector_t* arg, Vector_Ind_t* arg_ind) +{ + Handles_t handles; + ExtAggCtx_t* extAggCtx; + + /* Get OCI handles */ + if (GetHandles(extProcCtx, &handles)) + return ODCI_ERROR; + + /* Get context */ + extAggCtx=GetExtAggCtx(&handles,self,self_ind); + if (!extAggCtx) return ODCI_ERROR; + + if (do_delete(&handles,extAggCtx,arg,arg_ind)) + return ODCI_ERROR; + + return ODCI_SUCCESS; +} + +/*-----------------------------------------------------------------------*/ + +/* ODCIAgregateWrapContext */ + +int WrapContext(OCIExtProcContext* extProcCtx, + Imp_t* self, Imp_Ind_t* self_ind) +{ + Handles_t handles; + ExtAggCtx_t* extAggCtx; + + /* Get OCI handles */ + if (GetHandles(extProcCtx, &handles)) + return ODCI_ERROR; + + /* nothing to do if no external context */ + if (self_ind->key==OCI_IND_NULL) + return ODCI_SUCCESS; + + /* Get context */ + extAggCtx=GetExtAggCtx(&handles,self,self_ind); + if (!extAggCtx) return ODCI_ERROR; + + if (do_wrap(&handles,extAggCtx,&self->aggCtx,&self_ind->aggCtx)) + return ODCI_ERROR; + + /* Free external context memory */ + if (ChkErr(&handles, OCIMemoryFree((dvoid*)handles.usrhp, + handles.errhp, (dvoid*) extAggCtx))) + return ODCI_ERROR; + + self_ind->key=OCI_IND_NULL; + + return ODCI_SUCCESS; +} + +/*------------------------------------------------------------------------- + PRIVATE FUNCTIONS + -----------------------------------------------------------------------*/ + +static int do_init(Handles_t* handles, ExtAggCtx_t* extAggCtx) +{ + /* Initialize context */ + extAggCtx->x=0.0; + extAggCtx->y=0.0; + + return 0; +} + +/*-----------------------------------------------------------------------*/ + +static int do_iterate(Handles_t* handles, ExtAggCtx_t* extAggCtx, + Vector_t* arg, Vector_Ind_t* arg_ind) +{ + double length=0.0; + double angle=0.0; + + /* get the input value */ + if (arg_ind->length==OCI_IND_NOTNULL) + { + if (ChkErr(handles, OCINumberToReal(handles->errhp, &arg->length, + sizeof(length), (dvoid*) &length))) + return(-1); + + } + + if (arg_ind->angle==OCI_IND_NOTNULL) + { + if (ChkErr(handles, OCINumberToReal(handles->errhp, &arg->angle, + sizeof(angle), (dvoid*) &angle))) + return(-1); + + } + + /* update the context by adding the equivalent vector coordinates */ + extAggCtx->x+=length*cos(angle); + extAggCtx->y+=length*sin(angle); + + return 0; +} + +/*-----------------------------------------------------------------------*/ + +static int do_terminate(Handles_t* handles, ExtAggCtx_t* extAggCtx, + Vector_t* result, Vector_Ind_t* result_ind) +{ + double length=0.0; + double angle=0.0; + + /* calculate the length and angle using the coordinates in context */ + + if (extAggCtx->x!=0 || extAggCtx->y!=0) + length=sqrt(extAggCtx->x*extAggCtx->x+extAggCtx->y*extAggCtx->y); + + if (extAggCtx->x!=0) + angle=atan(extAggCtx->y/extAggCtx->x); + + /* assign the length and angle to the result vector */ + if (ChkErr(handles, OCINumberFromReal(handles->errhp, &length, + sizeof(length), &result->length))) + return -1; + + result_ind->length=OCI_IND_NOTNULL; + + if (ChkErr(handles, OCINumberFromReal(handles->errhp, &angle, + sizeof(angle), &result->angle))) + return -1; + + result_ind->angle=OCI_IND_NOTNULL; + + result_ind->_atomic=OCI_IND_NOTNULL; + + return 0; +} + +/*-----------------------------------------------------------------------*/ + +static int do_merge(Handles_t* handles, ExtAggCtx_t* extAggCtx, + ExtAggCtx_t* extAggCtx2) +{ + /* add the other context coordiantes to the current coordinates */ + extAggCtx->x+=extAggCtx2->x; + extAggCtx->y+=extAggCtx2->y; + + return 0; +} + +/*-----------------------------------------------------------------------*/ + +static int do_delete(Handles_t* handles, ExtAggCtx_t* extAggCtx, + Vector_t* arg, Vector_Ind_t* arg_ind) +{ + double length=0.0; + double angle=0.0; + + /* get the input value */ + if (arg_ind->length==OCI_IND_NOTNULL) + { + if (ChkErr(handles, OCINumberToReal(handles->errhp, &arg->length, + sizeof(length), (dvoid*) &length))) + return(-1); + + } + + if (arg_ind->angle==OCI_IND_NOTNULL) + { + if (ChkErr(handles, OCINumberToReal(handles->errhp, &arg->angle, + sizeof(angle), (dvoid*) &angle))) + return(-1); + + } + + /* update the context by subtracting the equivalent vector coordinates */ + extAggCtx->x-=length*cos(angle); + extAggCtx->y-=length*sin(angle); + + return 0; +} + +/*-----------------------------------------------------------------------*/ + +static int do_wrap(Handles_t* handles, ExtAggCtx_t* extAggCtx, + AggCtx_t* aggCtx, AggCtx_Ind_t* aggCtx_ind) +{ + /* transfer the external context's coordinates to the embedded context */ + + if (ChkErr(handles, OCINumberFromReal(handles->errhp, &extAggCtx->x, + sizeof(extAggCtx->x), &aggCtx->x))) + return -1; + + aggCtx_ind->x = OCI_IND_NOTNULL; + + if (ChkErr(handles, OCINumberFromReal(handles->errhp, &extAggCtx->y, + sizeof(extAggCtx->y), &aggCtx->y))) + return -1; + + aggCtx_ind->y = OCI_IND_NOTNULL; + + aggCtx_ind->_atomic = OCI_IND_NOTNULL; + + return 0; +} + +/*-----------------------------------------------------------------------*/ + +static int do_unwrap(Handles_t* handles, ExtAggCtx_t* extAggCtx, + AggCtx_t* aggCtx, AggCtx_Ind_t* aggCtx_ind) +{ + extAggCtx->x=0.0; + extAggCtx->y=0.0; + + /* get the coordinates from the embedded context and store them + in the external context */ + + if (aggCtx_ind->x==OCI_IND_NOTNULL) + { + if (ChkErr(handles, OCINumberToReal(handles->errhp, &aggCtx->x, + sizeof(extAggCtx->x), &extAggCtx->x))) + return -1; + } + + if (aggCtx_ind->x==OCI_IND_NOTNULL) + { + if (ChkErr(handles, OCINumberToReal(handles->errhp, &aggCtx->y, + sizeof(extAggCtx->y), &extAggCtx->y))) + return -1; + } + + return 0; +} + +/*-----------------------------------------------------------------------*/ + +static ExtAggCtx_t* GetExtAggCtx(Handles_t* handles, Imp_t* self, + Imp_Ind_t* self_ind) +{ + ExtAggCtx_t* extCtx; /* The real context */ + + if (self_ind->key==OCI_IND_NOTNULL) + { + /* the key is not null, so we'll use it to get + the address of external context */ + + ub1* key; /* key to retrieve context */ + ub4 keylen; /* length of key */ + + /* Get the key */ + key = OCIRawPtr(handles->envhp, self->key); + keylen = OCIRawSize(handles->envhp, self->key); + + /* Retrieve context from key */ + if (ChkErr(handles, OCIContextGetValue((dvoid *)handles->usrhp, + handles->errhp, key, (ub1)keylen, + (dvoid**) &extCtx))) + return NULL; + } + else + { + /* the key attribute was NULL, so we will allocate memory for + the external context */ + + ub4 key; + + /* Allocate memory to hold external scan context */ + if (ChkErr(handles, OCIMemoryAlloc((dvoid *)handles->usrhp, + handles->errhp, (dvoid **)&extCtx, + OCI_DURATION_STATEMENT, + (ub4)(sizeof(ExtAggCtx_t)), OCI_MEMORY_CLEARED))) + return NULL; + + /* generate a key */ + if (ChkErr(handles, OCIContextGenerateKey((dvoid *)handles->usrhp, + handles->errhp, &key))) + return NULL; + + /* set the memory address of the struct to be saved in the context */ + if (ChkErr(handles, OCIContextSetValue((dvoid *)handles->usrhp, + handles->errhp, OCI_DURATION_STATEMENT, + (ub1 *)&key, (ub1)sizeof(key), (dvoid*) extCtx))) + return NULL; + + /* store the key in self */ + if (ChkErr(handles, OCIRawAssignBytes(handles->envhp, handles->errhp, + (ub1 *)&key, (ub4)sizeof(key), &(self->key)))) + return NULL; + + self_ind->key = OCI_IND_NOTNULL; + + /* if the embedded context is not null, use it to initialize the + external context (unwrap) */ + + if (self_ind->aggCtx._atomic==OCI_IND_NOTNULL) + { + /* unwrap - create external context from embedded context */ + if (do_unwrap(handles,extCtx,&self->aggCtx,&self_ind->aggCtx)) + return NULL; + + /* set the embedded context to NULL */ + self_ind->aggCtx._atomic = OCI_IND_NULL; + + } + + } + + return extCtx; +} + +/*-----------------------------------------------------------------------*/ + +static int GetHandles(OCIExtProcContext* extProcCtx, Handles_t* handles) +{ + handles->extProcCtx=extProcCtx; + + /* Get OCI env, error and service handles */ + if (ChkErr(handles, OCIExtProcGetEnv(extProcCtx, &handles->envhp, + &handles->svchp, &handles->errhp))) + return -1; + + /* get the user handle */ + if (ChkErr(handles, OCIAttrGet((dvoid *)handles->svchp, + (ub4)OCI_HTYPE_SVCCTX, (dvoid *)&handles->usrhp, + (ub4 *)0, (ub4)OCI_ATTR_SESSION, handles->errhp))) + return -1; + + return 0; +} + +/*-----------------------------------------------------------------------*/ + +static int ChkErr(Handles_t* handles, sword status) +{ + text errbuf[512]; + sb4 errcode; + + /* check the error code */ + switch (status) + { + case OCI_SUCCESS: + case OCI_SUCCESS_WITH_INFO: + return 0; + case OCI_ERROR: + OCIErrorGet ((dvoid *) handles->errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); + sprintf((char*)errbuf, "OCI ERROR code %d",errcode); + break; + default: + sprintf((char*)errbuf, "Warning - error status %d",status); + break; + } + + /* register exception */ + OCIExtProcRaiseExcpWithMsg(handles->extProcCtx, 29400, errbuf, + strlen((char*)errbuf)); + return 1; +} + +/* end of file extdemo4.c */ + diff --git a/extdemo4.h b/extdemo4.h new file mode 100644 index 0000000..316bfe6 --- /dev/null +++ b/extdemo4.h @@ -0,0 +1,127 @@ +/* + * $Header: extdemo4.h 08-feb-2001.18:14:55 ayoaz Exp $ + */ + +/* Copyright (c) Oracle Corporation 1998, 2000. All Rights Reserved. */ + +/* + NAME + extdemo4.h - user defined aggregates using C safe callouts + with external aggregation context + + DESCRIPTION + This file contains the OCI declarations of the SQL types used + by the SumVector aggregate function. + + MODIFIED (MM/DD/YY) + ayoaz 02/08/01 - Merged ayoaz_udag_demo + ayoaz 02/06/01 - Creation + +*/ + +#ifndef EXTDEMO4_ORACLE +#define EXTDEMO4_ORACLE + +#ifndef OCI_ORACLE +# include +#endif +#ifndef ODCI_ORACLE +# include +#endif + +/*------------------------------------------------------------------------- + OCI REPRESENTATION OF SQL TYPES + -----------------------------------------------------------------------*/ + +/* Vector_t - this is the OCI representation of the Vector_t SQL type */ + +struct Vector_t +{ + OCINumber length; + OCINumber angle; +}; +typedef struct Vector_t Vector_t; + +/* Indicator struct for Vector_t type */ + +struct Vector_Ind_t +{ + OCIInd _atomic; + OCIInd length; + OCIInd angle; +}; +typedef struct Vector_Ind_t Vector_Ind_t; + +/* AggCtx_t - OCI representation of the AggCtx_t SQL type */ + +struct AggCtx_t +{ + OCINumber x; + OCINumber y; +}; +typedef struct AggCtx_t AggCtx_t; + +/* Indicator struct for AggCtx_t */ + +struct AggCtx_Ind_t +{ + OCIInd _atomic; + OCIInd x; + OCIInd y; +}; +typedef struct AggCtx_Ind_t AggCtx_Ind_t; + +/* Imp_t - OCI representation of the Imp_t SQL type */ + +struct Imp_t +{ + OCIRaw* key; /* a key identifying the external context (null if none) */ + AggCtx_t aggCtx; /* the aggregation context (null if context is external */ +}; +typedef struct Imp_t Imp_t; + +/* Indicator struct for Imp_t */ + +struct Imp_Ind_t +{ + OCIInd _atomic; + OCIInd key; + AggCtx_Ind_t aggCtx; +}; +typedef struct Imp_Ind_t Imp_Ind_t; + +/*------------------------------------------------------------------------ + PUBLIC FUNCTIONS + ----------------------------------------------------------------------*/ + +/* C implementation of ODCIAgregateInitialize */ +int Initialize(OCIExtProcContext* extProcCtx, + Imp_t* self, Imp_Ind_t* self_ind); + +/* C implementation of ODCIAgregateIterate */ +int Iterate(OCIExtProcContext* extProcCtx, + Imp_t* self, Imp_Ind_t* self_ind, + Vector_t* arg, Vector_Ind_t* arg_ind); + +/* C implementation of ODCIAgregateTerminate */ +int Terminate(OCIExtProcContext* extProcCtx, + Imp_t* self, Imp_Ind_t* self_ind, + Vector_t* result, Vector_Ind_t* result_ind, + OCINumber* flags, OCIInd flags_ind); + +/* C implementation of ODCIAggregateMerge */ +int Merge(OCIExtProcContext* extProcCtx, + Imp_t* self, Imp_Ind_t* self_ind, + Imp_t* sctx2, Imp_Ind_t* sctx2_ind); + +/* C implementation of ODCIAgregateDelete */ +int Delete(OCIExtProcContext* extProcCtx, + Imp_t* self, Imp_Ind_t* self_ind, + Vector_t* arg, Vector_Ind_t* arg_ind); + +/* C implementation of ODCIAgregateWrapContext */ +int WrapContext(OCIExtProcContext* extProcCtx, + Imp_t* self, Imp_Ind_t* self_ind); + +#endif + diff --git a/extdemo4.sql b/extdemo4.sql new file mode 100644 index 0000000..460704a --- /dev/null +++ b/extdemo4.sql @@ -0,0 +1,206 @@ +Rem +Rem $Header: extdemo4.sql 08-feb-2001.18:14:55 ayoaz Exp $ +Rem +Rem extdemo4.sql +Rem +Rem Copyright (c) Oracle Corporation 1998, 2000. All Rights Reserved. +Rem +Rem NAME +Rem extdemo4.sql - user defined aggregate implemented using C functions. +Rem +Rem DESCRIPTION +Rem This file demonstrates the creation and use of a simple user +Rem defined aggregate function called SumVector, which calculates +Rem the sum of a set of vectors. +Rem +Rem The following steps should be taken before running this script: +Rem +Rem 1. Create the shared library extdemo4.so: +Rem +Rem make extproc_with_context SHARED_LIBNAME=extdemo4.so OBJS="extdemo4.o" +Rem +Rem 2. Change the CREATE LIBRARY command in this script to reflect +Rem the path of the shared library created in step 1. +Rem For example: +Rem +Rem CREATE LIBRARY VectorLib is '/oracle_home/rdbms/demo/extdemo4.so'; +Rem / +Rem +Rem MODIFIED (MM/DD/YY) +Rem ayoaz 02/08/01 - Merged ayoaz_udag_demo +Rem ayoaz 02/06/01 - Created +Rem + +SET FEEDBACK 1 +SET ECHO ON + +CONNECT system/manager +DROP USER extdemo4 CASCADE; +GRANT RESOURCE, CONNECT TO extdemo4 IDENTIFIED BY extdemo4; +GRANT CREATE TYPE TO extdemo4; +GRANT CREATE PROCEDURE TO extdemo4; +GRANT CREATE TABLE TO extdemo4; +GRANT CREATE LIBRARY TO extdemo4; + +CONNECT extdemo4/extdemo4 + +CREATE LIBRARY VectorLib is '/ade/ayoaz_ade0/oracle/rdbms/demo/extdemo4.so'; +/ + +-- Vector type + +CREATE TYPE Vector_t AS OBJECT ( + length NUMBER, + angle NUMBER, + MAP MEMBER FUNCTION GetLength RETURN NUMBER +); +/ + +CREATE TYPE BODY Vector_t IS + MAP MEMBER FUNCTION GetLength RETURN NUMBER IS + BEGIN + RETURN length; + END; +END; +/ + +-- Create the context type + +CREATE TYPE AggCtx_t AS OBJECT ( + x NUMBER, + y NUMBER +); +/ + +-- Create the implementation type + +CREATE TYPE Imp_t AS OBJECT +( + key RAW(4), + aggCtx aggCtx_t, + + STATIC FUNCTION ODCIAggregateInitialize(sctx IN OUT Imp_t) + RETURN PLS_INTEGER + AS LANGUAGE C + LIBRARY VectorLib + NAME "Initialize" + WITH CONTEXT + PARAMETERS ( + CONTEXT, + sctx, + sctx INDICATOR STRUCT, + RETURN INT + ), + + MEMBER FUNCTION ODCIAggregateIterate(self IN OUT Imp_t, arg IN Vector_t) + RETURN PLS_INTEGER + AS LANGUAGE C + LIBRARY VectorLib + NAME "Iterate" + WITH CONTEXT + PARAMETERS ( + CONTEXT, + self, + self INDICATOR STRUCT, + arg, + arg INDICATOR STRUCT, + RETURN INT + ), + + MEMBER FUNCTION ODCIAggregateTerminate(self IN Imp_t, result OUT Vector_t, + flags IN NUMBER) RETURN PLS_INTEGER + AS LANGUAGE C + LIBRARY VectorLib + NAME "Terminate" + WITH CONTEXT + PARAMETERS ( + CONTEXT, + self, + self INDICATOR STRUCT, + result, + result INDICATOR STRUCT, + flags, + flags INDICATOR, + RETURN INT + ), + + MEMBER FUNCTION ODCIAggregateMerge(self IN OUT Imp_t, sctx2 IN Imp_t) + RETURN PLS_INTEGER + AS LANGUAGE C + LIBRARY VectorLib + NAME "Merge" + WITH CONTEXT + PARAMETERS ( + CONTEXT, + self, + self INDICATOR STRUCT, + sctx2, + sctx2 INDICATOR STRUCT, + RETURN INT + ), + + member function ODCIAggregateDelete(self IN OUT Imp_t, arg IN Vector_t) + RETURN PLS_INTEGER + AS LANGUAGE C + LIBRARY VectorLib + NAME "Delete" + WITH CONTEXT + PARAMETERS ( + CONTEXT, + self, + self INDICATOR STRUCT, + arg, + arg INDICATOR STRUCT, + RETURN INT + ), + + MEMBER FUNCTION ODCIAggregateWrapContext(self IN OUT Imp_t) + RETURN PLS_INTEGER + AS LANGUAGE C + LIBRARY VectorLib + NAME "WrapContext" + WITH CONTEXT + PARAMETERS ( + CONTEXT, + self, + self INDICATOR STRUCT, + RETURN INT + ) + +); +/ + +-- Create user aggregate function + +CREATE FUNCTION SumVector(arg Vector_t) RETURN Vector_t +PARALLEL_ENABLE AGGREGATE USING Imp_t; +/ + +-- Create sample data + +CREATE TABLE t1 (c1 NUMBER, c2 Vector_t); +INSERT INTO T1 VALUES(1, Vector_t(5,0)); +INSERT INTO T1 VALUES(1, Vector_t(3,0)); +INSERT INTO T1 VALUES(2, Vector_t(1,2)); +INSERT INTO T1 VALUES(2, Vector_t(2,1)); +INSERT INTO T1 VALUES(2, Vector_t(3,0.5)); +INSERT INTO T1 VALUES(2, Vector_t(3,2.5)); + +CREATE TABLE t2 PARALLEL 2 AS SELECT * FROM t1; + +COMMIT; + +-- Sample queries + +-- serial cases +SELECT SumVector(c2) sum FROM t1; +SELECT SumVector(DISTINCT c2) sum FROM t1; +SELECT c1, SumVector(c2) sum FROM t1 GROUP BY c1 ORDER BY c1; +SELECT c1, SumVector(distinct c2) sum FROM t1 GROUP BY c1 ORDER BY c1; + +-- parallel cases +SELECT SumVector(c2) sum FROM t2; +SELECT SumVector(DISTINCT c2) sum FROM t2; +SELECT c1, SumVector(c2) sum FROM t2 GROUP BY c1 ORDER BY c1; +SELECT c1, SumVector(distinct c2) sum FROM t2 GROUP BY c1 ORDER BY c1; + diff --git a/extdemo5.c b/extdemo5.c new file mode 100644 index 0000000..c9a0d84 --- /dev/null +++ b/extdemo5.c @@ -0,0 +1,824 @@ +#ifdef RCSID +static char *RCSid = + "$Header: extdemo5.c 05-apr-2005.06:32:29 yhu Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 2001, 2005, Oracle. All rights reserved. +*/ + +/* + + NAME + extdemo5.c - Extensible Indexing example implemented as C routines + for local domain index on varchar2 column of + a range partitioned table. + + DESCRIPTION + This file contains the definitions of the DML and Query routines + for the extensible indexing example that implements a simple btree + (sbtree). See extdemo5.sql for the SQL script that defines the + indextype. + + PUBLIC FUNCTION(S) + qxiqtbps - QXIQT Btree Start routine + qxiqtbpf - QXIQT Btree Fetch routine + qxiqtbpc - QXIQT Btree Close routine + qxiqtbpi - QXIQT Btree Insert routine + qxiqtbpd - QXIQT Btree Delete routine + qxiqtbpu - QXIQT Btree Update routine + + PRIVATE FUNCTION(S) + qxiqtbe - QXIQT error reporting routine + + NOTES + + + MODIFIED (MM/DD/YY) + yhu 04/04/05 - #4184410: fix porting exceptions in HP VMS + hdnguyen 04/27/01 - misc. modification + spsundar 04/25/01 - Creation + +*/ + +#ifndef EXTDEMO5_ORACLE +# include "extdemo5.h" +#endif +#include +#include + +/*--------------------------------------------------------------------------- + TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + PUBLIC FUNCTIONS + ---------------------------------------------------------------------------*/ + +/* ODCIIndexInsert function */ +OCINumber *qxiqtbpi(ctx, ix, ix_ind, rid, rid_ind, + newval, newval_ind, env, env_ind) +OCIExtProcContext *ctx; +ODCIIndexInfo *ix; +ODCIIndexInfo_ind *ix_ind; +char *rid; +short rid_ind; +char *newval; +short newval_ind; +ODCIEnv *env; +ODCIEnv_ind *env_ind; +{ + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCIStmt *stmthp = (OCIStmt *) 0; /* statement handle */ + OCIBind *bndp = (OCIBind *) 0; /* bind handle */ + + int retval = (int)ODCI_SUCCESS; /* return from this function */ + OCINumber *rval = (OCINumber *)0; + + char insstmt[2000]; /* sql insert statement */ + + /* allocate memory for OCINumber first */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + + /* Get oci handles */ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /****************************** + * Construct insert Statement * + ******************************/ + if (ix_ind->IndexPartition == OCI_IND_NULL) + (void)sprintf(insstmt, + "INSERT into %s.%s_sbtree values (:newval, :mrid)", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName)); + else + (void)sprintf(insstmt, + "INSERT into %s.%s_%s_sbtree values (:newval, :mrid)", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName), + OCIStringPtr(envhp, ix->IndexPartition)); + + + /**************************************** + * Parse and Execute Create Statement * + ****************************************/ + + /* allocate stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleAlloc((dvoid *)envhp, + (dvoid **)&stmthp, + (ub4)OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0))) + return(rval); + + /* prepare the statement */ + if (qxiqtce(ctx, errhp, OCIStmtPrepare(stmthp, errhp, + (text *)insstmt, + (ub4)strlen(insstmt), + OCI_NTV_SYNTAX, + OCI_DEFAULT))) + return(rval); + + /* Set up bind for newval */ + if (qxiqtce(ctx, errhp, OCIBindByPos(stmthp, &bndp, errhp, (ub4)1, + (dvoid *)newval, + (sb4)(strlen(newval)+1), + (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Set up bind for rid */ + if (qxiqtce(ctx, errhp, OCIBindByPos(stmthp, &bndp, errhp, (ub4)2, + (dvoid *)rid, + (sb4)(strlen(rid)+1), + (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Execute statement */ + if (qxiqtce(ctx, errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, + (ub4)0, (OCISnapshot *)NULL, + (OCISnapshot *)NULL, + (ub4)OCI_DEFAULT))) + return(rval); + + /* free stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleFree((dvoid *)stmthp, + (ub4)OCI_HTYPE_STMT))) + return(rval); + + return(rval); +} + +/* ODCIIndexDelete function */ +OCINumber *qxiqtbpd(ctx, ix, ix_ind, rid, rid_ind, + oldval, oldval_ind, env, env_ind) +OCIExtProcContext *ctx; +ODCIIndexInfo *ix; +ODCIIndexInfo_ind *ix_ind; +char *rid; +short rid_ind; +char *oldval; +short oldval_ind; +ODCIEnv *env; +ODCIEnv_ind *env_ind; +{ + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCIStmt *stmthp = (OCIStmt *) 0; /* statement handle */ + OCIBind *bndp = (OCIBind *) 0; /* bind handle */ + + int retval = (int)ODCI_SUCCESS; /* return from this function */ + OCINumber *rval = (OCINumber *)0; + + char delstmt[2000]; /* sql delete statement */ + + /* Get oci handles */ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /****************************** + * Construct delete Statement * + ******************************/ + if (ix_ind->IndexPartition == OCI_IND_NULL) + (void)sprintf(delstmt, + "DELETE FROM %s.%s_sbtree WHERE f2 = :rr", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName)); + else + (void)sprintf(delstmt, + "DELETE FROM %s.%s_%s_sbtree WHERE f2 = :rr", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName), + OCIStringPtr(envhp, ix->IndexPartition)); + + /**************************************** + * Parse and Execute delete Statement * + ****************************************/ + + /* allocate stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleAlloc((dvoid *)envhp, + (dvoid **)&stmthp, + (ub4)OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0))) + return(rval); + + /* prepare the statement */ + if (qxiqtce(ctx, errhp, OCIStmtPrepare(stmthp, errhp, + (text *)delstmt, + (ub4)strlen(delstmt), + OCI_NTV_SYNTAX, + OCI_DEFAULT))) + return(rval); + + /* Set up bind for rid */ + if (qxiqtce(ctx, errhp, OCIBindByPos(stmthp, &bndp, errhp, (ub4)1, + (dvoid *)rid, + (sb4)(strlen(rid)+1), + (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Execute statement */ + if (qxiqtce(ctx, errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, + (ub4)0, (OCISnapshot *)NULL, + (OCISnapshot *)NULL, + (ub4)OCI_DEFAULT))) + return(rval); + + /* free stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleFree((dvoid *)stmthp, + (ub4)OCI_HTYPE_STMT))) + return(rval); + + return(rval); +} + +/* ODCIIndexUpdate function */ +OCINumber *qxiqtbpu(ctx, ix, ix_ind, rid, rid_ind, oldval, oldval_ind, + newval, newval_ind, env, env_ind) +OCIExtProcContext *ctx; +ODCIIndexInfo *ix; +ODCIIndexInfo_ind *ix_ind; +char *rid; +short rid_ind; +char *oldval; +short oldval_ind; +char *newval; +short newval_ind; +ODCIEnv *env; +ODCIEnv_ind *env_ind; +{ + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCIStmt *stmthp = (OCIStmt *) 0; /* statement handle */ + OCIBind *bndp = (OCIBind *) 0; /* bind handle */ + + int retval = (int)ODCI_SUCCESS; /* return from this function */ + OCINumber *rval = (OCINumber *)0; + + char updstmt[2000]; /* sql upate statement */ + + /* Get oci handles */ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /****************************** + * Construct update Statement * + ******************************/ + if (ix_ind->IndexPartition == OCI_IND_NULL) + (void)sprintf(updstmt, + "UPDATE %s.%s_sbtree SET f1 = :newval WHERE f1 = :oldval", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName)); + else + (void)sprintf(updstmt, + "UPDATE %s.%s_%s_sbtree SET f1 = :newval WHERE f1 = :oldval", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName), + OCIStringPtr(envhp, ix->IndexPartition)); + + + /**************************************** + * Parse and Execute Create Statement * + ****************************************/ + + /* allocate stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleAlloc((dvoid *)envhp, + (dvoid **)&stmthp, + (ub4)OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0))) + return(rval); + + /* prepare the statement */ + if (qxiqtce(ctx, errhp, OCIStmtPrepare(stmthp, errhp, + (text *)updstmt, + (ub4)strlen(updstmt), + OCI_NTV_SYNTAX, + OCI_DEFAULT))) + return(rval); + + /* Set up bind for newval */ + if (qxiqtce(ctx, errhp, OCIBindByPos(stmthp, &bndp, errhp, (ub4)1, + (dvoid *)newval, + (sb4)(strlen(newval)+1), + (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Set up bind for oldval */ + if (qxiqtce(ctx, errhp, OCIBindByPos(stmthp, &bndp, errhp, (ub4)2, + (dvoid *)oldval, + (sb4)(strlen(oldval)+1), + (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Execute statement */ + if (qxiqtce(ctx, errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, + (ub4)0, (OCISnapshot *)NULL, + (OCISnapshot *)NULL, + (ub4)OCI_DEFAULT))) + return(rval); + + /* free stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleFree((dvoid *)stmthp, + (ub4)OCI_HTYPE_STMT))) + return(rval); + + return(rval); +} + +/* ODCIIndexStart function */ +OCINumber *qxiqtbps(ctx, sctx, sctx_ind, ix, ix_ind, pr, pr_ind, + qy, qy_ind, strt, strt_ind, stop, stop_ind, + cmpval, cmpval_ind, env, env_ind) +OCIExtProcContext *ctx; +qxiqtim *sctx; +qxiqtin *sctx_ind; +ODCIIndexInfo *ix; +ODCIIndexInfo_ind *ix_ind; +ODCIPredInfo *pr; +ODCIPredInfo_ind *pr_ind; +ODCIQueryInfo *qy; +ODCIQueryInfo_ind *qy_ind; +OCINumber *strt; +short strt_ind; +OCINumber *stop; +short stop_ind; +char *cmpval; +short cmpval_ind; +ODCIEnv *env; +ODCIEnv_ind *env_ind; +{ + sword status; + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCISession *usrhp = (OCISession *) 0; /* user handle */ + qxiqtcx *icx = (qxiqtcx *) 0; /* state to be saved for later calls */ + + int strtval; /* start bound */ + int stopval; /* stop bound */ + + int errnum = 29400; /* choose some oracle error number */ + char errmsg[512]; /* error message buffer */ + size_t errmsglen; /* Length of error message */ + + char relop[3]; /* relational operator used in sql stmt */ + char selstmt[2000]; /* sql select statement */ + + int retval = (int)ODCI_SUCCESS; /* return from this function */ + OCINumber *rval = (OCINumber *)0; + ub4 key; /* key value set in "sctx" */ + + ub1 *rkey; /* key to retrieve context */ + ub4 rkeylen; /* length of key */ + + /* Get oci handles */ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /* get the user handle */ + if (qxiqtce(ctx, errhp, OCIAttrGet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)&usrhp, (ub4 *)0, + (ub4)OCI_ATTR_SESSION, + errhp))) + return(rval); + + /**********************************************/ + /* Allocate memory to hold index scan context */ + /**********************************************/ + if (sctx_ind ->atomic_qxiqtin == OCI_IND_NULL || + sctx_ind ->scind_qxiqtin == OCI_IND_NULL) + { + if (qxiqtce(ctx, errhp, OCIMemoryAlloc((dvoid *)usrhp, errhp, + (dvoid **)&icx, + OCI_DURATION_STATEMENT, + (ub4)(sizeof(qxiqtcx)), + OCI_MEMORY_CLEARED))) + return(rval); + + icx->stmthp = (OCIStmt *)0; + icx->defnp = (OCIDefine *)0; + icx->bndp = (OCIBind *)0; + } + else + { + /*************************/ + /* Retrieve scan context */ + /*************************/ + rkey = OCIRawPtr(envhp, sctx->sctx_qxiqtim); + rkeylen = OCIRawSize(envhp, sctx->sctx_qxiqtim); + + if (qxiqtce(ctx, errhp, OCIContextGetValue((dvoid *)usrhp, errhp, + rkey, (ub1)rkeylen, + (dvoid **)&(icx)))) + return(rval); + } + + /***********************************/ + /* Check that the bounds are valid */ + /***********************************/ + /* convert from oci numbers to native numbers */ + if (qxiqtce(ctx, errhp, OCINumberToInt(errhp, strt, + sizeof(strtval), + OCI_NUMBER_SIGNED, + (dvoid *)&strtval))) + return(rval); + + if (qxiqtce(ctx, errhp, OCINumberToInt(errhp, stop, + sizeof(stopval), + OCI_NUMBER_SIGNED, + (dvoid *)&stopval))) + return(rval); + + /* verify that strtval/stopval are both either 0 or 1 */ + if (!(((strtval == 0) && (stopval == 0)) || + ((strtval == 1) && (stopval == 1)))) + { + strcpy(errmsg, (char *)"Incorrect predicate for sbtree operator"); + errmsglen = (size_t)strlen(errmsg); + if (OCIExtProcRaiseExcpWithMsg(ctx, errnum, (text *)errmsg, errmsglen) + != OCIEXTPROC_SUCCESS) + /* Use cartridge error services here */; + return(rval); + } + + /*********************************************/ + /* Generate the SQL statement to be executed */ + /*********************************************/ + if (memcmp((dvoid *)OCIStringPtr(envhp, pr->ObjectName), (dvoid *)"EQ", 2) + == 0) + if (strtval == 1) + strcpy(relop, (char *)"="); + else + strcpy(relop, (char *)"!="); + else if (memcmp((dvoid *)OCIStringPtr(envhp, pr->ObjectName), (dvoid *)"LT", + 2) == 0) + if (strtval == 1) + strcpy(relop, (char *)"<"); + else + strcpy(relop, (char *)">="); + else + if (strtval == 1) + strcpy(relop, (char *)">"); + else + strcpy(relop, (char *)"<="); + + if (ix_ind->IndexPartition == OCI_IND_NULL) + (void)sprintf(selstmt, "select f2 from %s.%s_sbtree where f1 %s :val", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName), relop); + else + (void)sprintf(selstmt, "select f2 from %s.%s_%s_sbtree where f1 %s :val", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName), + OCIStringPtr(envhp, ix->IndexPartition), relop); + + + /***********************************/ + /* Parse, bind, define and execute */ + /***********************************/ + if (sctx_ind ->atomic_qxiqtin == OCI_IND_NULL || + sctx_ind ->scind_qxiqtin == OCI_IND_NULL) + { + /* allocate stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleAlloc((dvoid *)envhp, + (dvoid **)&(icx->stmthp), + (ub4)OCI_HTYPE_STMT, + (size_t)0, (dvoid **)0))) + return(rval); + } + + /* prepare the statement */ + if (qxiqtce(ctx, errhp, OCIStmtPrepare(icx->stmthp, errhp, + (text *)selstmt, + (ub4)strlen(selstmt), + OCI_NTV_SYNTAX, + OCI_DEFAULT))) + return(rval); + + /* Set up bind */ + if (qxiqtce(ctx, errhp, OCIBindByPos(icx->stmthp, &(icx->bndp), + errhp, (ub4)1, + (dvoid *)cmpval, + (sb4)(strlen(cmpval)+1), + (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Set up define */ + if (qxiqtce(ctx, errhp, OCIDefineByPos(icx->stmthp, &(icx->defnp), + errhp, (ub4)1, + (dvoid *)(icx->ridp), + (sb4) sizeof(icx->ridp), + (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)OCI_DEFAULT))) + return(rval); + + /* execute */ + if (qxiqtce(ctx, errhp, OCIStmtExecute(svchp, icx->stmthp, + errhp, (ub4)0, + (ub4)0, (OCISnapshot *)NULL, + (OCISnapshot *)NULL, + (ub4)OCI_DEFAULT))) + return(rval); + + /************************************/ + /* Set index context to be returned */ + /************************************/ + if (sctx_ind ->atomic_qxiqtin == OCI_IND_NULL || + sctx_ind ->scind_qxiqtin == OCI_IND_NULL) + { + /* generate a key */ + if (qxiqtce(ctx, errhp, OCIContextGenerateKey((dvoid *)usrhp, + errhp, &key))) + return(rval); + + /* set the memory address of the struct to be saved in the context */ + if (qxiqtce(ctx, errhp, OCIContextSetValue((dvoid *)usrhp, errhp, + OCI_DURATION_STATEMENT, + (ub1 *)&key, + (ub1)sizeof(key), + (dvoid *)icx))) + return(rval); + + /* set the key as the member of "sctx" */ + if (qxiqtce(ctx, errhp, OCIRawAssignBytes(envhp, errhp, + (ub1 *)&key, + (ub4)sizeof(key), + &(sctx->sctx_qxiqtim)))) + return(rval); + + sctx_ind->atomic_qxiqtin = OCI_IND_NOTNULL; + sctx_ind->scind_qxiqtin = OCI_IND_NOTNULL; + + return(rval); + } + + return(rval); +} + +/* ODCIIndexFetch function */ +OCINumber *qxiqtbpf(ctx, self, self_ind, nrows, nrows_ind, + rids, rids_ind, env, env_ind) +OCIExtProcContext *ctx; +qxiqtim *self; +qxiqtin *self_ind; +OCINumber *nrows; +short nrows_ind; +OCIArray **rids; +short *rids_ind; +ODCIEnv *env; +ODCIEnv_ind *env_ind; +{ + sword status; + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCISession *usrhp = (OCISession *) 0; /* user handle */ + qxiqtcx *icx = (qxiqtcx *) 0; /* state to be saved for later calls */ + + int idx = 1; + int nrowsval; + + OCIArray *ridarrp = *rids; /* rowid collection */ + OCIString *ridstr = (OCIString *)0; + + int done = 0; + int retval = (int)ODCI_SUCCESS; + OCINumber *rval = (OCINumber *)0; + + ub1 *key; /* key to retrieve context */ + ub4 keylen; /* length of key */ + + /*******************/ + /* Get OCI handles */ + /*******************/ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, + OCINumberFromInt(errhp, (dvoid *)&retval, sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /* get the user handle */ + if (qxiqtce(ctx, errhp, OCIAttrGet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)&usrhp, (ub4 *)0, + (ub4)OCI_ATTR_SESSION, errhp))) + return(rval); + + /********************************/ + /* Retrieve context from key */ + /********************************/ + key = OCIRawPtr(envhp, self->sctx_qxiqtim); + keylen = OCIRawSize(envhp, self->sctx_qxiqtim); + + if (qxiqtce(ctx, errhp, OCIContextGetValue((dvoid *)usrhp, errhp, + key, (ub1)keylen, + (dvoid **)&(icx)))) + return(rval); + + /* get value of nrows */ + if (qxiqtce(ctx, errhp, OCINumberToInt(errhp, nrows, + sizeof(nrowsval), + OCI_NUMBER_SIGNED, + (dvoid *)&nrowsval))) + return(rval); + + /****************/ + /* Fetch rowids */ + /****************/ + while (!done) + { + if (idx > nrowsval) + done = 1; + else + { + status = OCIStmtFetch(icx->stmthp, errhp, (ub4)1, (ub2) 0, + (ub4)OCI_DEFAULT); + if (status == OCI_NO_DATA) + { + short col_ind = OCI_IND_NULL; + /* have to create dummy oci string */ + OCIStringAssignText(envhp, errhp, (text *)"dummy", + (ub2)5, &ridstr); + /* append null element to collection */ + if (qxiqtce(ctx, errhp, OCICollAppend(envhp, errhp, + (dvoid *)ridstr, + (dvoid *)&col_ind, + (OCIColl *)ridarrp))) + return(rval); + done = 1; + } + else if (status == OCI_SUCCESS) + { + OCIStringAssignText(envhp, errhp, (text *)icx->ridp, + (ub2)18, (OCIString **)&ridstr); + /* append rowid to collection */ + if (qxiqtce(ctx, errhp, OCICollAppend(envhp, errhp, + (dvoid *)ridstr, + (dvoid *)0, + (OCIColl *)ridarrp))) + return(rval); + idx++; + } + else if (qxiqtce(ctx, errhp, status)) + return(rval); + } + } + + /* free ridstr finally */ + if (ridstr && + (qxiqtce(ctx, errhp, OCIStringResize(envhp, errhp, (ub4)0, + &ridstr)))) + return(rval); + + *rids_ind = OCI_IND_NOTNULL; + + return(rval); +} + + +/* ODCIIndexClose function */ +OCINumber *qxiqtbpc(ctx, self, self_ind, env, env_ind) +OCIExtProcContext *ctx; +qxiqtim *self; +qxiqtin *self_ind; +ODCIEnv *env; +ODCIEnv_ind *env_ind; +{ + sword status; + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCISession *usrhp = (OCISession *) 0; /* user handle */ + qxiqtcx *icx = (qxiqtcx *) 0; /* state to be saved for later calls */ + + int retval = (int) ODCI_SUCCESS; + OCINumber *rval = (OCINumber *)0; + + ub1 *key; /* key to retrieve context */ + ub4 keylen; /* length of key */ + + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /* get the user handle */ + if (qxiqtce(ctx, errhp, OCIAttrGet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)&usrhp, (ub4 *)0, + (ub4)OCI_ATTR_SESSION, errhp))) + return(rval); + + /********************************/ + /* Retrieve context using key */ + /********************************/ + key = OCIRawPtr(envhp, self->sctx_qxiqtim); + keylen = OCIRawSize(envhp, self->sctx_qxiqtim); + + if (qxiqtce(ctx, errhp, OCIContextGetValue((dvoid *)usrhp, errhp, + key, (ub1)keylen, + (dvoid **)&(icx)))) + return(rval); + + /* Free handles and memory */ + if (qxiqtce(ctx, errhp, OCIHandleFree((dvoid *)icx->stmthp, + (ub4)OCI_HTYPE_STMT))) + return(rval); + + if (qxiqtce(ctx, errhp, OCIMemoryFree((dvoid *)usrhp, errhp, (dvoid *)icx))) + return(rval); + + return(rval); +} + + +/*--------------------------------------------------------------------------- + PRIVATE FUNCTIONS + ---------------------------------------------------------------------------*/ +static int qxiqtce(ctx, errhp, status) +OCIExtProcContext *ctx; +OCIError *errhp; +sword status; +{ + text errbuf[512]; + sb4 errcode = 0; + int errnum = 29400; /* choose some oracle error number */ + int rc = 0; + + switch (status) + { + case OCI_SUCCESS: + rc = 0; + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4)1, (text *)NULL, &errcode, + errbuf, (ub4)sizeof(errbuf), OCI_HTYPE_ERROR); + OCIExtProcRaiseExcpWithMsg(ctx, errnum, errbuf, strlen((char *)errbuf)); + rc = 1; + break; + default: + (void) sprintf((char *)errbuf, "Warning - some error\n"); + OCIExtProcRaiseExcpWithMsg(ctx, errnum, errbuf, strlen((char *)errbuf)); + rc = 1; + break; + } + return (rc); +} + +/* end of file extdemo5.c */ + diff --git a/extdemo5.h b/extdemo5.h new file mode 100644 index 0000000..e8fb980 --- /dev/null +++ b/extdemo5.h @@ -0,0 +1,173 @@ +/* + * $Header: extdemo5.h 30-apr-2001.16:05:04 hdnguyen Exp $ + */ + +/* Copyright (c) 2001, Oracle Corporation. All rights reserved. +*/ + +/* + NAME + extdemo5.h - Extensible Indexing example implemented as C routines + for local domain index on varchar2 column of a + range partitioned table. + + DESCRIPTION + This file contains the definitions of the DML and Query routines + for the extensible indexing example that implements a simple btree + (sbtree). See extdemo5.sql for the SQL script that defines the + indextype. + + RELATED DOCUMENTS + + INSPECTION STATUS + Inspection date: + Inspection status: + Estimated increasing cost defects per page: + Rule sets: + + ACCEPTANCE REVIEW STATUS + Review date: + Review status: + Reviewers: + + PUBLIC FUNCTION(S) + qxiqtbps - QXIQT Btree Start routine + qxiqtbpf - QXIQT Btree Fetch routine + qxiqtbpc - QXIQT Btree Close routine + qxiqtbpi - QXIQT Btree Insert routine + qxiqtbpd - QXIQT Btree Delete routine + qxiqtbpu - QXIQT Btree Update routine + + PRIVATE FUNCTION(S) + qxiqtbe - QXIQT error reporting routine + + EXAMPLES + + NOTES + + + MODIFIED (MM/DD/YY) + hdnguyen 04/27/99 - misc. modification + spsundar 04/25/01 - Creation + +*/ + + +#ifndef EXTDEMO5_ORACLE +# define EXTDEMO5_ORACLE + +#ifndef OCI_ORACLE +# include +#endif +#ifndef ODCI_ORACLE +# include +#endif + +/*--------------------------------------------------------------------------- + PUBLIC TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + +#ifdef WIN32COMMON +#define DLLEXPORT __declspec(dllexport) +#else +#define DLLEXPORT +#endif + +/* index scan context - should be stored in "statement" duration memory + * and used by start, fetch and close routines. + */ +struct qxiqtcx +{ + OCIStmt *stmthp; + OCIDefine *defnp; + OCIBind *bndp; + char ridp[19]; +}; +typedef struct qxiqtcx qxiqtcx; + +/* The index implementation type is an ADT with a single RAW attribute + * which will be used to store the context key value. + * C mapping of the implementation type : + */ +struct qxiqtim +{ + OCIRaw *sctx_qxiqtim; +}; +typedef struct qxiqtim qxiqtim; + +struct qxiqtin +{ + short atomic_qxiqtin; + short scind_qxiqtin; +}; +typedef struct qxiqtin qxiqtin; + +/*--------------------------------------------------------------------------- + PUBLIC FUNCTIONS + ---------------------------------------------------------------------------*/ +/* ODCIIndexStart */ +OCINumber DLLEXPORT *qxiqtbps(/*_ OCIExtProcContext *ctx, + struct qxiqtim *sctx, struct qxiqtin *sctx_ind, + ODCIIndexInfo *ix, ODCIIndexInfo_ind *ix_ind, + ODCIPredInfo *pr, ODCIPredInfo_ind *pr_ind, + ODCIQueryInfo *qy, ODCIQueryInfo_ind *qy_ind, + OCINumber *strt, short strt_ind, + OCINumber *stop, short stop_ind, + char *cmpval, short cmpval_ind, + ODCIEnv *env, ODCIEnv_ind *env_ind _*/); + +/* ODCIIndexFetch */ +OCINumber DLLEXPORT *qxiqtbpf(/*_ OCIExtProcContext *ctx, + struct qxiqtim *self, struct qxiqtin *self_ind, + OCINumber *nrows, short nrows_ind, + OCIArray **rids, short *rids_ind, + ODCIEnv *env, ODCIEnv_ind *env_ind _*/); + +/* ODCIIndexClose */ +OCINumber DLLEXPORT *qxiqtbpc(/*_ OCIExtProcContext *ctx, + struct qxiqtim *self, struct qxiqtin *self_ind, + ODCIEnv *env, ODCIEnv_ind *env_ind _*/); + +/* ODCIIndexInsert */ +OCINumber DLLEXPORT *qxiqtbpi(/*_ OCIExtProcContext *ctx, + ODCIIndexInfo *ix, + ODCIIndexInfo_ind *ix_ind, + char *rid, + short rid_ind, + char *newval, + short newval_ind, + ODCIEnv *env, ODCIEnv_ind *env_ind _*/); + +/* ODCIIndexDelete */ +OCINumber DLLEXPORT *qxiqtbpd(/*_ OCIExtProcContext *ctx, + ODCIIndexInfo *ix, + ODCIIndexInfo_ind *ix_ind, + char *rid, + short rid_ind, + char *oldval, + short oldval_ind, + ODCIEnv *env, ODCIEnv_ind *env_ind _*/); + +/* ODCIIndexUpdate */ +OCINumber DLLEXPORT *qxiqtbpu(/*_ OCIExtProcContext *ctx, + ODCIIndexInfo *ix, + ODCIIndexInfo_ind *ix_ind, + char *rid, + short rid_ind, + char *oldval, + short oldval_ind, + char *newval, + short newval_ind, + ODCIEnv *env, ODCIEnv_ind *env_ind _*/); + +/*--------------------------------------------------------------------------- + PRIVATE FUNCTIONS + ---------------------------------------------------------------------------*/ +static int qxiqtce(/*_ OCIExtProcContext *ctx, OCIError *errhp, + sword status _*/); + +#endif /* EXTDEMO5_ORACLE */ diff --git a/extdemo5.sql b/extdemo5.sql new file mode 100644 index 0000000..7c38ab1 --- /dev/null +++ b/extdemo5.sql @@ -0,0 +1,768 @@ +rem +rem $Header: extdemo5.sql 30-apr-2001.16:05:05 hdnguyen Exp $ +rem +rem extdemo5.sql +rem +rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +rem +rem NAME +rem extdemo5.sql - An extensible indexing example implemented +rem as C routines for local domain index on +rem varchar2 column of a range partitioned table. +rem +rem DESCRIPTION +rem This file demonstrates the definition and usage of a simple +rem btree indextype whose routines are implemented as C callouts. +rem The C routines are in the file extdemo5.c +rem The header file is extdemo5.h +rem +rem The following steps should have been done before running +rem this script. +rem 1. Compile the C file (i.e make -f demo_rdbms.mk demos) +rem 2. Create a user named extdemo5 with password extdemo5 +rem with all the necessary privileges. +rem 3. Create a library in extdemo5 schema called extdemo5l +rem which points to the compiled extdemo5.c +rem +rem The design of the indextype is as follows : +rem +rem The sbtree indextype implemented here will support the evaluation +rem of three user-defined operators : gt(Greater Than), lt(Less Than) +rem and eq(EQuals). These operators can operate on the operands of +rem VARCHAR2 datatype. +rem To simplify the implementation of the indextype, we will store +rem the index data in a regular table. +rem Thus, our code merely translates operations on the SB-tree into +rem operations on the table storing the index data. +rem When a user creates a SB-tree index, we will create a table +rem consisting of the indexed column and a rowid column. Inserts into +rem the base table will cause appropriate insertions into the index table. +rem Deletes and updates are handled similarly. +rem When the SB-tree is queried based on a user-defined operator (one +rem of gt, lt and eq), we will fire off an appropriate query against +rem the index table to retrieve all the satisfying rows and return them. +rem +rem NOTE: +rem The database has to be at compatible = 9.0.0 or above +rem +rem MODIFIED (MM/DD/YY) +rem hdnguyen 04/30/01 - modified MergePartition. +rem hdnguyen 04/27/01 - misc. modification +rem spsundar 04/25/01 - Created + +--------------------------------------------------------------------- +-- SIMPLE B-TREE Index Method Implemented as C Callouts -- +--------------------------------------------------------------------- + +connect extdemo5/extdemo5 +set echo off +@'?/rdbms/admin/utlxplan.sql' +set echo on + +-- CREATE FUNCTIONAL IMPLEMENTATIONS for operators + +create function bt_eq(a varchar2, b varchar2) return number as +begin + if a = b then + return 1; + else + return 0; + end if; +end; +/ +show errors + +create function bt_lt(a varchar2, b varchar2) return number as +begin + if a < b then + return 1; + else + return 0; + end if; +end; +/ +show errors + +create function bt_gt(a varchar2, b varchar2) return number as +begin + if a > b then + return 1; + else + return 0; + end if; +end; +/ +show errors + +-- CREATE BTREE OPERATORS + +create operator eq binding (varchar2, varchar2) + return number using bt_eq; + +create operator lt binding (varchar2, varchar2) + return number using bt_lt; + +create operator gt binding (varchar2, varchar2) + return number using bt_gt; + + +-- CREATE INDEXTYPE IMPLEMENTATION TYPE +create type psbtree_im as object +( + scanctx RAW(4), + static function ODCIGetInterfaces(ifclist OUT sys.ODCIObjectList) + return NUMBER, + + static function ODCIIndexCreate (ia sys.ODCIIndexInfo, + parms varchar2, env sys.ODCIEnv) return NUMBER, + + static function ODCIIndexDrop(ia sys.ODCIIndexInfo, + env sys.ODCIEnv) return NUMBER, + + static function ODCIIndexInsert(ia sys.ODCIIndexInfo, rid VARCHAR2, + newval VARCHAR2, env sys.ODCIEnv) return NUMBER, + + static function ODCIIndexDelete(ia sys.ODCIIndexInfo, rid VARCHAR2, + oldval VARCHAR2, env sys.ODCIEnv) return NUMBER, + + static function ODCIIndexUpdate(ia sys.ODCIIndexInfo, rid VARCHAR2, + oldval VARCHAR2, newval VARCHAR2, env sys.ODCIEnv) + return NUMBER, + + static function ODCIIndexTruncate(ia sys.ODCIIndexInfo, + env sys.ODCIEnv) return NUMBER, + + static function ODCIIndexExchangePartition (ia sys.ODCIIndexInfo, + ia1 sys.ODCIIndexInfo, env sys.ODCIEnv) return NUMBER, + + static function ODCIIndexMergePartition (ia sys.ODCIIndexInfo, + part_name1 sys.ODCIPartInfo, part_name2 sys.ODCIPartInfo, + parms varchar2, env sys.ODCIEnv) return NUMBER, + + static function ODCIIndexSplitPartition (ia sys.ODCIIndexInfo, + part_name1 sys.ODCIPartInfo, part_name2 sys.ODCIPartInfo, + parms varchar2, env sys.ODCIEnv) return NUMBER, + + static function ODCIIndexStart(sctx IN OUT psbtree_im, + ia sys.ODCIIndexInfo, op sys.ODCIPredInfo, + qi sys.ODCIQueryInfo, strt number, stop number, + cmpval varchar2, env sys.ODCIEnv) + return NUMBER, + + member function ODCIIndexFetch(nrows number, + rids OUT sys.ODCIRidList, env sys.ODCIEnv) + return NUMBER, + + member function ODCIIndexClose(env sys.ODCIEnv) return NUMBER +); +/ +show errors + +--------------------------------- +-- CREATE IMPLEMENTATION UNIT -- +--------------------------------- + +-- CREATE TYPE BODY +create or replace type body psbtree_im +is + static function ODCIGetInterfaces(ifclist OUT sys.ODCIObjectList) + return number is + begin + ifclist := sys.ODCIObjectList(sys.ODCIObject('SYS','ODCIINDEX2')); + return ODCIConst.Success; + end ODCIGetInterfaces; + + static function ODCIIndexCreate (ia sys.ODCIIndexInfo, + parms varchar2, env sys.ODCIEnv) return number + is + i integer; + stmt varchar2(1000); + cnum integer; + junk integer; + begin + stmt := ''; + + if ((env.CallProperty is null) and (ia.IndexPartition is null )) then + stmt := 'create table ' ||ia.IndexSchema || '.' || ia.IndexName || + '_sbtree(f1, f2) as select ' || + ia.IndexCols(1).Colname || ', ROWID from ' || + ia.IndexCols(1).TableSchema || '.' || + ia.IndexCols(1).TableName; + end if; + + if ((env.CallProperty is not null) and (ia.IndexPartition is not null)) then + stmt := 'create table ' || ia.IndexSchema || '.' || ia.IndexName || + '_' || ia.IndexPartition || '_sbtree' || + '(f1, f2) as select ' || + ia.IndexCols(1).Colname || ', ROWID from ' || + ia.IndexCols(1).TableSchema || '.' || + ia.IndexCols(1).TableName || ' partition (' || + ia.IndexCols(1).tablepartition || ')'; + end if; + + if ((env.CallProperty is null) and (ia.IndexPartition is not null)) then + stmt := 'create table ' || ia.IndexSchema || '.' || ia.IndexName || + '_' || ia.IndexPartition || '_sbtree' || + '(f1, f2) as select ' || + ia.IndexCols(1).Colname || ', ROWID from ' || + ia.IndexCols(1).TableSchema || '.' || + ia.IndexCols(1).TableName || ' partition (' || + ia.IndexCols(1).TablePartition || ')'; + end if; + + dbms_output.put_line('Create'); + dbms_output.put_line(stmt); + + -- execute the statement + if ( (env.CallProperty is null) or + (env.CallProperty = sys.ODCIConst.IntermediateCall) ) then + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + end if; + + return ODCIConst.Success; + end; + + static function ODCIIndexDrop(ia sys.ODCIIndexInfo, env sys.ODCIEnv) + return number is + stmt varchar2(1000); + cnum integer; + junk integer; + begin + -- construct the sql statement + stmt := ''; + if ((env.CallProperty is null) and (ia.IndexPartition is null) ) then + stmt := 'drop table ' || ia.IndexSchema || '.' || ia.IndexName || + '_sbtree'; + else + if (ia.IndexPartition is not null) then + stmt := 'drop table ' || ia.IndexSchema || '.' || ia.IndexName || + '_' || ia.IndexPartition || '_sbtree'; + end if; + end if; + + dbms_output.put_line('Drop'); + dbms_output.put_line(stmt); + + -- execute the statement + if ( (env.CallProperty is null) or + (env.CallProperty = sys.ODCIConst.IntermediateCall) ) then + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + end if; + + return ODCIConst.Success; + end; + + static function ODCIIndexTruncate(ia sys.ODCIIndexInfo, env sys.ODCIEnv) + return number is + stmt varchar2(2000); + cnum integer; + junk integer; + begin + -- construct the sql statement + stmt := ''; + if ((env.CallProperty is null) and (ia.IndexPartition is null) ) then + stmt := 'truncate table ' || ia.IndexSchema || '.' || ia.IndexName || + '_sbtree'; + else + if (ia.IndexPartition is not null) then + stmt := 'truncate table ' || ia.IndexSchema || '.' || ia.IndexName || + '_' || ia.IndexPartition || '_sbtree'; + end if; + end if; + + dbms_output.put_line('Truncate'); + dbms_output.put_line(stmt); + + -- execute the statement + if ( (env.CallProperty is null) or + (env.CallProperty = sys.ODCIConst.IntermediateCall) ) then + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + end if; + + return ODCIConst.Success; + end; + + static function ODCIIndexExchangePartition(ia sys.ODCIIndexInfo, + ia1 sys.ODCIIndexInfo, env sys.ODCIEnv) + return number + is + stmt varchar2(2000); + cnum integer; + junk integer; + begin + stmt := ''; + dbms_output.put_line('Exchange Partitions'); + + -- construct the sql statement + stmt := 'alter table temp exchange partition p1 with table ' || + ia1.IndexSchema || '.' || ia1.IndexName || '_sbtree'; + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + + stmt := 'alter table temp exchange partition p1 with table ' || + ia.IndexSchema || '.' || ia.IndexName || + '_' || ia.IndexPartition || '_sbtree'; + + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + + stmt := 'alter table temp exchange partition p1 with table ' || + ia1.IndexSchema || '.' || ia1.IndexName || '_sbtree'; + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + + return ODCIConst.Success; + end; + + static function ODCIIndexMergePartition(ia sys.ODCIIndexInfo, + part_name1 sys.ODCIPartInfo, part_name2 sys.ODCIPartInfo, + parms varchar2, env sys.ODCIEnv) + return number + is + stmt varchar2(2000); + cnum integer; + junk integer; + begin + dbms_output.put_line('Merge Partitions'); + stmt := ''; + + if ( part_name2 is not null) then + stmt := 'create table ' || ia.IndexSchema || '.' || ia.IndexName || + '_' || part_name2.IndexPartition || '_sbtree' || + '(f1 ' || ia.IndexCols(1).ColTypeName || + '(30), f2 ROWID)'; + + dbms_output.put_line('create'); + dbms_output.put_line('Parameter string : ' || parms); + + dbms_output.put_line(stmt); + + -- execute the statement + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + end if; + + if ( part_name1 is not null) then + stmt := 'drop table ' || ia.IndexSchema || '.' || ia.IndexName || + '_' || part_name1.IndexPartition || '_sbtree'; + + dbms_output.put_line('drop'); + dbms_output.put_line(stmt); + + -- execute the statement + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + end if; + + if (ia.IndexPartition is not null) then + stmt := 'drop table ' || ia.IndexSchema || '.' || ia.IndexName || + '_' || ia.IndexPartition || '_sbtree'; + + dbms_output.put_line('drop'); + dbms_output.put_line(stmt); + + -- execute the statement + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + end if; + + return ODCIConst.Success; + end; + + static function ODCIIndexSplitPartition(ia sys.ODCIIndexInfo, + part_name1 sys.ODCIPartInfo, part_name2 sys.ODCIPartInfo, + parms varchar2, env sys.ODCIEnv) + return number + is + stmt varchar2(2000); + cnum integer; + junk integer; + begin + dbms_output.put_line('Split Partition'); + stmt := ''; + + if (ia.IndexPartition is not null) then + stmt := 'drop table ' || ia.IndexSchema || '.' || ia.IndexName || + '_' || ia.IndexPartition || '_sbtree'; + + dbms_output.put_line('drop'); + dbms_output.put_line(stmt); + + -- execute the statement + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + end if; + + if ( part_name1 is not null) then + stmt := 'create table ' || ia.IndexSchema || '.' || ia.IndexName || + '_' || part_name1.IndexPartition || '_sbtree' || + '( f1 ' || ia.IndexCols(1).ColTypeName || + '(30), f2 ROWID)'; + + dbms_output.put_line('create'); + dbms_output.put_line('Parameter string : ' || parms); + dbms_output.put_line(stmt); + + -- execute the statement + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + end if; + + if ( part_name2 is not null) then + stmt := 'create table ' || ia.IndexSchema || '.' || ia.IndexName || + '_' || part_name2.IndexPartition || '_sbtree' || + '( f1 ' || ia.IndexCols(1).ColTypeName || + '(30), f2 ROWID)'; + + dbms_output.put_line('create'); + dbms_output.put_line('Parameter string : ' || parms); + dbms_output.put_line(stmt); + + -- execute the statement + cnum := dbms_sql.open_cursor; + dbms_sql.parse(cnum, stmt, dbms_sql.native); + junk := dbms_sql.execute(cnum); + dbms_sql.close_cursor(cnum); + end if; + + return ODCIConst.Success; + end; + + static function ODCIIndexInsert(ia sys.ODCIIndexInfo, rid VARCHAR2, + newval VARCHAR2, env sys.ODCIEnv) + RETURN NUMBER AS external + name "qxiqtbpi" + library extdemo5l + WITH context + parameters ( + context, + ia, + ia indicator struct, + rid, + rid indicator, + newval, + newval indicator, + env, + env indicator struct, + return ocinumber + ); + + static function ODCIIndexDelete(ia sys.ODCIIndexInfo, rid VARCHAR2, + oldval VARCHAR2, env sys.ODCIEnv) + RETURN NUMBER AS external + name "qxiqtbpd" + library extdemo5l + WITH context + parameters ( + context, + ia, + ia indicator struct, + rid, + rid indicator, + oldval, + oldval indicator, + env, + env indicator struct, + return ocinumber + ); + + static function ODCIIndexUpdate(ia sys.ODCIIndexInfo, rid VARCHAR2, + oldval VARCHAR2, newval VARCHAR2, env sys.ODCIEnv) + RETURN NUMBER AS external + name "qxiqtbpu" + library extdemo5l + WITH context + parameters ( + context, + ia, + ia indicator struct, + rid, + rid indicator, + oldval, + oldval indicator, + newval, + newval indicator, + env, + env indicator struct, + return ocinumber + ); + + static function ODCIIndexStart(sctx in out psbtree_im, + ia sys.ODCIIndexInfo, op sys.ODCIPredInfo, + qi sys.ODCIQueryInfo, strt number, stop number, + cmpval varchar2, env sys.ODCIEnv) + RETURN NUMBER AS external + name "qxiqtbps" + library extdemo5l + WITH context + parameters ( + context, + sctx, + sctx indicator struct, + ia, + ia indicator struct, + op, + op indicator struct, + qi, + qi indicator struct, + strt, + strt indicator, + stop, + stop indicator, + cmpval, + cmpval indicator, + env, + env indicator struct, + return OCINumber + ); + + member function ODCIIndexFetch(nrows number, + rids OUT sys.ODCIRidList, env sys.ODCIEnv) + RETURN NUMBER AS external + name "qxiqtbpf" + library extdemo5l + WITH context + parameters ( + context, + self, + self indicator struct, + nrows, + nrows indicator, + rids, + rids indicator, + env, + env indicator struct, + return OCINumber + ); + + member function ODCIIndexClose (env sys.ODCIEnv) + ReTURN NUMBEr AS external + name "qxiqtbpc" + library extdemo5l + WITH context + parameters ( + context, + self, + self indicator struct, + env, + env indicator struct, + return OCINumber + ); + +end; +/ +show errors + +--------------------- +-- CREATE INDEXTYPE +--------------------- + +create indextype psbtree +for +eq(varchar2, varchar2), +lt(varchar2, varchar2), +gt(varchar2, varchar2) +using psbtree_im with local range partition; + +-------------------------- +-- USAGE EXAMPLES -- +-------------------------- +set serveroutput on size 20000 + +---------------- +-- CREATE TABLE +---------------- + +create table t1 (f1 number, f2 varchar2(200)) +partition by range(f1) +( + partition p1 values less than (101), + partition p2 values less than (201), + partition p3 values less than (301), + partition p4 values less than (401) + ); +insert into t1 values (10, 'aaaa'); +insert into t1 values (200, 'bbbb'); +insert into t1 values (100, 'cccc'); +insert into t1 values (300, 'dddd'); +insert into t1 values (400, 'eeee'); +commit; + +----------------------------- +-- CREATE LOCAL DOMAIN INDEX +----------------------------- + +create index it1 on t1(f2) indextype is psbtree local +(partition pe1 parameters('test1'), partition pe2, + partition pe3, partition pe4 parameters('test4')) +parameters('test'); + +----------- +-- INSERTS +----------- + +insert into t1 values (11, 'gggg'); +insert into t1 values (325, 'hhhh'); +insert into t1 values (327, 'iiii'); +select * from t1 order by f1; + +commit; + +----------- +-- DELETES +----------- + +delete from t1 where f1 = 325; +select * from t1 order by f1; + +rollback; + +select * from t1 where eq(f2, 'hhhh') = 1; + +delete from t1 where eq(f2, 'hhhh') = 1; +select * from t1 order by f1; + +select * from t1 where eq(f2, 'hhhh') = 1; + +commit; + +----------- +-- UPDATES +----------- +update t1 set f2 = '####' where f1=327; +select * from t1 order by f1; + +commit; + +update t1 set f1 = 328 where eq(f2, '####') = 1; + +select * from t1 where eq(f2, '####') = 1; + +----------- +-- QUERIES +----------- +-- partition extended table_name +explain plan for + select * from t1 partition(p1) where eq(f2, 'gggg') = 1; +set echo off +@@extdemo0 +set echo on + +select * from t1 partition(p1) where eq(f2, 'gggg') = 1; + +-- entire table +explain plan for + select * from t1 where eq(f2, 'gggg') = 1; +set echo off +@@extdemo0 +set echo on + +select * from t1 where eq(f2, 'gggg') = 1; + +-- subset of table +explain plan for + select * from t1 where eq(f2, 'dddd') = 1 and f1>101 ; +set echo off +@@extdemo0 +set echo on + +select * from t1 where eq(f2, 'dddd') = 1 and f1>101 ; + +-- single partition +explain plan for + select * from t1 where eq(f2, 'dddd') = 1 and f1 =300 ; +set echo off +@@extdemo0 +set echo on + +select * from t1 where eq(f2, 'dddd') = 1 and f1 = 300; + +select * from t1 where lt(f2, 'zzzz') = 1 order by f1; + +select * from t1 where gt(f2, 'aaaa') = 1 order by f1; + +-------------------------- +-- ALTER TABLE OPERATIONS +-------------------------- +--Alter Table Add Partition +alter table t1 add partition pp2 values less than (501); +insert into t1 values (500, 'ffff'); + +--Alter Table Drop Partition +alter table t1 drop partition pp2; + +--Alter Table Split Partition +alter table t1 split partition p2 at (150) into +(partition p21, partition p22); + +--Alter Table Merge Partition +alter table t1 merge partitions p22, p3 into partition pp2; + +--Create A Non-Partitioned Table +create table ext (f1 number, f2 varchar2(200)); + +insert into ext values (310, 'aaaa'); +insert into ext values (320, 'bbbb'); +insert into ext values (330, 'dddd'); + +-- NOW, CREATE DOMAIN INDEXES +create index it2 on ext(f2) indextype is psbtree; + +create table temp ( f1 varchar2(200) , f2 ROWID) +partition by range (f1) +( partition p1 values less than (maxvalue)); + +--Alter Table Exchange Partition + +alter table t1 exchange partition p4 with table ext including indexes; + +--Alter Table Modify Unusable +alter table t1 modify partition p4 unusable local indexes; + +--Alter Table Truncate Partition +alter table t1 truncate partition p1; + +------------ +-- CLEANUPS +------------ + +drop index it1; +drop index it2; +drop table t1; +drop table temp; +drop table ext; +drop indextype psbtree; +drop type psbtree_im; +drop operator eq; +drop operator lt; +drop operator gt; +drop function bt_eq; +drop function bt_lt; +drop function bt_gt; + + diff --git a/extdemo6.c b/extdemo6.c new file mode 100644 index 0000000..199df07 --- /dev/null +++ b/extdemo6.c @@ -0,0 +1,960 @@ +/* Copyright (c) 2008, Oracle. All rights reserved. */ + +/* + + NAME + extdemo6.c - Extensible Indexing example implemented as C routines + for system-managed local domain index on varchar2 column of + a range partitioned table. + + DESCRIPTION + This file contains the definitions of the DML and Query routines + for the extensible indexing example that implements a simple btree + (sbtree) using a system-managed approach. See extdemo6.sql for the + SQL script that defines the indextype. + + PUBLIC FUNCTION(S) + qxiqtbsps - QXIQT Btree Start routine + qxiqtbspf - QXIQT Btree Fetch routine + qxiqtbspc - QXIQT Btree Close routine + qxiqtbspi - QXIQT Btree Insert routine + qxiqtbspd - QXIQT Btree Delete routine + qxiqtbspu - QXIQT Btree Update routine + + PRIVATE FUNCTION(S) + qxiqtce - QXIQT error reporting routine + + NOTES + + + MODIFIED (MM/DD/YY) + yhu 06/06/08 - Creation + +*/ + +#ifndef EXTDEMO6_ORACLE +# include "extdemo6.h" +#endif +#include +#include + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + STATIC FUNCTION DECLARATIONS + ---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + PUBLIC FUNCTIONS + ---------------------------------------------------------------------------*/ + +/* ODCIIndexInsert function */ +OCINumber *qxiqtbspi( +OCIExtProcContext *ctx, +ODCIIndexInfo *ix, +ODCIIndexInfo_ind *ix_ind, +char *rid, +short rid_ind, +char *newval, +short newval_ind, +ODCIEnv *env, +ODCIEnv_ind *env_ind) +{ + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCIStmt *stmthp = (OCIStmt *) 0; /* statement handle */ + OCIBind *bndp = (OCIBind *) 0; /* bind handle */ + + int retval = (int)ODCI_SUCCESS; /* return from this function */ + OCINumber *rval = (OCINumber *)0; + + char insstmt[2000]; /* sql insert statement */ + ODCIColInfo *colinfo; /* column info */ + ODCIColInfo_ind *colinfo_ind; + boolean exists = TRUE; + int partiden; /* table partition iden */ + + + /* allocate memory for OCINumber first */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + + /* Get oci handles */ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /****************************** + * Construct insert Statement * + ******************************/ + if ( ix_ind->IndexPartitionIden == OCI_IND_NULL ) + (void)sprintf(insstmt, + "INSERT into %s.%s_sbtree values (:newval, :mrid)", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName)); + else + { + if (qxiqtce(ctx, errhp, OCICollGetElem(envhp, errhp, + (OCIColl *)ix->IndexCols, (sb4)0, &exists, + (void **) &colinfo, (void **) &colinfo_ind))) + return(rval); + + (void)sprintf(insstmt, + "INSERT into %s.%s_sbtree partition (DATAOBJ_TO_PARTITION(%s, :partiden)) values (:newval, :mrid)", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName), + OCIStringPtr(envhp, colinfo->TableName)); + } + + /**************************************** + * Parse and Execute Create Statement * + ****************************************/ + + /* allocate stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleAlloc((dvoid *)envhp, + (dvoid **)&stmthp, + (ub4)OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0))) + return(rval); + + /* prepare the statement */ + if (qxiqtce(ctx, errhp, OCIStmtPrepare(stmthp, errhp, + (text *)insstmt, + (ub4)strlen(insstmt), + OCI_NTV_SYNTAX, + OCI_DEFAULT))) + return(rval); + + if (ix_ind->IndexPartitionIden != OCI_IND_NULL) + { + /* Convert partiden to integer from OCINumber */ + if (qxiqtce(ctx, errhp, OCINumberToInt(errhp, + &(colinfo->TablePartitionIden), + sizeof(partiden), + OCI_NUMBER_SIGNED, + ( void *)&partiden))) + return(rval); + + /* Set up bind for partiden */ + if (qxiqtce(ctx, errhp, OCIBindByName(stmthp, &bndp, errhp, + (text *)":partiden", + sizeof(":partiden")-1, + (dvoid *)&partiden, + (sb4)(sizeof(partiden)), + (ub2)SQLT_INT, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + } + + /* Set up bind for newval */ + if (qxiqtce(ctx, errhp, OCIBindByName(stmthp, &bndp, errhp, + (text *)":newval", + sizeof(":newval")-1, + (dvoid *)newval, + (sb4)(strlen(newval)+1), + (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Set up bind for rid */ + if (qxiqtce(ctx, errhp, OCIBindByName(stmthp, &bndp, errhp, + (text *)":mrid", + sizeof(":mrid")-1, + (dvoid *)rid, + (sb4)(strlen(rid)+1), + (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Execute statement */ + if (qxiqtce(ctx, errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, + (ub4)0, (OCISnapshot *)NULL, + (OCISnapshot *)NULL, + (ub4)OCI_DEFAULT))) + return(rval); + + /* free stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleFree((dvoid *)stmthp, + (ub4)OCI_HTYPE_STMT))) + return(rval); + + return(rval); +} + +/* ODCIIndexDelete function */ +OCINumber *qxiqtbspd( +OCIExtProcContext *ctx, +ODCIIndexInfo *ix, +ODCIIndexInfo_ind *ix_ind, +char *rid, +short rid_ind, +char *oldval, +short oldval_ind, +ODCIEnv *env, +ODCIEnv_ind *env_ind) +{ + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCIStmt *stmthp = (OCIStmt *) 0; /* statement handle */ + OCIBind *bndp = (OCIBind *) 0; /* bind handle */ + + int retval = (int)ODCI_SUCCESS; /* return from this function */ + OCINumber *rval = (OCINumber *)0; + + char delstmt[2000]; /* sql delete statement */ + ODCIColInfo *colinfo; /* column info */ + ODCIColInfo_ind *colinfo_ind; + boolean exists = TRUE; + int partiden; /* table partition iden */ + + /* Get oci handles */ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /****************************** + * Construct delete Statement * + ******************************/ + if (ix_ind->IndexPartitionIden == OCI_IND_NULL ) + (void)sprintf(delstmt, + "DELETE FROM %s.%s_sbtree WHERE f2 = :rr", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName)); + else + { + if (qxiqtce(ctx, errhp, OCICollGetElem(envhp, errhp, + (OCIColl *)ix->IndexCols, (sb4)0, &exists, + (void **) &colinfo, (void **) &colinfo_ind))) + return(rval); + + (void)sprintf(delstmt, + "DELETE FROM %s.%s_sbtree partition (DATAOBJ_TO_PARTITION(%s, :partiden)) WHERE f2 = :rr", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName), + OCIStringPtr(envhp, colinfo->TableName)); + } + + /**************************************** + * Parse and Execute delete Statement * + ****************************************/ + + /* allocate stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleAlloc((dvoid *)envhp, + (dvoid **)&stmthp, + (ub4)OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0))) + return(rval); + + /* prepare the statement */ + if (qxiqtce(ctx, errhp, OCIStmtPrepare(stmthp, errhp, + (text *)delstmt, + (ub4)strlen(delstmt), + OCI_NTV_SYNTAX, + OCI_DEFAULT))) + return(rval); + + if (ix_ind->IndexPartitionIden != OCI_IND_NULL) + { + /* Convert partiden to integer from OCINumber */ + if (qxiqtce(ctx, errhp, OCINumberToInt(errhp, + &(colinfo->TablePartitionIden), + sizeof(partiden), + OCI_NUMBER_SIGNED, + ( void *)&partiden))) + return(rval); + + /* Set up bind for partiden */ + if (qxiqtce(ctx, errhp, OCIBindByName(stmthp, &bndp, errhp, + (text *)":partiden", + sizeof(":partiden")-1, + (dvoid *)&partiden, + (sb4)(sizeof(partiden)), + (ub2)SQLT_INT, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + } + + /* Set up bind for rid */ + if (qxiqtce(ctx, errhp, OCIBindByName(stmthp, &bndp, errhp, + (text *)":rr", + sizeof(":rr")-1, + (dvoid *)rid, + (sb4)(strlen(rid)+1), + (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Execute statement */ + if (qxiqtce(ctx, errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, + (ub4)0, (OCISnapshot *)NULL, + (OCISnapshot *)NULL, + (ub4)OCI_DEFAULT))) + return(rval); + + /* free stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleFree((dvoid *)stmthp, + (ub4)OCI_HTYPE_STMT))) + return(rval); + + return(rval); +} + +/* ODCIIndexUpdate function */ +OCINumber *qxiqtbspu( +OCIExtProcContext *ctx, +ODCIIndexInfo *ix, +ODCIIndexInfo_ind *ix_ind, +char *rid, +short rid_ind, +char *oldval, +short oldval_ind, +char *newval, +short newval_ind, +ODCIEnv *env, +ODCIEnv_ind *env_ind) +{ + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCIStmt *stmthp = (OCIStmt *) 0; /* statement handle */ + OCIBind *bndp = (OCIBind *) 0; /* bind handle */ + + int retval = (int)ODCI_SUCCESS; /* return from this function */ + OCINumber *rval = (OCINumber *)0; + + char updstmt[2000]; /* sql upate statement */ + ODCIColInfo *colinfo; /* column info */ + ODCIColInfo_ind *colinfo_ind; + boolean exists = TRUE; + int partiden; /* table partition iden */ + + /* Get oci handles */ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /****************************** + * Construct update Statement * + ******************************/ + if (ix_ind->IndexPartitionIden == OCI_IND_NULL) + (void)sprintf(updstmt, + "UPDATE %s.%s_sbtree SET f1 = :newval WHERE f2 = :rr", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName)); + else + { + if (qxiqtce(ctx, errhp, OCICollGetElem(envhp, errhp, + (OCIColl *)ix->IndexCols, (sb4)0, &exists, + (void **) &colinfo, (void **) &colinfo_ind))) + return(rval); + + (void)sprintf(updstmt, + "UPDATE %s.%s_sbtree partition (DATAOBJ_TO_PARTITION(%s, :partiden)) SET f1 = :newval WHERE f2 = :rr", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName), + OCIStringPtr(envhp, colinfo->TableName)); + } + + /**************************************** + * Parse and Execute Create Statement * + ****************************************/ + + /* allocate stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleAlloc((dvoid *)envhp, + (dvoid **)&stmthp, + (ub4)OCI_HTYPE_STMT, (size_t)0, + (dvoid **)0))) + return(rval); + + /* prepare the statement */ + if (qxiqtce(ctx, errhp, OCIStmtPrepare(stmthp, errhp, + (text *)updstmt, + (ub4)strlen(updstmt), + OCI_NTV_SYNTAX, + OCI_DEFAULT))) + return(rval); + + if (ix_ind->IndexPartitionIden != OCI_IND_NULL) + { + /* Convert partiden to integer from OCINumber */ + if (qxiqtce(ctx, errhp, OCINumberToInt(errhp, + &(colinfo->TablePartitionIden), + sizeof(partiden), + OCI_NUMBER_SIGNED, + ( void *)&partiden))) + return(rval); + + /* Set up bind for partiden */ + if (qxiqtce(ctx, errhp, OCIBindByName(stmthp, &bndp, errhp, + (text *)":partiden", + sizeof(":partiden")-1, + (dvoid *)&partiden, + (sb4)(sizeof(partiden)), + (ub2)SQLT_INT, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + } + + /* Set up bind for newval */ + if (qxiqtce(ctx, errhp, OCIBindByName(stmthp, &bndp, errhp, + (text *)":newval", + sizeof(":newval")-1, + (dvoid *)newval, + (sb4)(strlen(newval)+1), + (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Set up bind for rid */ + if (qxiqtce(ctx, errhp, OCIBindByName(stmthp, &bndp, errhp, + (text *)":rr", + sizeof(":rr")-1, + (dvoid *)rid, + (sb4)(strlen(rid)+1), + (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Execute statement */ + if (qxiqtce(ctx, errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, + (ub4)0, (OCISnapshot *)NULL, + (OCISnapshot *)NULL, + (ub4)OCI_DEFAULT))) + return(rval); + + /* free stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleFree((dvoid *)stmthp, + (ub4)OCI_HTYPE_STMT))) + return(rval); + + return(rval); +} + +/* ODCIIndexStart function */ +OCINumber *qxiqtbsps( +OCIExtProcContext *ctx, +qxiqtim *sctx, +qxiqtin *sctx_ind, +ODCIIndexInfo *ix, +ODCIIndexInfo_ind *ix_ind, +ODCIPredInfo *pr, +ODCIPredInfo_ind *pr_ind, +ODCIQueryInfo *qy, +ODCIQueryInfo_ind *qy_ind, +OCINumber *strt, +short strt_ind, +OCINumber *stop, +short stop_ind, +char *cmpval, +short cmpval_ind, +ODCIEnv *env, +ODCIEnv_ind *env_ind) +{ + sword status; + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCISession *usrhp = (OCISession *) 0; /* user handle */ + qxiqtcx *icx = (qxiqtcx *) 0; /* state to be saved for later calls */ + + int strtval; /* start bound */ + int stopval; /* stop bound */ + + int errnum = 29400; /* choose some oracle error number */ + char errmsg[512]; /* error message buffer */ + size_t errmsglen; /* Length of error message */ + + char relop[3]; /* relational operator used in sql stmt */ + char selstmt[2000]; /* sql select statement */ + + int retval = (int)ODCI_SUCCESS; /* return from this function */ + OCINumber *rval = (OCINumber *)0; + ub4 key; /* key value set in "sctx" */ + + ub1 *rkey; /* key to retrieve context */ + ub4 rkeylen; /* length of key */ + ODCIColInfo *colinfo; /* column info */ + ODCIColInfo_ind *colinfo_ind; + boolean exists = TRUE; + int partiden; /* table partition iden */ + + /* Get oci handles */ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /* get the user handle */ + if (qxiqtce(ctx, errhp, OCIAttrGet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)&usrhp, (ub4 *)0, + (ub4)OCI_ATTR_SESSION, + errhp))) + return(rval); + + /**********************************************/ + /* Allocate memory to hold index scan context */ + /**********************************************/ + if (sctx_ind ->atomic_qxiqtin == OCI_IND_NULL || + sctx_ind ->scind_qxiqtin == OCI_IND_NULL) + { + if (qxiqtce(ctx, errhp, OCIMemoryAlloc((dvoid *)usrhp, errhp, + (dvoid **)&icx, + OCI_DURATION_STATEMENT, + (ub4)(sizeof(qxiqtcx)), + OCI_MEMORY_CLEARED))) + return(rval); + + icx->stmthp = (OCIStmt *)0; + icx->defnp = (OCIDefine *)0; + icx->bndp = (OCIBind *)0; + } + else + { + /*************************/ + /* Retrieve scan context */ + /*************************/ + rkey = OCIRawPtr(envhp, sctx->sctx_qxiqtim); + rkeylen = OCIRawSize(envhp, sctx->sctx_qxiqtim); + + if (qxiqtce(ctx, errhp, OCIContextGetValue((dvoid *)usrhp, errhp, + rkey, (ub1)rkeylen, + (dvoid **)&(icx)))) + return(rval); + } + + /***********************************/ + /* Check that the bounds are valid */ + /***********************************/ + /* convert from oci numbers to native numbers */ + if (qxiqtce(ctx, errhp, OCINumberToInt(errhp, strt, + sizeof(strtval), + OCI_NUMBER_SIGNED, + (dvoid *)&strtval))) + return(rval); + + if (qxiqtce(ctx, errhp, OCINumberToInt(errhp, stop, + sizeof(stopval), + OCI_NUMBER_SIGNED, + (dvoid *)&stopval))) + return(rval); + + /* verify that strtval/stopval are both either 0 or 1 */ + if (!(((strtval == 0) && (stopval == 0)) || + ((strtval == 1) && (stopval == 1)))) + { + strcpy(errmsg, (char *)"Incorrect predicate for sbtree operator"); + errmsglen = (size_t)strlen(errmsg); + if (OCIExtProcRaiseExcpWithMsg(ctx, errnum, (text *)errmsg, errmsglen) + != OCIEXTPROC_SUCCESS) + /* Use cartridge error services here */; + return(rval); + } + + /*********************************************/ + /* Generate the SQL statement to be executed */ + /*********************************************/ + if (memcmp((dvoid *)OCIStringPtr(envhp, pr->ObjectName), (dvoid *)"EQ", 2) + == 0) + if (strtval == 1) + strcpy(relop, (char *)"="); + else + strcpy(relop, (char *)"!="); + else if (memcmp((dvoid *)OCIStringPtr(envhp, pr->ObjectName), (dvoid *)"LT", + 2) == 0) + if (strtval == 1) + strcpy(relop, (char *)"<"); + else + strcpy(relop, (char *)">="); + else + if (strtval == 1) + strcpy(relop, (char *)">"); + else + strcpy(relop, (char *)"<="); + + if (ix_ind->IndexPartitionIden == OCI_IND_NULL) + (void)sprintf(selstmt, "select f2 from %s.%s_sbtree where f1 %s :val", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName), relop); + else + { + + if (qxiqtce(ctx, errhp, OCICollGetElem(envhp, errhp, + (OCIColl *)ix->IndexCols, (sb4)0, &exists, + (void **) &colinfo, (void **) &colinfo_ind))) + return(rval); + (void)sprintf(selstmt, "select f2 from %s.%s_sbtree partition (DATAOBJ_TO_PARTITION(%s, :partiden)) where f1 %s :val", + OCIStringPtr(envhp, ix->IndexSchema), + OCIStringPtr(envhp, ix->IndexName), + OCIStringPtr(envhp, colinfo->TableName), relop); + } + + /***********************************/ + /* Parse, bind, define and execute */ + /***********************************/ + if (sctx_ind ->atomic_qxiqtin == OCI_IND_NULL || + sctx_ind ->scind_qxiqtin == OCI_IND_NULL) + { + /* allocate stmt handle */ + if (qxiqtce(ctx, errhp, OCIHandleAlloc((dvoid *)envhp, + (dvoid **)&(icx->stmthp), + (ub4)OCI_HTYPE_STMT, + (size_t)0, (dvoid **)0))) + return(rval); + } + + /* prepare the statement */ + if (qxiqtce(ctx, errhp, OCIStmtPrepare(icx->stmthp, errhp, + (text *)selstmt, + (ub4)strlen(selstmt), + OCI_NTV_SYNTAX, + OCI_DEFAULT))) + return(rval); + + + if (ix_ind->IndexPartitionIden != OCI_IND_NULL) + { + /* Convert partiden to integer from OCINumber */ + if (qxiqtce(ctx, errhp, OCINumberToInt(errhp, + &(colinfo->TablePartitionIden), + sizeof(partiden), + OCI_NUMBER_SIGNED, + ( void *)&partiden))) + return(rval); + + /* Set up bind for partiden */ + if (qxiqtce(ctx, errhp, OCIBindByName(icx->stmthp, &(icx->bndp), errhp, + (text *)":partiden", + sizeof(":partiden")-1, + (dvoid *)&partiden, + (sb4)(sizeof(partiden)), + (ub2)SQLT_INT, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + } + + /* Set up bind for compare value */ + if (qxiqtce(ctx, errhp, OCIBindByName(icx->stmthp, &(icx->bndp),errhp, + (text *)":val", + sizeof(":val")-1, + (dvoid *)cmpval, + (sb4)(strlen(cmpval)+1), + (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)0, (ub4 *)0, + (ub4)OCI_DEFAULT))) + return(rval); + + /* Set up define */ + if (qxiqtce(ctx, errhp, OCIDefineByPos(icx->stmthp, &(icx->defnp), + errhp, (ub4)1, + (dvoid *)(icx->ridp), + (sb4) sizeof(icx->ridp), + (ub2)SQLT_STR, + (dvoid *)0, (ub2 *)0, + (ub2 *)0, (ub4)OCI_DEFAULT))) + return(rval); + + /* execute */ + if (qxiqtce(ctx, errhp, OCIStmtExecute(svchp, icx->stmthp, + errhp, (ub4)0, + (ub4)0, (OCISnapshot *)NULL, + (OCISnapshot *)NULL, + (ub4)OCI_DEFAULT))) + return(rval); + + /************************************/ + /* Set index context to be returned */ + /************************************/ + if (sctx_ind ->atomic_qxiqtin == OCI_IND_NULL || + sctx_ind ->scind_qxiqtin == OCI_IND_NULL) + { + /* generate a key */ + if (qxiqtce(ctx, errhp, OCIContextGenerateKey((dvoid *)usrhp, + errhp, &key))) + return(rval); + + /* set the memory address of the struct to be saved in the context */ + if (qxiqtce(ctx, errhp, OCIContextSetValue((dvoid *)usrhp, errhp, + OCI_DURATION_STATEMENT, + (ub1 *)&key, + (ub1)sizeof(key), + (dvoid *)icx))) + return(rval); + + /* set the key as the member of "sctx" */ + if (qxiqtce(ctx, errhp, OCIRawAssignBytes(envhp, errhp, + (ub1 *)&key, + (ub4)sizeof(key), + &(sctx->sctx_qxiqtim)))) + return(rval); + + sctx_ind->atomic_qxiqtin = OCI_IND_NOTNULL; + sctx_ind->scind_qxiqtin = OCI_IND_NOTNULL; + + return(rval); + } + + return(rval); +} + +/* ODCIIndexFetch function */ +OCINumber *qxiqtbspf( +OCIExtProcContext *ctx, +qxiqtim *self, +qxiqtin *self_ind, +OCINumber *nrows, +short nrows_ind, +OCIArray **rids, +short *rids_ind, +ODCIEnv *env, +ODCIEnv_ind *env_ind) +{ + sword status; + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCISession *usrhp = (OCISession *) 0; /* user handle */ + qxiqtcx *icx = (qxiqtcx *) 0; /* state to be saved for later calls */ + + int idx = 1; + int nrowsval; + + OCIArray *ridarrp = *rids; /* rowid collection */ + OCIString *ridstr = (OCIString *)0; + + int done = 0; + int retval = (int)ODCI_SUCCESS; + OCINumber *rval = (OCINumber *)0; + + ub1 *key; /* key to retrieve context */ + ub4 keylen; /* length of key */ + + /*******************/ + /* Get OCI handles */ + /*******************/ + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, + OCINumberFromInt(errhp, (dvoid *)&retval, sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /* get the user handle */ + if (qxiqtce(ctx, errhp, OCIAttrGet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)&usrhp, (ub4 *)0, + (ub4)OCI_ATTR_SESSION, errhp))) + return(rval); + + /********************************/ + /* Retrieve context from key */ + /********************************/ + key = OCIRawPtr(envhp, self->sctx_qxiqtim); + keylen = OCIRawSize(envhp, self->sctx_qxiqtim); + + if (qxiqtce(ctx, errhp, OCIContextGetValue((dvoid *)usrhp, errhp, + key, (ub1)keylen, + (dvoid **)&(icx)))) + return(rval); + + /* get value of nrows */ + if (qxiqtce(ctx, errhp, OCINumberToInt(errhp, nrows, + sizeof(nrowsval), + OCI_NUMBER_SIGNED, + (dvoid *)&nrowsval))) + return(rval); + + /****************/ + /* Fetch rowids */ + /****************/ + while (!done) + { + if (idx > nrowsval) + done = 1; + else + { + status = OCIStmtFetch(icx->stmthp, errhp, (ub4)1, (ub2) 0, + (ub4)OCI_DEFAULT); + if (status == OCI_NO_DATA) + { + short col_ind = OCI_IND_NULL; + /* have to create dummy oci string */ + OCIStringAssignText(envhp, errhp, (text *)"dummy", + (ub2)5, &ridstr); + /* append null element to collection */ + if (qxiqtce(ctx, errhp, OCICollAppend(envhp, errhp, + (dvoid *)ridstr, + (dvoid *)&col_ind, + (OCIColl *)ridarrp))) + return(rval); + done = 1; + } + else if (status == OCI_SUCCESS) + { + OCIStringAssignText(envhp, errhp, (text *)icx->ridp, + (ub2)18, (OCIString **)&ridstr); + /* append rowid to collection */ + if (qxiqtce(ctx, errhp, OCICollAppend(envhp, errhp, + (dvoid *)ridstr, + (dvoid *)0, + (OCIColl *)ridarrp))) + return(rval); + idx++; + } + else if (qxiqtce(ctx, errhp, status)) + return(rval); + } + } + + /* free ridstr finally */ + if (ridstr && + (qxiqtce(ctx, errhp, OCIStringResize(envhp, errhp, (ub4)0, + &ridstr)))) + return(rval); + + *rids_ind = OCI_IND_NOTNULL; + + return(rval); +} + + +/* ODCIIndexClose function */ +OCINumber *qxiqtbspc( +OCIExtProcContext *ctx, +qxiqtim *self, +qxiqtin *self_ind, +ODCIEnv *env, +ODCIEnv_ind *env_ind) +{ + sword status; + OCIEnv *envhp = (OCIEnv *) 0; /* env. handle */ + OCISvcCtx *svchp = (OCISvcCtx *) 0; /* service handle */ + OCIError *errhp = (OCIError *) 0; /* error handle */ + OCISession *usrhp = (OCISession *) 0; /* user handle */ + qxiqtcx *icx = (qxiqtcx *) 0; /* state to be saved for later calls */ + + int retval = (int) ODCI_SUCCESS; + OCINumber *rval = (OCINumber *)0; + + ub1 *key; /* key to retrieve context */ + ub4 keylen; /* length of key */ + + if (qxiqtce(ctx, errhp, OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp))) + return(rval); + + /* set up return code */ + rval = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber)); + if (qxiqtce(ctx, errhp, OCINumberFromInt(errhp, (dvoid *)&retval, + sizeof(retval), + OCI_NUMBER_SIGNED, rval))) + return(rval); + + /* get the user handle */ + if (qxiqtce(ctx, errhp, OCIAttrGet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)&usrhp, (ub4 *)0, + (ub4)OCI_ATTR_SESSION, errhp))) + return(rval); + + /********************************/ + /* Retrieve context using key */ + /********************************/ + key = OCIRawPtr(envhp, self->sctx_qxiqtim); + keylen = OCIRawSize(envhp, self->sctx_qxiqtim); + + if (qxiqtce(ctx, errhp, OCIContextGetValue((dvoid *)usrhp, errhp, + key, (ub1)keylen, + (dvoid **)&(icx)))) + return(rval); + + /* Free handles and memory */ + if (qxiqtce(ctx, errhp, OCIHandleFree((dvoid *)icx->stmthp, + (ub4)OCI_HTYPE_STMT))) + return(rval); + + if (qxiqtce(ctx, errhp, OCIMemoryFree((dvoid *)usrhp, errhp, (dvoid *)icx))) + return(rval); + + return(rval); +} + + +/*--------------------------------------------------------------------------- + PRIVATE FUNCTIONS + ---------------------------------------------------------------------------*/ +static int qxiqtce( +OCIExtProcContext *ctx, +OCIError *errhp, +sword status) +{ + text errbuf[512]; + sb4 errcode = 0; + int errnum = 29400; /* choose some oracle error number */ + int rc = 0; + + switch (status) + { + case OCI_SUCCESS: + rc = 0; + break; + case OCI_ERROR: + (void) OCIErrorGet((dvoid *)errhp, (ub4)1, (text *)NULL, &errcode, + errbuf, (ub4)sizeof(errbuf), OCI_HTYPE_ERROR); + OCIExtProcRaiseExcpWithMsg(ctx, errnum, errbuf, strlen((char *)errbuf)); + rc = 1; + break; + default: + (void) sprintf((char *)errbuf, "Warning - some error\n"); + OCIExtProcRaiseExcpWithMsg(ctx, errnum, errbuf, strlen((char *)errbuf)); + rc = 1; + break; + } + return (rc); +} + +/* end of file extdemo6.c */ + diff --git a/extdemo6.h b/extdemo6.h new file mode 100644 index 0000000..362743d --- /dev/null +++ b/extdemo6.h @@ -0,0 +1,158 @@ +/* Copyright (c) 2008, Oracle. All rights reserved. */ + +/* + NAME + extdemo6.h - Extensible Indexing example implemented as C routines + for system-managed local domain index on varchar2 column + of a range partitioned table. + + DESCRIPTION + This file contains the definitions of the DML and Query routines + for the extensible indexing example that implements a simple btree + (sbtree) using a system-managed approach. See extdemo6.sql for the + SQL script that defines the indextype. + + RELATED DOCUMENTS + + PUBLIC FUNCTION(S) + qxiqtbsps - QXIQT Btree Start routine + qxiqtbspf - QXIQT Btree Fetch routine + qxiqtbspc - QXIQT Btree Close routine + qxiqtbspi - QXIQT Btree Insert routine + qxiqtbspd - QXIQT Btree Delete routine + qxiqtbspu - QXIQT Btree Update routine + + PRIVATE FUNCTION(S) + qxiqtce - QXIQT error reporting routine + + EXAMPLES + + NOTES + + + MODIFIED (MM/DD/YY) + yhu 06/06/08 - Creation + +*/ + +#ifndef EXTDEMO6_ORACLE +# define EXTDEMO6_ORACLE + +#ifndef OCI_ORACLE +# include +#endif +#ifndef ODCI_ORACLE +# include +#endif + +/*--------------------------------------------------------------------------- + PUBLIC TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + +#ifdef WIN32COMMON +#define DLLEXPORT __declspec(dllexport) +#else +#define DLLEXPORT +#endif + +/* index scan context - should be stored in "statement" duration memory + * and used by start, fetch and close routines. + */ +struct qxiqtcx +{ + OCIStmt *stmthp; + OCIDefine *defnp; + OCIBind *bndp; + char ridp[19]; +}; +typedef struct qxiqtcx qxiqtcx; + +/* The index implementation type is an ADT with a single RAW attribute + * which will be used to store the context key value. + * C mapping of the implementation type : + */ +struct qxiqtim +{ + OCIRaw *sctx_qxiqtim; +}; +typedef struct qxiqtim qxiqtim; + +struct qxiqtin +{ + short atomic_qxiqtin; + short scind_qxiqtin; +}; +typedef struct qxiqtin qxiqtin; + +/*--------------------------------------------------------------------------- + EXPORT FUNCTIONS + ---------------------------------------------------------------------------*/ +/* ODCIIndexStart */ +OCINumber DLLEXPORT *qxiqtbsps( OCIExtProcContext *ctx, + struct qxiqtim *sctx, struct qxiqtin *sctx_ind, + ODCIIndexInfo *ix, ODCIIndexInfo_ind *ix_ind, + ODCIPredInfo *pr, ODCIPredInfo_ind *pr_ind, + ODCIQueryInfo *qy, ODCIQueryInfo_ind *qy_ind, + OCINumber *strt, short strt_ind, + OCINumber *stop, short stop_ind, + char *cmpval, short cmpval_ind, + ODCIEnv *env, ODCIEnv_ind *env_ind ); + +/* ODCIIndexFetch */ +OCINumber DLLEXPORT *qxiqtbspf( OCIExtProcContext *ctx, + struct qxiqtim *self, struct qxiqtin *self_ind, + OCINumber *nrows, short nrows_ind, + OCIArray **rids, short *rids_ind, + ODCIEnv *env, ODCIEnv_ind *env_ind ); + +/* ODCIIndexClose */ +OCINumber DLLEXPORT *qxiqtbspc( OCIExtProcContext *ctx, + struct qxiqtim *self, struct qxiqtin *self_ind, + ODCIEnv *env, ODCIEnv_ind *env_ind ); + +/* ODCIIndexInsert */ +OCINumber DLLEXPORT *qxiqtbspi( OCIExtProcContext *ctx, + ODCIIndexInfo *ix, + ODCIIndexInfo_ind *ix_ind, + char *rid, + short rid_ind, + char *newval, + short newval_ind, + ODCIEnv *env, ODCIEnv_ind *env_ind ); + +/* ODCIIndexDelete */ +OCINumber DLLEXPORT *qxiqtbspd( OCIExtProcContext *ctx, + ODCIIndexInfo *ix, + ODCIIndexInfo_ind *ix_ind, + char *rid, + short rid_ind, + char *oldval, + short oldval_ind, + ODCIEnv *env, ODCIEnv_ind *env_ind ); + +/* ODCIIndexUpdate */ +OCINumber DLLEXPORT *qxiqtbspu( OCIExtProcContext *ctx, + ODCIIndexInfo *ix, + ODCIIndexInfo_ind *ix_ind, + char *rid, + short rid_ind, + char *oldval, + short oldval_ind, + char *newval, + short newval_ind, + ODCIEnv *env, ODCIEnv_ind *env_ind ); + + +/*--------------------------------------------------------------------------- + INTERNAL FUNCTIONS + ---------------------------------------------------------------------------*/ + +static int qxiqtce( OCIExtProcContext *ctx, OCIError *errhp, + sword status ); + +#endif /* EXTDEMO6_ORACLE */ diff --git a/extdemo6.sql b/extdemo6.sql new file mode 100644 index 0000000..4046a2b --- /dev/null +++ b/extdemo6.sql @@ -0,0 +1,722 @@ +Rem +Rem $Header: extdemo6.sql 06-jun-2008.09:31:29 yhu Exp $ +Rem +Rem extdemo6.sql +Rem +Rem Copyright (c) 2008, Oracle. All rights reserved. +Rem +Rem NAME +Rem extdemo6.sql - An extensible indexing example implemented +Rem as C routines for system-managed local domain index +Rem on varchar2 column of a range partitioned table. +Rem +Rem DESCRIPTION +Rem This file demonstrates the definition and usage of a simple +Rem btree indextype whose routines are implemented as C callouts. +Rem The C routines are in the file extdemo6.c +Rem The header file is extdemo6.h +Rem +Rem The following steps should have been done before running +Rem this script. +Rem 1. Compile the C file (i.e make -f demo_rdbms.mk demos) +Rem 2. Create a user named extdemo6 with password extdemo6 +Rem with all the necessary privileges. +Rem 3. Create a library in extdemo6 schema called extdemo6l +Rem which points to the compiled extdemo6.c +Rem +Rem The design of the indextype is as follows : +Rem +Rem The sbtree indextype implemented here will support the evaluation +Rem of three user-defined operators : gt(Greater Than), lt(Less Than) +Rem and eq(EQuals). These operators can operate on the operands of +Rem VARCHAR2 datatype. +Rem To simplify the implementation of the indextype, we will store +Rem the index data in a regular table. +Rem Thus, our code merely translates operations on the SB-tree into +Rem operations on the table storing the index data. +Rem When a user creates a SB-tree index, we will create a table +Rem consisting of the indexed column and a rowid column. Inserts into +Rem the base table will cause appropriate insertions into the index table. +Rem Deletes and updates are handled similarly. +Rem When the SB-tree is queried based on a user-defined operator (one +Rem of gt, lt and eq), we will fire off an appropriate query against +Rem the index table to retrieve all the satisfying rows and return them. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem yhu 06/06/08 - Created +Rem + +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 + +--------------------------------------------------------------------- +-- SIMPLE B-TREE Index Method Implemented as C Callouts -- +--------------------------------------------------------------------- + +connect extdemo6/extdemo6 +set echo off +@'?/rdbms/admin/utlxplan.sql' +set echo on + +-- CREATE FUNCTIONAL IMPLEMENTATIONS for operators + +create function bt_eq(a varchar2, b varchar2) return number as +begin + if a = b then + return 1; + else + return 0; + end if; +end; +/ +show errors + +create function bt_lt(a varchar2, b varchar2) return number as +begin + if a < b then + return 1; + else + return 0; + end if; +end; +/ +show errors + +create function bt_gt(a varchar2, b varchar2) return number as +begin + if a > b then + return 1; + else + return 0; + end if; +end; +/ +show errors + +-- CREATE BTREE OPERATORS + +create operator eq binding (varchar2, varchar2) + return number using bt_eq; + +create operator lt binding (varchar2, varchar2) + return number using bt_lt; + +create operator gt binding (varchar2, varchar2) + return number using bt_gt; + +create table md_table(iname varchar2(30), ipname varchar2(30), + params varchar2(1000), ipobj# number); + +create or replace package md authid definer as + procedure insertmd(iname varchar2, ipname varchar2, + ipobj# number, params varchar2); + procedure updateobjnum(iname varchar2, ipname varchar2, ipobj# number); + procedure updateidxnam(oldiname varchar2, newiname varchar2); + procedure updateidxpart(iname varchar2,oldpname varchar2, newpname varchar2); + procedure updateparams(iname varchar2, ipname varchar2, params varchar2); + procedure deletemd(iname varchar2, ipname varchar2); + procedure deleteindexmd(iname varchar2); +end md; +/ + +show errors + +create or replace package body md as + procedure insertmd (iname varchar2, ipname varchar2, + ipobj# number, params varchar2) + is + stmt1 varchar2(1000); + begin + stmt1 := 'insert into md_table values(:1, :2, :3, :4)'; + execute immediate stmt1 using iname, ipname, params, ipobj#; + + end; + + procedure updateobjnum(iname varchar2, ipname varchar2, ipobj# number) + is + stmt1 varchar2(1000); + begin + stmt1 := 'update md_table set ipobj# = :1 where iname = :2 and ipname= :3'; + execute immediate stmt1 using ipobj#, iname, ipname; + + end; + + procedure updateidxnam(oldiname varchar2, newiname varchar2) + is + stmt1 varchar2(1000); + begin + stmt1 := 'update md_table set iname = :1 where iname = :2'; + execute immediate stmt1 using newiname, oldiname; + end; + + procedure updateidxpart(iname varchar2,oldpname varchar2, newpname varchar2) + is + stmt1 varchar2(1000); + begin + stmt1 := 'update md_table set ipname =:1 where iname =:2 and ipname =:3'; + execute immediate stmt1 using newpname, iname, oldpname; + end; + + procedure updateparams(iname varchar2, ipname varchar2, params varchar2) + is + stmt1 varchar2(1000); + begin + stmt1 := 'update md_table set params = :1 where iname =:2 and ipname=:3'; + execute immediate stmt1 using params, iname, ipname; + end; + + procedure deletemd(iname varchar2, ipname varchar2) + is + stmt1 varchar2(1000); + begin + stmt1 := 'delete from md_table where iname = :1 and ipname = :2'; + execute immediate stmt1 using iname, ipname; + + end; + + procedure deleteindexmd(iname varchar2) + is + stmt1 varchar2(1000); + begin + stmt1 := 'delete from md_table where iname = :1'; + execute immediate stmt1 using iname; + + end; + end; +/ + +show errors; + +-- CREATE INDEXTYPE IMPLEMENTATION TYPE +create type psbtree_im as object +( + scanctx RAW(4), + static function ODCIGetInterfaces(ifclist OUT sys.ODCIObjectList) + return NUMBER, + + static function ODCIIndexCreate (ia sys.ODCIIndexInfo, + parms varchar2, env sys.ODCIEnv) return NUMBER, + + static function ODCIIndexAlter (ia sys.ODCIIndexInfo, + parms IN OUT varchar2, altopt number, env sys.ODCIEnv) return NUMBER, + + static function ODCIIndexDrop(ia sys.ODCIIndexInfo, + env sys.ODCIEnv) return NUMBER, + + static function ODCIIndexInsert(ia sys.ODCIIndexInfo, rid VARCHAR2, + newval VARCHAR2, env sys.ODCIEnv) return NUMBER, + + static function ODCIIndexDelete(ia sys.ODCIIndexInfo, rid VARCHAR2, + oldval VARCHAR2, env sys.ODCIEnv) return NUMBER, + + static function ODCIIndexUpdate(ia sys.ODCIIndexInfo, rid VARCHAR2, + oldval VARCHAR2, newval VARCHAR2, env sys.ODCIEnv) + return NUMBER, + + static function ODCIIndexUpdPartMetadata(ia sys.ODCIIndexInfo, + palist sys.ODCIPartInfoList, env sys.ODCIEnv) + return NUMBER, + + static function ODCIIndexExchangePartition (ia sys.ODCIIndexInfo, + ia1 sys.ODCIIndexInfo, env sys.ODCIEnv) return NUMBER, + + static function ODCIIndexStart(sctx IN OUT psbtree_im, + ia sys.ODCIIndexInfo, op sys.ODCIPredInfo, + qi sys.ODCIQueryInfo, strt number, stop number, + cmpval varchar2, env sys.ODCIEnv) + return NUMBER, + + member function ODCIIndexFetch(nrows number, + rids OUT sys.ODCIRidList, env sys.ODCIEnv) + return NUMBER, + + member function ODCIIndexClose(env sys.ODCIEnv) return NUMBER +); +/ +show errors + +--------------------------------- +-- CREATE IMPLEMENTATION UNIT -- +--------------------------------- + +-- CREATE TYPE BODY +create or replace type body psbtree_im +is + static function ODCIGetInterfaces(ifclist OUT sys.ODCIObjectList) + return number is + begin + ifclist := sys.ODCIObjectList(sys.ODCIObject('SYS','ODCIINDEX2')); + return ODCIConst.Success; + end ODCIGetInterfaces; + + static function ODCIIndexCreate (ia sys.ODCIIndexInfo, + parms varchar2, env sys.ODCIEnv) return number + is + i integer; + stmt varchar2(2000); + cursor cur1(ianame varchar2) is + select partition_name, parameters from user_ind_partitions + where index_name = ianame order by partition_name; + begin + stmt := ''; + + if (env.CallProperty is null) then + stmt := 'create table ' ||ia.IndexSchema || '.' || ia.IndexName || + '_sbtree(f1 varchar2(1000), f2 rowid)'; + elsif (env.callproperty = sys.ODCIConst.FirstCall) then + stmt := ''; + i := 1; + + for c1 in cur1(ia.indexname) loop + if (i >1) then + stmt := stmt || ','; + end if; + stmt := stmt || 'partition ' || c1.partition_name; + md.insertmd(ia.indexname, c1.partition_name, 0, c1.parameters); + i := i+1; + end loop; + stmt := 'create table ' || ia.indexschema || '.' || ia.indexname || + '_sbtree (f1 varchar2(1000), f2 rowid) partition by system ' || + '( ' || stmt || ')'; + end if; + + dbms_output.put_line('Create'); + dbms_output.put_line(stmt); + + -- execute the statement + if ( (env.CallProperty is null) or + (env.CallProperty = sys.ODCIConst.FirstCall) ) then + execute immediate stmt; + if (env.CallProperty is null) then + execute immediate 'insert into ' ||ia.IndexSchema || '.' + || ia.IndexName || '_sbtree select ' || + ia.IndexCols(1).Colname || ', ROWID from ' || + ia.IndexCols(1).TableSchema || '.' || + ia.IndexCols(1).TableName; + end if; + end if; + + return ODCIConst.Success; + end; + + static function ODCIIndexAlter (ia sys.ODCIIndexInfo, + parms IN OUT varchar2, altopt number, env sys.ODCIEnv) + return number is + stmt varchar2(2000); + + begin + stmt := ''; + if (altopt = ODCIConst.AlterIndexRebuild) then + if (env.callproperty = ODCIConst.IntermediateCall) then + md.updateobjnum(ia.IndexName, ia.IndexPartition, ia.IndexPartitionIden); + stmt := 'insert into ' || ia.indexschema || '.' || ia.indexname || + '_sbtree partition (' || ia.indexpartition || ') select ' || + ia.indexcols(1).colname || ', rowid from ' || + ia.indexcols(1).tableschema || '.' || ia.indexcols(1).tablename || + ' partition (' || ia.indexcols(1).tablepartition || ')'; + dbms_output.put_line(stmt); + execute immediate stmt; + end if; + elsif (altopt = ODCIConst.AlterIndexRename) then + if (ia.IndexPartition is not null) then + md.updateidxpart(ia.IndexName, ia.IndexPartition, parms); + stmt := 'alter table ' || ia.indexschema || '.' || + ia.indexname || '_sbtree rename partition ' || + ia.indexpartition || ' to ' || parms; + dbms_output.put_line(stmt); + execute immediate stmt; + else + md.updateidxnam(ia.IndexName, parms); + stmt := 'alter table ' || ia.indexschema || '.' || + ia.indexname || '_sbtree rename to ' || parms || '_sbtree'; + dbms_output.put_line(stmt); + execute immediate stmt; + end if; + end if; + + dbms_output.put_line('Alter'); + return ODCIConst.Success; + end ODCIIndexAlter; + + static function ODCIIndexDrop(ia sys.ODCIIndexInfo, env sys.ODCIEnv) + return number is + stmt varchar2(1000); + cnum integer; + junk integer; + begin + -- construct the sql statement + stmt := ''; + if (env.CallProperty is null) then + md.deleteindexmd(ia.indexname); + stmt := 'drop table ' || ia.IndexSchema || '.' || ia.IndexName || + '_sbtree'; + + dbms_output.put_line('Drop'); + dbms_output.put_line(stmt); + + execute immediate stmt; + end if; + + return ODCIConst.Success; + end; + + static function ODCIIndexExchangePartition(ia sys.ODCIIndexInfo, + ia1 sys.ODCIIndexInfo, env sys.ODCIEnv) + return number + is + stmt varchar2(2000); + cnum integer; + junk integer; + begin + stmt := ''; + dbms_output.put_line('Exchange Partitions'); + + -- construct the sql statement + stmt := 'alter table ' || ia.IndexSchema || '.' || ia.IndexName || + '_sbtree exchange partition ' || ia.IndexPartition || + ' with table ' || ia1.IndexSchema || '.' || ia1.IndexName || '_sbtree'; + + dbms_output.put_line(stmt); + execute immediate stmt; + + return ODCIConst.Success; + end; + + static function ODCIIndexUpdPartMetadata(ia sys.ODCIIndexInfo, + palist sys.ODCIPartInfoList, env sys.ODCIEnv) + return number is + col number; + begin + + dbms_output.put_line('ODCIUpdPartMetadata'); + SYS.ODCIINDEXINFODUMP(ia); + SYS.ODCIPARTINFOLISTDUMP(palist); + + FOR col IN palist.FIRST..palist.LAST LOOP + IF (palist(col).PartOp = ODCIConst.AddPartition) THEN + md.insertmd(ia.indexname, palist(col).indexpartition, + palist(col).indexpartitioniden, null); + ELSIF (palist(col).PartOp = ODCIConst.DropPartition) THEN + md.deletemd(ia.indexname, palist(col).indexpartition); + END IF; + END LOOP; + return ODCIConst.Success; + END; + + static function ODCIIndexInsert(ia sys.ODCIIndexInfo, rid VARCHAR2, + newval VARCHAR2, env sys.ODCIEnv) + RETURN NUMBER AS external + name "qxiqtbspi" + library extdemo6l + WITH context + parameters ( + context, + ia, + ia indicator struct, + rid, + rid indicator, + newval, + newval indicator, + env, + env indicator struct, + return ocinumber + ); + + static function ODCIIndexDelete(ia sys.ODCIIndexInfo, rid VARCHAR2, + oldval VARCHAR2, env sys.ODCIEnv) + RETURN NUMBER AS external + name "qxiqtbspd" + library extdemo6l + WITH context + parameters ( + context, + ia, + ia indicator struct, + rid, + rid indicator, + oldval, + oldval indicator, + env, + env indicator struct, + return ocinumber + ); + + static function ODCIIndexUpdate(ia sys.ODCIIndexInfo, rid VARCHAR2, + oldval VARCHAR2, newval VARCHAR2, env sys.ODCIEnv) + RETURN NUMBER AS external + name "qxiqtbspu" + library extdemo6l + WITH context + parameters ( + context, + ia, + ia indicator struct, + rid, + rid indicator, + oldval, + oldval indicator, + newval, + newval indicator, + env, + env indicator struct, + return ocinumber + ); + + static function ODCIIndexStart(sctx in out psbtree_im, + ia sys.ODCIIndexInfo, op sys.ODCIPredInfo, + qi sys.ODCIQueryInfo, strt number, stop number, + cmpval varchar2, env sys.ODCIEnv) + RETURN NUMBER AS external + name "qxiqtbsps" + library extdemo6l + WITH context + parameters ( + context, + sctx, + sctx indicator struct, + ia, + ia indicator struct, + op, + op indicator struct, + qi, + qi indicator struct, + strt, + strt indicator, + stop, + stop indicator, + cmpval, + cmpval indicator, + env, + env indicator struct, + return OCINumber + ); + + member function ODCIIndexFetch(nrows number, + rids OUT sys.ODCIRidList, env sys.ODCIEnv) + RETURN NUMBER AS external + name "qxiqtbspf" + library extdemo6l + WITH context + parameters ( + context, + self, + self indicator struct, + nrows, + nrows indicator, + rids, + rids indicator, + env, + env indicator struct, + return OCINumber + ); + + member function ODCIIndexClose (env sys.ODCIEnv) + ReTURN NUMBEr AS external + name "qxiqtbspc" + library extdemo6l + WITH context + parameters ( + context, + self, + self indicator struct, + env, + env indicator struct, + return OCINumber + ); + +end; +/ +show errors + +--------------------- +-- CREATE INDEXTYPE +--------------------- + +create indextype psbtree +for +eq(varchar2, varchar2), +lt(varchar2, varchar2), +gt(varchar2, varchar2) +using psbtree_im with local range partition +with system managed storage tables; + +-------------------------- +-- USAGE EXAMPLES -- +-------------------------- +set serveroutput on size 20000 + +---------------- +-- CREATE TABLE +---------------- + +create table t1 (f1 number, f2 varchar2(200)) +partition by range(f1) +( + partition p1 values less than (101), + partition p2 values less than (201), + partition p3 values less than (301), + partition p4 values less than (401) + ); +insert into t1 values (10, 'aaaa'); +insert into t1 values (200, 'bbbb'); +insert into t1 values (100, 'cccc'); +insert into t1 values (300, 'dddd'); +insert into t1 values (400, 'eeee'); +commit; + +----------------------------- +-- CREATE LOCAL DOMAIN INDEX +----------------------------- + +create index it1 on t1(f2) indextype is psbtree local +(partition pe1 parameters('test1'), partition pe2, + partition pe3, partition pe4 parameters('test4')) +parameters('test'); + +----------- +-- INSERTS +----------- + +insert into t1 values (11, 'gggg'); +insert into t1 values (325, 'hhhh'); +insert into t1 values (327, 'iiii'); +select * from t1 order by f1; + +commit; + +----------- +-- DELETES +----------- + +delete from t1 where f1 = 325; +select * from t1 order by f1; + +rollback; + +select * from t1 where eq(f2, 'hhhh') = 1; + +delete from t1 where eq(f2, 'hhhh') = 1; +select * from t1 order by f1; + +select * from t1 where eq(f2, 'hhhh') = 1; + +commit; + +----------- +-- UPDATES +----------- +update t1 set f2 = '####' where f1=327; +select * from t1 order by f1; + +commit; + +update t1 set f1 = 328 where eq(f2, '####') = 1; + +select * from t1 where eq(f2, '####') = 1; + +----------- +-- QUERIES +----------- +-- partition extended table_name +explain plan for + select * from t1 partition(p1) where eq(f2, 'gggg') = 1; +set echo off +@@extdemo0 +set echo on + +select * from t1 partition(p1) where eq(f2, 'gggg') = 1; + +-- entire table +explain plan for + select * from t1 where eq(f2, 'gggg') = 1; +set echo off +@@extdemo0 +set echo on + +select * from t1 where eq(f2, 'gggg') = 1; + +-- subset of table +explain plan for + select * from t1 where eq(f2, 'dddd') = 1 and f1>101 ; +set echo off +@@extdemo0 +set echo on + +select * from t1 where eq(f2, 'dddd') = 1 and f1>101 ; + +-- single partition +explain plan for + select * from t1 where eq(f2, 'dddd') = 1 and f1 =300 ; +set echo off +@@extdemo0 +set echo on + +select * from t1 where eq(f2, 'dddd') = 1 and f1 = 300; + +select * from t1 where lt(f2, 'zzzz') = 1 order by f1; + +select * from t1 where gt(f2, 'aaaa') = 1 order by f1; + +-------------------------- +-- ALTER TABLE OPERATIONS +-------------------------- +--Alter Table Add Partition +alter table t1 add partition pp2 values less than (501); +insert into t1 values (500, 'ffff'); + +--Alter Table Drop Partition +alter table t1 drop partition pp2; + +--Alter Table Split Partition +alter table t1 split partition p2 at (150) into +(partition p21, partition p22); + +--Alter Table Merge Partition +alter table t1 merge partitions p22, p3 into partition pp2; + +--Create A Non-Partitioned Table +create table ext (f1 number, f2 varchar2(200)); + +insert into ext values (310, 'aaaa'); +insert into ext values (320, 'bbbb'); +insert into ext values (330, 'dddd'); + +-- NOW, CREATE DOMAIN INDEXES +create index it2 on ext(f2) indextype is psbtree; + +--Alter Table Exchange Partition + +alter table t1 exchange partition p4 with table ext including indexes; + +--Alter Table Modify Unusable +alter table t1 modify partition p4 unusable local indexes; + +--Alter Table Truncate Partition +alter table t1 truncate partition p1; + +------------ +-- CLEANUPS +------------ + +drop index it1; +drop index it2; +drop table t1; +drop table ext; +drop indextype psbtree; +drop type psbtree_im; +drop operator eq; +drop operator lt; +drop operator gt; +drop function bt_eq; +drop function bt_lt; +drop function bt_gt; + + diff --git a/fdemo1.for b/fdemo1.for new file mode 100644 index 0000000..128b139 --- /dev/null +++ b/fdemo1.for @@ -0,0 +1,499 @@ +C +C $Header: fdemo1.for 25-jul-2001.04:07:17 ssappara Exp $ +C +C Copyright (c) 1991, 1999, Oracle Corporation. All rights reserved. +C +C NAME +C fdemo1.for - Fortran demo program #1 +C MODIFIED (MM/DD/YY) +C ssappara 07/25/01 - bug1788355:Don't use return length NULL in ODEFIN +C mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +C plocke 11/14/95 - to update for v7.3 +C lchidamb 05/16/95 - merge changes from branch 1.2.720.1 +C rkooi2 11/05/92 - Portability mods +C sjain 03/16/92 - Creation + + PROGRAM FDEMO1 + +*--------------------------------------------------------------- +* FDEMO1 is a demonstration program that adds new employee +* rows to the personnel data base. Checking +* is done to insure the integrity of the data base. +* The employee numbers are automatically selected using +* the current maximum employee number as the start. +* If any employee number is a duplicate, it is skipped. +* The program queries the user for data as follows: +* +* Enter employee name : +* Enter employee job : +* Enter employee salary: +* Enter employee dept : +* +* If just is entered for the employee name, +* the program terminates. +* +* If the row is successfully inserted, the following +* is printed: +* +* ENAME added to DNAME department as employee N. +* +* The maximum lengths of the 'ename', 'job', and 'dname' +* columns are determined by an ODESCR call. +* +* Note: VAX FORTRAN, by default, passes all CHARACTER variables +* (variables declared as CHARACTER*N) by descriptor. +* To compile this program on systems that pass character +* variables by descriptor, insert %REF() where necessary. +*--------------------------------------------------------------- + + IMPLICIT INTEGER (A-Z) + + INTEGER*2 LDA(32) + INTEGER*2 CURS(32,2) + INTEGER*2 HDA(256) + CHARACTER*20 UID, PSW + INTEGER*4 NOBLOK + +* CHARACTER string vars to hold the SQL statements + + CHARACTER*60 SMAX + CHARACTER*60 SEMP + CHARACTER*150 INS + CHARACTER*60 SEL + + INTEGER*4 SMAXL, SEMPL, INSL, SELL + +* Program vars to be bound to SQL placeholders and +* select-list fields . + + INTEGER*4 EMPNO, DEPTNO, SAL + CHARACTER*10 ENAME + CHARACTER*10 JOB + CHARACTER*14 DNAME + +* Actual lengths of columns . + + INTEGER*4 ENAMES, JOBS, DNAMES + +* Character strings for SQL placeholders. + + CHARACTER*6 ENON + CHARACTER*6 ENAN + CHARACTER*4 JOBN + CHARACTER*4 SALN + CHARACTER*7 DEPTN + +* Lengths of character strings for SQL placeholders. + + INTEGER*4 ENONL, ENANL, JOBNL, SALNL, DEPTNL + +* Parameters for OPARSE. + + INTEGER*4 NODEFP, V7FLAG + +* Parameters for ODESCR. + + INTEGER*2 DTYPE, PREC, SCALE, NULLOK + INTEGER*4 DSIZE, CNAMEL + CHARACTER*80 CNAME + +*--------------------------------------------------------------- +* Initialize variables. +*--------------------------------------------------------------- + + SMAX = 'SELECT NVL(MAX(EMPNO),0) FROM EMP' + SMAXL = LEN_TRIM(SMAX) + + SEMP = 'SELECT ENAME,JOB FROM EMP' + SEMPL= LEN_TRIM(SEMP) + + INS = 'INSERT INTO EMP(EMPNO,ENAME,JOB,SAL, + + DEPTNO) VALUES (:EMPNO,:ENAME,:JOB,:SAL,:DEPTNO)' + INSL = LEN_TRIM(INS) + + SEL = 'SELECT DNAME FROM DEPT WHERE DEPTNO = :1' + SELL = LEN_TRIM(SEL) + +* All in Deferred Mode + NODEFP = 1 + V7FLAG = 2 + ENAMEL = 10 + JOBL = 10 + EMPNOL = 4 + DEPTL = 4 + SALL = 4 + + ENON = ':EMPNO' + ENAN = ':ENAME' + JOBN = ':JOB' + SALN = ':SAL' + DEPTN = ':DEPTNO' + + ENONL = 6 + ENANL = 6 + JOBNL = 4 + SALNL = 4 + DEPTNL = 7 + +*--------------------------------------------------------------- +* Connect to ORACLE in non-blocking mode. +* HDA must be initialized to all zeros before call to OLOG. +*--------------------------------------------------------------- + + UID = 'SCOTT' + PSW = 'TIGER' + NOBLOK = 0 + DATA HDA/256*0/ + + CALL OLOG(LDA, HDA, UID, LEN_TRIM(UID), + + PSW, LEN_TRIM(PSW), 0, -1, NOBLOK) + IF (LDA(7).NE.0) THEN + CALL ERRRPT(LDA(1), LDA(1)) + GO TO 900 + END IF + + WRITE (*, '(1X, A, A20)') 'Logged on to ORACLE as user ', + + UID + +*--------------------------------------------------------------- +* Open two cursors for the personnel data base. +*--------------------------------------------------------------- + + CALL OOPEN(CURS(1,1), LDA, 0, -1, -1, 0, -1) + IF (CURS(1,1).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + + CALL OOPEN(CURS(1,2),LDA(1),0, -1, -1, 0, -1) + IF (CURS(1,2).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,2)) + GO TO 700 + END IF + +*--------------------------------------------------------------- +* Turn off auto-commit. Note: the default is off, +* so this could be omitted. +*--------------------------------------------------------------- + + CALL OCOF(LDA(1)) + IF (LDA(1).NE.0) THEN + CALL ERRRPT(LDA(1), LDA(1)) + GO TO 700 + END IF + +*--------------------------------------------------------------- +* Retrieve the current maximum employee number. +*---------------------------------------------------------------- + +* Parse the SQL statement. + + CALL OPARSE(CURS(1,1), SMAX, SMAXL, NODEFP, V7FLAG) + IF (CURS(1,1).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + +* Define a buffer to receive the MAX(EMPNO) from ORACLE. + + CALL ODEFIN(CURS(1,1), 1, EMPNO, 4, 3, -1, INDP, 0, -1, -1, + + RLEN,RCODE) + IF (CURS(1,1).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + + +* Execute the SQL statement. + + CALL OEXEC(CURS(1,1)) + IF (CURS(1,1).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + +* Fetch the data from ORACLE into the defined buffer. + + CALL OFETCH(CURS(1,1)) + IF (CURS(1,1).EQ.0) GO TO 50 + IF (CURS(7,1).NE.1403) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + +* A cursor return code of 1403 means that no row +* satisfied the query, so generate the first empno. + + EMPNO=10 +50 CONTINUE + +*--------------------------------------------------------------- +* Determine the max length of the employee name and job title. +* Parse the SQL statement - it will not be executed. +* Describe the two fields specified in the SQL statement. +*---------------------------------------------------------------- + + CALL OPARSE(CURS(1,1), SEMP, SEMPL, NODEFP, V7FLAG) + IF (CURS(1,1).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + + CNAMEL = 80 + CALL ODESCR(CURS(1,1), 1, ENAMES, DTYPE, CNAME, + + CNAMEL, DSIZE, PREC, SCALE, NULLOK) + IF (CURS(1,1).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + + IF (ENAMES .GT. ENAMEL) THEN + WRITE (*, '(1X, A, I2, A, I2)') 'ENAME too large (', + + ENAMES, ' for buffer (', ENAMEL, ').' + GO TO 700 + END IF + + CNAMEL = 80 + CALL ODESCR(CURS(1,1), 2, JOBS, DTYPE, CNAME, + + CNAMEL, DSIZE, PREC, SCALE, NULLOK) + IF (CURS(1,1).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + + IF (JOBS .GT. JOBL) THEN + WRITE (*, '(1X, A, I2, A, I2)') 'JOB too large (', + + JOBS, ' for buffer (', JOBL, ').' + GO TO 700 + END IF + +*-------------------------------------------------------------- +* Parse the insert and select statements. +*-------------------------------------------------------------- + + CALL OPARSE(CURS(1,1), INS, INSL, NODEFP, V7FLAG) + IF (CURS(1,1).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + + CALL OPARSE(CURS(1,2), SEL, SELL, NODEFP, V7FLAG) + IF (CURS(1,2).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,2)) + GO TO 700 + END IF + +*-------------------------------------------------------------- +* Bind all placeholders. +*-------------------------------------------------------------- + + CALL OBNDRV(CURS(1,1),ENON,LEN(ENON),EMPNO,EMPNOL,3,-1,0,0,-1,-1) + IF (CURS(1,1).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + + CALL OBNDRV(CURS(1,1),ENAN,ENANL,ENAME,ENAMEL,1,-1,0,0,-1,-1) + IF (CURS(1,1).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + + CALL OBNDRV(CURS(1,1),JOBN,JOBNL,JOB,JOBL,1,-1,0,0,-1,-1) + IF (CURS(1,1).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + + CALL OBNDRV(CURS(1,1),SALN,SALNL,SAL,SALL,3,-1,0,0,-1,-1) + IF (CURS(1,1).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + + CALL OBNDRV(CURS(1,1),DEPTN,DEPTNL,DEPTNO,DEPTL,3,-1,0,0,-1,-1) + IF (CURS(1,1).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + +*-------------------------------------------------------------- +* Bind the DEPTNO variable. +*-------------------------------------------------------------- + + CALL OBNDRN(CURS(1,2), 1, DEPTNO, DEPTL, 3,-1,0,0,-1,-1) + IF (CURS(1,2).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,2)) + GO TO 700 + END IF + +*-------------------------------------------------------------- +* Describe the DNAME column - get the name and length. +*-------------------------------------------------------------- + + DNAMEL = 14 + CALL ODESCR(CURS(1,1), 1, DNAMES, DTYPE, DNAME, + + DNAMEL, DSIZE, PREC, SCALE, NULLOK) + IF (CURS(1,2).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,2)) + GO TO 700 + END IF + + IF (DNAMES .GT. DNAMEL) THEN + WRITE (*, '(1X, A)') 'DNAME too large for buffer.' + GO TO 700 + END IF + +*-------------------------------------------------------------- +* Define the buffer to receive DNAME. +*-------------------------------------------------------------- + + CALL ODEFIN(CURS(1,2),1,DNAME,DNAMEL,1,-1,INDP,0,-1,-1, + + RLEN,RCODE) + IF (CURS(1,2).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,2)) + GO TO 700 + END IF + +*-------------------------------------------------------------- +* Read the user's input. Statement 100 +* starts the main program loop. +*-------------------------------------------------------------- + +100 WRITE (*, '( A)') + + 'Enter employee name (CR to QUIT) : ' + READ (*, '(A)'), ENAME + IF (LEN_TRIM(ENAME) .EQ. 0) GO TO 700 + WRITE (*, '( A)'), 'Enter employee job : ' + READ (*, '(A)'), JOB + WRITE (*, '( A)') 'Enter employee salary: ' + READ (*, '(I6)'), SAL +300 WRITE (*, '( A)') 'Enter employee dept : ' + READ (*, '(I6)'), DEPTNO + +*-------------------------------------------------------------- +* Check for a valid department number by +* executing the SELECT statement. +*-------------------------------------------------------------- + + CALL OEXEC(CURS(1,2)) + IF (CURS(1,2).NE.0) THEN + CALL ERRRPT(LDA(1), CURS(1,2)) + GO TO 700 + END IF + +*-------------------------------------------------------------- +* Fetch the rows - DEPTNO is a primary key, so a max of +* one row will be fetched. +* If the return code is 1403 no such department exists. +*-------------------------------------------------------------- + + CALL OFETCH(CURS(1,2)) + IF (CURS(1,2).EQ.0) GO TO 500 + IF (CURS(7,2).NE.1403) THEN + CALL ERRRPT(LDA(1), CURS(1,2)) + GO TO 700 + END IF + + WRITE (*, '(1X, A)') 'No such department number' + GO TO 300 + +*-------------------------------------------------------------- +* Increment EMPNO by 10. +* Execute the insert statement. +*-------------------------------------------------------------- + +500 EMPNO = EMPNO + 10 + CALL OEXEC(CURS(1,1)) + IF (CURS(1,1).EQ.0) GO TO 600 + +*-------------------------------------------------------------- +* If the call returns code 1 (duplicate value in index), +* generate the next possible employee number. +*-------------------------------------------------------------- + + IF (CURS(7,1).NE.1) THEN + CALL ERRRPT(LDA(1), CURS(1,1)) + GO TO 700 + END IF + + EMPNO=EMPNO+10 + GO TO 500 + +600 WRITE (*, 610) ENAME, DNAME, EMPNO +610 FORMAT(/, 1X, A10, ' added to the ', A14, + + ' department as employee# ', I4, /) + +*-------------------------------------------------------------- +* The row has been added - commit this transaction. +*-------------------------------------------------------------- + + CALL OCOM(LDA(1)) + IF (LDA(1).NE.0) THEN + CALL ERRRPT(LDA(1), LDA(1)) + GO TO 700 + END IF + + GO TO 100 + +*-------------------------------------------------------------- +* Either a fatal error has occurred or the user typed +* for the employee name. +* Close the cursors, disconnect, and end the program. +*-------------------------------------------------------------- + +700 CONTINUE + + CALL OCLOSE(CURS(1,1)) + IF (CURS(1,1).NE.0) CALL ERRRPT(LDA(1), CURS(1,1)) + CALL OCLOSE(CURS(1,2)) + IF (CURS(1,2).NE.0) CALL ERRRPT(LDA(1), CURS(1,2)) + + CALL OLOGOF(LDA(1)) + IF (LDA(1).NE.0) CALL ERRRPT(LDA(1), LDA(1)) +900 STOP + END + + +*-------------------------------------------------------------- +* ERRRPT prints the cursor number, the error code, and the +* OCI function code. +* +* CURS is a cursor. +* N is the cursor number. +*-------------------------------------------------------------- + + SUBROUTINE ERRRPT(LDA, CURS) + INTEGER*2 CURS(32), LDA(32) + + CHARACTER*160 ERRMSG + + IF (CURS(6) .GT. 0) THEN + WRITE (*, '(1X, A, I3)') 'ORACLE error processing OCI + + function ', CURS(6) + END IF + + CALL OERHMS(LDA(1), CURS(7), ERRMSG, 160) + WRITE (*, '(1X, A)') ERRMSG + + RETURN + END + + + INTEGER FUNCTION LEN_TRIM(STRING) + CHARACTER*(*) STRING + + INTEGER NEXT + + DO 10 NEXT = LEN(STRING), 1, -1 + IF (STRING(NEXT : NEXT) .NE. ' ') THEN + LEN_TRIM = NEXT + RETURN + ENDIF +10 CONTINUE + + LEN_TRIM = 0 + + RETURN + END + diff --git a/fdemo2.for b/fdemo2.for new file mode 100644 index 0000000..8e24eee --- /dev/null +++ b/fdemo2.for @@ -0,0 +1,389 @@ +C +C $Header: fdemo2.for 14-jul-99.13:43:24 mjaeger Exp $ +C +C Copyright (c) 1991, 1999, Oracle Corporation. All rights reserved. +C +C NAME +C fdemo2.for - Fortran demo program # 2 +C MODIFIED (MM/DD/YY) +C mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +C plocke 11/14/95 - to update for v7.3 +C lchidamb 05/16/95 - merge changes from branch 1.1.720.1 +C sjain 03/16/92 - Creation + +* FDEMO2.FOR +* +* A dynamic SQL OCI example program. Processes +* SQL statements entered interactively by the user. +* +* There is a 132-character limit on the length of +* the SQL statements. It is not necessary to +* terminate the SQL statement with a semicolon. +* +* To end the demo, type 'exit' or 'EXIT' at the +* prompt. + + PROGRAM FDEMO2 + IMPLICIT INTEGER*4 (A-Z) + +* Data structures +* Logon and cursor areas + INTEGER*2 CDA(32), LDA(32), HDA(256) + +* Bind values + CHARACTER*20 BVARV(8) + INTEGER NBV + +* Output values + CHARACTER*10 DVARC(8) + INTEGER DVARI(8) + REAL*4 DVARF(8) + INTEGER*2 DBTYPE(8), RLEN(8), RCODE(8) + INTEGER*2 INDP(8) + INTEGER NOV + +* Column names for SELECT + CHARACTER*10 COLNAM(8) + +* SQL statement buffer and logon info + CHARACTER*80 SQLSTM, UID, PWD, PROMPT + INTEGER UIDL, PWDL, SQLL, NOBLOK + + UID = 'SCOTT' + PWD = 'TIGER' + UIDL = LEN_TRIM(UID) + PWDL = LEN_TRIM(PWD) + NOBLOK = 0 + +* Connect to ORACLE in non-blocking mode. +* HDA must be initialized to all zeros before call to OLOG. + + DATA HDA/256*0/ + CALL OLOG(LDA, HDA, UID, UIDL, PWD, PWDL, 0, -1, NOBLOK) + IF (LDA(7) .NE. 0) THEN + CALL ERRRPT(LDA, CDA) + GO TO 999 + ENDIF + WRITE (*, '(1X, A, A)') 'Connected to ORACLE as user ', UID + +* Open a cursor. + CALL OOPEN(CDA, LDA, UID, 0, -1, PWD, 0) + IF (LDA(7) .NE. 0) THEN + CALL ERRRPT(LDA, CDA) + GO TO 900 + ENDIF + +* Beginning of the main program loop. +* Get and process SQL statements. + PROMPT = 'Enter SQL statement (132 char max) or EXIT to quit >' +100 WRITE (*, '(/, A)') PROMPT + READ '(A)', SQLSTM + + SQLL = LEN_TRIM(SQLSTM) + IF (SQLL .EQ. 0) GO TO 100 + + I = INDEX(SQLSTM, ';') + IF (I .GT. 0) THEN + SQLL = I - 1 + ENDIF + + IF ((SQLSTM(1:4) .EQ. 'exit') .OR. + + (SQLSTM(1:4) .EQ. 'EXIT')) GO TO 900 + +* Parse the statement. + CALL OPARSE(CDA, SQLSTM, SQLL, 0, 2) + IF (CDA(7) .NE. 0) THEN + CALL ERRRPT(LDA, CDA) + GO TO 100 + ENDIF + +* If there are bind values, obtain them from user. + CALL GETBNV(LDA, CDA, SQLSTM, BVARV, NBV) + IF (NBV .LT. 0) GO TO 100 + +* Define the output variables. If the statement is not a +* query, NOV returns as 0. If there were errors defining +* the output variables, NOV returns as -1. + CALL DEFINE(LDA, CDA, COLNAM, DBTYPE, DVARC, DVARI, + + DVARF, INDP, RLEN, RCODE, NOV) + IF (NOV .LT. 0) GO TO 100 + +* Execute the statement. + CALL OEXN(CDA, 1, 0) + IF (CDA(7) .NE. 0) THEN + CALL ERRRPT(LDA, CDA) + GO TO 100 + ENDIF + +* Fetch rows and display output if the statement was a query. + CALL FETCHN(LDA, CDA, COLNAM, NOV, DBTYPE, DVARC, + + DVARI, DVARF, INDP, RV) + IF (RV .LT. 0) GO TO 100 + +* Loop back to statement 100 to process +* another SQL statement. + GO TO 100 + +* End of main program loop. Here on exit or fatal error. +900 CALL OCLOSE(CDA) + CALL OLOGOF(LDA) + +* End of program. Come here if connect fails. +999 END + + +* Begin subprograms. + + SUBROUTINE GETBNV(LDA, CDA, STMT, BVARV, N) + IMPLICIT INTEGER*4 (A-Z) + INTEGER*2 LDA(32), CDA(32) + CHARACTER*(*) STMT + CHARACTER*(*) BVARV(8) + +* Arrays for bind variable info. + INTEGER BVARI(8), BVARL(8) + +* Scan the SQL statement for placeholders (:ph). +* Note that a placeholder must be terminated with +* a space, a comma, or a close parentheses. +* Two arrays are maintained: an array of starting +* indices in the string (BVARI), and an array of +* corresponding lengths (BVARL). + POS = 1 + DO 300 K = 1, 8 ! maximum of 8 per statement + I = INDEX(STMT(POS:), ':') + IF (I .EQ. 0) GO TO 400 + POS = I + POS - 1 + BVARI(K) = POS + DO 100 J = POS, LEN(STMT) + IF (STMT(J:J) .EQ. ' ' + + .OR. STMT(J:J) .EQ. ',' + + .OR. STMT(J:J) .EQ. ')') THEN + BVARL(K) = J - POS + GO TO 200 + ENDIF +100 CONTINUE + +200 POS = POS + 1 ! index past the ':' +300 CONTINUE + +400 N = K - 1 ! N is the number of BVs + + DO 500 K = 1, N + CALL OBNDRV(CDA, STMT(BVARI(K) :), BVARL(K), + + BVARV(K), 20, 1,-1,0,0,-1,-1) + IF (CDA(7) .NE. 0) THEN + CALL ERRRPT(LDA, CDA) + N = -1 + RETURN + ENDIF + WRITE (*, '( A, A, A)') 'Enter value for ', + + STMT(BVARI(K)+1:BVARI(K)+BVARL(K)-1), ' --> ' + READ '(A)', BVARV(K) +500 CONTINUE + + RETURN + END + + +* Define output variables for queries. +* Returns the number of select-list items (N) +* and the names of the select-list items (COLNAM). +* A maximum of 8 select-list items is permitted. +* (Note that this program does not check if there +* are more, but a production-quality program +* must do this.) + + SUBROUTINE DEFINE(LDA, CDA, COLNAM, DBTYPE, DVARC, + + DVARI, DVARF, INDP, RLEN, RCODE, RV) + IMPLICIT INTEGER*4 (A-Z) + INTEGER*2 LDA(32), CDA(32), DBTYPE(8) + INTEGER*2 RLEN(8), RCODE(8), INDP(8) + CHARACTER*(*) DVARC(8), COLNAM(8) + INTEGER DVARI(8), RV + REAL*4 DVARF(8) + + INTEGER DBSIZE(8), COLNML(8), DSIZE(8) + INTEGER*2 PREC(8), SCALE(8), NOK(8) + +* If not a query (SQL function code .ne. 4), return. + IF (CDA(2) .NE. 4) THEN + RV = 0 + RETURN + ENDIF + +* Describe the select-list (up to 8 items max), +* and define an output variable for each item, with the +* external (hence, FORTRAN) type depending on the +* internal ORACLE type, and its attributes. + + DO 100 N = 1, 8 + COLNML(N) = 10 ! COL length must be set on the call + CALL ODESCR(CDA, N, DBSIZE(N), DBTYPE(N), + + COLNAM(N), COLNML(N), DSIZE(N), + + PREC(N), SCALE(N), NOK(N)) + +* If the return code from ODESCR is 1007, then you have +* reached the end of the select list. + IF (CDA(7) .EQ. 1007) THEN + GO TO 200 +* Otherwise, if the return code is non-zero, an +* error occurred. Exit the subroutine, signalling +* an error. + ELSE IF (CDA(7) .NE. 0) THEN + CALL ERRRPT(LDA, CDA) + RV = -1 ! Error on return + RETURN + ENDIF + +* Check the datatype of the described item. If it's a +* NUMBER, check if the SCALE is 0. If so, define the +* output variable as INTEGER (3). If it's NUMBER with SCALE != 0, +* define the output variable as REAL (4). Otherwise, +* it's assumed to be a DATE, LONG, CHAR, or VARCHAR2, +* so define the output as 1 (VARCHAR2). + + IF (DBTYPE(N) .EQ. 2) THEN + IF (SCALE(N) .EQ. 0) THEN + DBTYPE(N) = 3 + ELSE + DBTYPE(N) = 4 + ENDIF + ELSE + DBTYPE(N) = 1 + ENDIF + +* Define the output variable. Do not define RLEN if +* the external datatype is 1. + IF (DBTYPE(N) .EQ. 3) THEN + CALL ODEFIN(CDA, N, DVARI(N), 4, 3, 0, INDP(N), + + FMT, 0, 0, RLEN(N), RCODE(N)) + ELSE IF (DBTYPE(N) .EQ. 4) THEN + CALL ODEFIN(CDA, N, DVARF(N), 4, 4, 0, INDP(N), + + FMT, 0, 0, RLEN(N), RCODE(N)) + ELSE + CALL ODEFIN(CDA, N, DVARC(N), 10, 1, 0, INDP(N), + + FMT, 0, 0, %VAL(-1), RCODE(N)) + ENDIF + IF (CDA(7) .NE. 0) THEN + CALL ERRRPT(LDA, CDA) + RV = -1 + RETURN + ENDIF +100 CONTINUE + +200 RV = N - 1 ! Decrement to get correct count + + RETURN + END + + +* FETCHN uses OFETCH to fetch the rows that satisfy +* the query, and displays the output. The data is +* fetched 1 row at a time. + + SUBROUTINE FETCHN(LDA, CDA, NAMES, NOV, DBTYPE, DVARC, + + DVARI, DVARF, INDP, RV) + IMPLICIT INTEGER*4 (A-Z) + INTEGER*2 LDA(32), CDA(32), DBTYPE(8), INDP(8) + CHARACTER*(*) NAMES(8), DVARC(8) + INTEGER DVARI(8), NOV, RV + REAL*4 DVARF(8) + + IF (CDA(2) .NE. 4) THEN ! not a query + RV = 0 + RETURN + ENDIF + + DO 50 COL = 1, NOV + IF (DBTYPE(COL) .EQ. 1) THEN + WRITE (*, 900) NAMES(COL), ' ' +900 FORMAT ('+', A10, A1, $) + ELSE + WRITE (*, 902) NAMES(COL), ' ' +902 FORMAT ('+', A8, A1, $) + ENDIF +50 CONTINUE + + WRITE (*, '(1X, A, /)') '------------------------------ + +-----------------------------------------------' + + DO 200 NROWS = 1, 10000 + CALL OFETCH(CDA) + IF (CDA(7) .EQ. 1403) GO TO 300 + IF (CDA(7) .NE. 0 .AND. CDA(7) .NE. 1406) THEN + CALL ERRRPT(LDA, CDA) + RV = -1 + RETURN + ENDIF + DO 100 COL = 1, NOV + IF (INDP(COL) .LT. 0 .AND. DBTYPE(COL) .NE. 1) THEN + WRITE (*, 903), ' ' +903 FORMAT ('+', A9, $) + ELSE IF (INDP(COL) .LT. 0 .AND. DBTYPE(COL) .EQ. 1) THEN + WRITE (*, 905), ' ' +905 FORMAT ('+', A11, $) + ELSE + IF (DBTYPE(COL) .EQ. 3) THEN + WRITE (*, 904) DVARI(COL), ' ' +904 FORMAT ('+', I6, A3, $) + ELSE IF (DBTYPE(COL) .EQ. 4) THEN + WRITE (*, 906) DVARF(COL), ' ' +906 FORMAT ('+', F8.2, A1, $) + ELSE + WRITE (*, 908) DVARC(COL), ' ' +908 FORMAT ('+', A10, A1, $) + ENDIF + ENDIF +100 CONTINUE + WRITE (*, '(1X)') +200 CONTINUE + +300 NROWS = NROWS - 1 + WRITE (*, '(/, 1X, I3, A)') NROWS, ' rows returned' + + RETURN + END + + + + SUBROUTINE ERRRPT(LDA, CDA) + INTEGER*2 LDA(32), CDA(32) + + CHARACTER*132 MSG + + MSG = ' ' + IF (LDA(7) .NE. 0) THEN + CDA(7) = LDA(7) + CDA(6) = 0 + ENDIF + + IF (CDA(6) .NE. 0) THEN + WRITE (*, '(1X, A, I3)') 'Error processing OCI function', + + CDA(6) + ENDIF + + CALL OERHMS (LDA, CDA(7), MSG, 132) + WRITE (*, '(1X, A)') MSG + + RETURN + END + + + INTEGER FUNCTION LEN_TRIM(STRING) + CHARACTER*(*) STRING + + INTEGER NEXT + + DO 10 NEXT = LEN(STRING), 1, -1 + IF (STRING(NEXT : NEXT) .NE. ' ') THEN + LEN_TRIM = NEXT + RETURN + ENDIF +10 CONTINUE + + LEN_TRIM = 0 + + RETURN + END + diff --git a/fdemo3.for b/fdemo3.for new file mode 100644 index 0000000..fa09691 --- /dev/null +++ b/fdemo3.for @@ -0,0 +1,285 @@ +C +C $Header: fdemo3.for 14-jul-99.13:44:03 mjaeger Exp $ +C +C Copyright (c) 1991, 1999, Oracle Corporation. All rights reserved. +C +C NAME +C fdemo3.for - Fortran demo program # 3 +C MODIFIED (MM/DD/YY) +C mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +C plocke 11/14/95 - to update for v7.3 +C lchidamb 05/16/95 - merge changes from branch 1.1.720.1 +C sjain 03/16/92 - Creation + +* FDEMO3.FOR +* OCI FORTRAN Sample Program 3 +* +* Demonstrates using the OFLNG routine to retrieve +* part of a LONG RAW column +* +* This example "plays" a digitized voice message +* by repeatedly extracting 64 kB chunks of the message +* from the row in the table, and sending them to a +* converter buffer (for example, a Digital-to-Analog +* Converter (DAC) FIFO buffer). +* +* The hardware-specific DAC routine is merely simulated +* in this example. + + PROGRAM FDEMO3 + IMPLICIT INTEGER(A-Z) + +* Connect and Cursor Data Structures + + INTEGER*2 CDA(32) + INTEGER*2 LDA(32) + INTEGER*2 HDA(256) + +* Program Variables + + CHARACTER*132 SQLSTM + CHARACTER*20 UID, PWD + INTEGER MSGID, MSGLEN + INTEGER*2 INDP, RLEN, RCODE + INTEGER RETL + BYTE DBIN(200000) + CHARACTER*6 FMT + INTEGER*4 NOBLOK + +* Connect to ORACLE in non-blocking mode. +* The HDA must be initialized to all zeros before calling OLOG. + UID = 'SCOTT' + PWD = 'TIGER' + DATA HDA/256*0/ + + CALL OLOG(LDA, HDA, UID, LEN_TRIM(UID), + + PWD, LEN_TRIM(PWD), 0, -1, NOBLOK) + IF (LDA(1) .NE. 0) THEN + WRITE (*, '(1X, A)') 'Cannot connect as scott/tiger...' + WRITE (*, '(1X, A)') 'Application terminating...' + GOTO 999 + END IF + +* Open the cursor. (Use UID as a dummy parameter--it +* won't be looked at.) + CALL OOPEN(CDA, LDA, UID, 0, 0, UID, 0) + IF (CDA(7) .NE. 0) THEN + CALL ERRPT(CDA) + GOTO 900 + END IF + +* Drop the old table. + WRITE (*, '( A)') 'OK to drop table VOICE_MAIL (Y or N)? : ' + READ '(A)', FMT + IF (FMT(1:1) .EQ. 'y' .OR. FMT(1:1) .EQ. 'Y') THEN + GO TO 10 + ELSE + GO TO 900 + ENDIF + +* Parse the DROP TABLE statement. +10 SQLSTM = 'DROP TABLE VOICE_MAIL' + CALL OPARSE(CDA, SQLSTM, LEN_TRIM(SQLSTM), 0, 2) + IF (CDA(7) .EQ. 0) THEN + WRITE (*, '(1X, A)') 'Table VOICE_MAIL dropped.' + ELSEIF (CDA(7) .EQ. 942) THEN + WRITE (*, '(1X, A)') 'Table did not exist.' + ELSE + CALL ERRPT(LDA, CDA) + GO TO 900 + ENDIF + +* Create new table. Parse with DEFFLG set to zero, +* to immediately execute the DDL statement. The LNGFLG +* is set to 2 (Version 7). + + SQLSTM = 'CREATE TABLE VOICE_MAIL + + (MSG_ID NUMBER(6), MSG_LEN NUMBER(12), MSG LONG RAW)' + +* Parse the statement. Do not defer the parse, so that the +* DDL statement is executed immediately. + CALL OPARSE(CDA, SQLSTM, LEN_TRIM(SQLSTM), 0, 2) + IF (CDA(7) .EQ. 0) THEN + WRITE (*, '(1X, A)') 'Created table VOICE_MAIL.' + ELSE + CALL ERRPT(LDA, CDA) + GOTO 900 + END IF + +* Insert some dummy data into the table. + SQLSTM = 'INSERT INTO VOICE_MAIL VALUES (:1, :2, :3)' + CALL OPARSE(CDA, SQLSTM, LEN_TRIM(SQLSTM), 1, 2) + IF (CDA(7) .NE. 0) THEN + CALL ERRPT(LDA, CDA) + GOTO 900 + END IF + +* Do the binds for the input data to set values +* in the new table. + INDP = 0 + CALL OBNDRN(CDA, 1, MSGID, 4, 3, 0, INDP, FMT, 0, 0) + IF (CDA(7) .NE. 0) THEN + CALL ERRPT(LDA, CDA) + GOTO 900 + END IF + + CALL OBNDRN(CDA, 2, MSGLEN, 4, 3, 0, INDP, FMT, 0, 0) + IF (CDA(7) .NE. 0) THEN + CALL ERRPT(LDA, CDA) + GOTO 900 + END IF + + CALL OBNDRN(CDA, 3, DBIN, 200000, 24, 0, INDP, FMT, 0, 0) + IF (CDA(7) .NE. 0) THEN + CALL ERRPT(LDA, CDA) + GOTO 900 + END IF + +* Fill the input buffer with some dummy data. + MSGID = 100 + MSGLEN = 200000 + DO 100 I = 1, 200000 +100 DBIN(I) = 42 + +* Execute the statement to INSERT the data + WRITE (*, '(1X, A)') 'Inserting data into the table.' + CALL OEXN(CDA, 1, 0) + IF (CDA(7) .NE. 0) THEN + CALL ERRPT(LDA, CDA) + GOTO 900 + END IF + +* Do the selects. First position the cursor at the +* proper row, using the MSG_ID. Then fetch the data +* in 64K chunks, using OFLNG. + SQLSTM = 'SELECT MSG_ID, MSG_LEN, MSG + + FROM VOICE_MAIL WHERE MSG_ID = 100' + + CALL OPARSE(CDA, SQLSTM, LEN_TRIM(SQLSTM), 1, 2) + IF (CDA(7) .NE. 0) THEN + CALL ERRPT(LDA, CDA) + GOTO 900 + END IF + +* Define the output variables for the SELECT. + CALL ODEFIN(CDA, 1, MSGID, 4, 3, 0, %VAL(-1), %VAL(-1), + + 0, 0, %VAL(-1), %VAL(-1)) + IF (CDA(7) .NE. 0) THEN + CALL ERRPT(LDA, CDA) + GOTO 900 + END IF + + CALL ODEFIN(CDA, 2, MSGLEN, 4, 3, 0, %VAL(-1), %VAL(-1), + + 0, 0, %VAL(-1), %VAL(-1)) + IF (CDA(7) .NE. 0) THEN + CALL ERRPT(LDA, CDA) + GOTO 900 + END IF + + CALL ODEFIN(CDA, 3, DBIN, 200000, 24, 0, INDP, %VAL(-1), + + 0, 0, RLEN, RCODE) + IF (CDA(7) .NE. 0) THEN + CALL ERRPT(LDA, CDA) + GOTO 900 + END IF + +* Do the query, getting the MSG_ID to position the cursor, and +* the first 100 bytes of the message. +* CANCEL and EXACT are FALSE. + CALL OEXFET(CDA, 1, 0, 0) + IF (CDA(7) .NE. 0) THEN + CALL ERRPT(LDA, CDA) + GOTO 900 + END IF + + WRITE (*, '(1X, A, I4, A)') 'Message', MSGID, + +' is available.' + WRITE (*, '(1X, A, I7, A)') 'The length is', MSGLEN, + +' bytes.' + +* Play out the message, calling the DAC routine for each +* 64K chunk fetched by OFLNG. + + OFFSET = 0 + N = MSGLEN/65536 + 1 + DO 200 J = 1, N + IF (MSGLEN .LT. 65536) THEN + LEN = MSGLEN + ELSE + LEN = 65536 + ENDIF + CALL OFLNG(CDA, 3, DBIN, LEN, 24, RETL, OFFSET) + IF (CDA(7) .NE. 0) THEN + CALL ERRPT(LDA, CDA) + GOTO 900 + ENDIF + CALL PLAYMSG(DBIN, LEN) + MSGLEN = MSGLEN - LEN + IF (MSGLEN .LT. 0) GO TO 900 +200 CONTINUE + +900 CALL OCLOSE(CDA) + IF (CDA(7) .NE. 0) THEN + CALL ERRPT(LDA, CDA) + GOTO 900 + END IF + CALL OLOGOF(LDA) + IF (LDA(7) .NE. 0) THEN + CALL ERRPT(LDA, CDA) + GOTO 900 + END IF + +999 STOP 'End of OCIDEMO3.' + END + + SUBROUTINE PLAYMSG(OUT, LEN) + BYTE OUT(65536) + INTEGER LEN + + WRITE (*, '(1X, A, I7, A)') 'Playing', LEN, ' bytes.' + RETURN + END + + + SUBROUTINE ERRPT(LDA, CDA) + INTEGER*2 LDA(32), CDA(32) + + CHARACTER*132 MSG + + MSG = ' ' + IF (LDA(7) .NE. 0) THEN + CDA(7) = LDA(7) + CDA(6) = 0 + ENDIF + + IF (CDA(6) .NE. 0) THEN + WRITE (*, '(1X, A, I3)') 'Error processing OCI function', + + CDA(6) + ENDIF + + CALL OERHMS (LDA, CDA(7), MSG, 132) + WRITE (*, '(1X, A)') MSG + + RETURN + END + + + + INTEGER FUNCTION LEN_TRIM(STRING) + CHARACTER*(*) STRING + + INTEGER NEXT + + DO 10 NEXT = LEN(STRING), 1, -1 + IF (STRING(NEXT : NEXT) .NE. ' ') THEN + LEN_TRIM = NEXT + RETURN + ENDIF +10 CONTINUE + + LEN_TRIM = 0 + + RETURN + END + + diff --git a/fgacdemo.sql b/fgacdemo.sql new file mode 100644 index 0000000..9217e92 --- /dev/null +++ b/fgacdemo.sql @@ -0,0 +1,587 @@ +rem +rem $Header: fgacdemo.sql 09-may-2003.13:35:57 rvissapr Exp $ +rem +rem Copyright (c) 1999, 2003, Oracle Corporation. All rights reserved. +rem +rem NAME +rem fgacdemo.sql - Build Oracle8i Security Demonstration Tables/Users +rem DESCRIPTION +rem This SQL script builds Oracle8i Security demonstration tables/user +rem MODIFIED (MM/DD/YY) +rem rvissapr 05/09/03 - remove temporary tablespace clause +rem rvissapr 01/08/03 - bug 2368367 +rem dmwong 03/08/00 - remove MURRAY . +rem dmwong 01/05/00 - merge the split line +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + +rem This script builds a database that enforces security based on +rem server enforced security using fine grain access control and application +rem context. Appropriate security context is setup using application +rem context and fine grain access control enforces data access control using +rem these secure application context. + +rem ======================================================================== +rem First clean up previous installs +rem ======================================================================== + +CONNECT SYSTEM/MANAGER +DROP TRIGGER SECDEMO.SET_EXPENSE_CTX ; +DROP USER MOREAU; +DROP USER MILLER; + +DROP USER SECDEMO CASCADE; +DROP CONTEXT expenses_reporting; + +rem ======================================================================== +rem Then create users for the demo (you may want to customize tablespaces) +rem ======================================================================== + +CREATE USER "SECDEMO" IDENTIFIED BY "SECDEMO" +DEFAULT TABLESPACE "SYSTEM" +PROFILE DEFAULT +QUOTA UNLIMITED ON "SYSTEM" ACCOUNT UNLOCK; + +GRANT CONNECT TO SECDEMO; +GRANT CREATE ANY CONTEXT TO SECDEMO; +GRANT CREATE ANY SYNONYM TO SECDEMO; +GRANT CREATE TRIGGER TO "SECDEMO"; +GRANT CREATE PROCEDURE TO SECDEMO; +GRANT "EXECUTE_CATALOG_ROLE" TO "SECDEMO"; +ALTER USER "SECDEMO" DEFAULT ROLE ALL; + + +CREATE USER "MOREAU" IDENTIFIED BY "MOREAU" +DEFAULT TABLESPACE "SYSTEM" +PROFILE DEFAULT +QUOTA UNLIMITED ON "SYSTEM" ACCOUNT UNLOCK; +GRANT CONNECT TO MOREAU; + + +CREATE USER "MILLER" IDENTIFIED BY "MILLER" +DEFAULT TABLESPACE "SYSTEM" +PROFILE DEFAULT +QUOTA UNLIMITED ON "SYSTEM" ACCOUNT UNLOCK; +GRANT CONNECT TO MILLER; + + +GRANT "EXECUTE_CATALOG_ROLE" TO "MOREAU"; +ALTER USER "MOREAU" DEFAULT ROLE ALL; +GRANT "EXECUTE_CATALOG_ROLE" TO "MILLER"; +ALTER USER "MILLER" DEFAULT ROLE ALL; + +CREATE PUBLIC SYNONYM exprep_ctx FOR secdemo.exprep_ctx; + +rem ======================================================================== +rem Now Create the tables/views for the demo +rem ======================================================================== + +CONNECT SECDEMO/SECDEMO + +rem Create new datasources + +CREATE TABLE EMPLOYEE ( + EMPLOYEE_ID NUMBER(4), + LAST_NAME VARCHAR2(15), + FIRST_NAME VARCHAR2(15), + MIDDLE_INITIAL VARCHAR2(1), + COST_CENTER_ID NUMBER(4), + MANAGER_ID NUMBER(4)); + +CREATE TABLE COST_CENTER ( + COST_CENTER_ID NUMBER(4), + MANAGER_ID NUMBER(4), + DESCRIPTION VARCHAR2(30)); + +CREATE TABLE EXP_REPORT ( + REPORT_ID NUMBER(4), + EMPLOYEE_ID NUMBER(4), + COST_CENTER_ID NUMBER(4), + SUBMISSION_DATE DATE, + APPROVAL_DATE DATE, + PURPOSE VARCHAR2(30)); + +CREATE TABLE EXP_LINE ( + REPORT_ID NUMBER(4), + LINE_ID NUMBER(4), + TYPE_ID NUMBER(4), + RECEIVED_AMOUNT NUMBER(7,2), + RECEIPT NUMBER(1), + EXP_DATE DATE, + CURRENCY_ID NUMBER(4)); + +CREATE TABLE EXP_TYPE ( + TYPE_ID NUMBER(4), + DESCRIPTION VARCHAR2(30)); + +CREATE TABLE EXP_CURRENCY ( + CURRENCY_ID NUMBER(4), + DESCRIPTION VARCHAR2(30), + RATE NUMBER(7,2), + SYMBOL VARCHAR2(2)); + +rem Add views + +DROP VIEW EXP_REPORT_SUM_VIEW; + +CREATE VIEW EXP_REPORT_SUM_VIEW AS +SELECT E.EMPLOYEE_ID,E.LAST_NAME,R.REPORT_ID, R.PURPOSE, + SUM(L.RECEIVED_AMOUNT) TOTAL_AMOUNT, R.COST_CENTER_ID, + R.SUBMISSION_DATE,R.APPROVAL_DATE +FROM EMPLOYEE E,EXP_REPORT R, EXP_LINE L +WHERE E.EMPLOYEE_ID=R.EMPLOYEE_ID +AND R.REPORT_ID=L.REPORT_ID +GROUP BY E.EMPLOYEE_ID,R.REPORT_ID,E.LAST_NAME, R.PURPOSE, R.COST_CENTER_ID, + R.SUBMISSION_DATE,R.APPROVAL_DATE; + + +rem Grant SELECT privileges to PUBLIC on the datasources + +GRANT SELECT ON EMPLOYEE TO PUBLIC; +GRANT SELECT ON COST_CENTER TO PUBLIC; +GRANT SELECT ON EXP_REPORT TO PUBLIC; +GRANT SELECT ON EXP_LINE TO PUBLIC; +GRANT SELECT ON EXP_TYPE TO PUBLIC; +GRANT SELECT ON EXP_CURRENCY TO PUBLIC; +GRANT SELECT ON EXP_REPORT_SUM_VIEW TO PUBLIC; + +GRANT UPDATE ON EXP_REPORT TO PUBLIC; +GRANT DELETE ON EXP_REPORT TO PUBLIC; +GRANT INSERT ON EXP_REPORT TO PUBLIC; +GRANT DELETE ON EXP_LINE TO PUBLIC; +GRANT INSERT ON EXP_LINE TO PUBLIC; + + +rem Insert Data + +INSERT INTO EXP_CURRENCY VALUES (1, '$ US DOLLAR',1.0,'$'); +INSERT INTO EXP_CURRENCY VALUES (2, 'FF - FRENCH FRANC',0.2,'FF'); +INSERT INTO EXP_CURRENCY VALUES (3, '£ - UK POUNDS',2.0,'£'); +INSERT INTO EXP_CURRENCY VALUES (4, 'DM - DEUTCH MARKS',0.6,'DM'); + +INSERT INTO EXP_TYPE VALUES (1, 'AIRFARE'); +INSERT INTO EXP_TYPE VALUES (2, 'TAXI'); +INSERT INTO EXP_TYPE VALUES (3, 'RENTAL CAR'); +INSERT INTO EXP_TYPE VALUES (4, 'LIMO/CAR SERVICE'); +INSERT INTO EXP_TYPE VALUES (5, 'ROOM'); +INSERT INTO EXP_TYPE VALUES (6, 'FOOD/DRINKS ON HOTEL BILL'); +INSERT INTO EXP_TYPE VALUES (7, 'PHONE/OTHER ON HOTEL BILL'); +INSERT INTO EXP_TYPE VALUES (8, 'BREAKFAST'); +INSERT INTO EXP_TYPE VALUES (9, 'LUNCH'); +INSERT INTO EXP_TYPE VALUES (10, 'DINNER'); + +INSERT INTO COST_CENTER VALUES (692, 7839, 'ADMINISTRATION'); +INSERT INTO COST_CENTER VALUES (672, 7839, 'US SALES'); +INSERT INTO COST_CENTER VALUES (667,7506, 'ASIAN SALES'); +INSERT INTO COST_CENTER VALUES (670,7569, 'EUROPEAN SALES'); +INSERT INTO COST_CENTER VALUES (668,7507, 'WW SUPPORT'); +INSERT INTO COST_CENTER VALUES (671,7839, 'WW MARKETING'); +INSERT INTO COST_CENTER VALUES (673, 7505, 'US MARKETING'); +INSERT INTO COST_CENTER VALUES (674, 7698, 'ASIAN MARKETING'); +INSERT INTO COST_CENTER VALUES (669, 7566, 'EUROPEAN MARKETING'); + + +INSERT INTO EMPLOYEE VALUES + (7369,'SMITH','JOHN','Q',667,7902); +INSERT INTO EMPLOYEE VALUES + (7499,'ALLEN','KEVIN','J',670,7698); +INSERT INTO EMPLOYEE VALUES + (7505,'DOYLE','JEAN','K',671,7839); +INSERT INTO EMPLOYEE VALUES + (7506,'DENNIS','LYNN','S',671,7839); +INSERT INTO EMPLOYEE VALUES + (7507,'BAKER','LESLIE','D',671,7839); +INSERT INTO EMPLOYEE VALUES + (7521,'WARD','CYNTHIA','D',670,7698); +INSERT INTO EMPLOYEE VALUES + (7555,'PETERS','DANIEL','T',670,7505); +INSERT INTO EMPLOYEE VALUES + (7557,'SHAW','KAREN','P',670,7505); +INSERT INTO EMPLOYEE VALUES + (7560,'DUNCAN','SARAH','S',670,7506); +INSERT INTO EMPLOYEE VALUES + (7564,'LANGE','GREGORY','J',670,7506); +INSERT INTO EMPLOYEE VALUES + (7566,'JONES','TERRY','M',671,7839); +INSERT INTO EMPLOYEE VALUES + (7569,'MOREAU','ALBERT','L',670,7839); +INSERT INTO EMPLOYEE VALUES + (7600,'PORTER','RAYMOND','Y',670,7505); +INSERT INTO EMPLOYEE VALUES + (7609,'LEWIS','RICHARD','M',668,7507); +INSERT INTO EMPLOYEE VALUES + (7654,'MARTIN','KENNETH','J',670,7698); +INSERT INTO EMPLOYEE VALUES + (7676,'SOMMERS','DENISE','D',668,7507); +INSERT INTO EMPLOYEE VALUES + (7698,'JURGEN','DIETER','S',670,7839); +INSERT INTO EMPLOYEE VALUES + (7782,'CLARK','CAROL','F',671,7839); +INSERT INTO EMPLOYEE VALUES + (7788,'SCOTT','DONALD','T',669,7566); +INSERT INTO EMPLOYEE VALUES + (7789,'WEST','LIVIA','N',670,7506); +INSERT INTO EMPLOYEE VALUES + (7799,'FISHER','MATTHEW','G',669,7569); +INSERT INTO EMPLOYEE VALUES + (7820,'ROSS','PAUL','S',670,7505); +INSERT INTO EMPLOYEE VALUES + (7839,'KING','FRANCIS','A',672,7839); +INSERT INTO EMPLOYEE VALUES + (7844,'TURNER','MARY','A',670,7698); +INSERT INTO EMPLOYEE VALUES + (7876,'ADAMS','DIANE','G',667,7788); +INSERT INTO EMPLOYEE VALUES + (7900,'JAMES','FRED','S',667,7698); +INSERT INTO EMPLOYEE VALUES + (7902,'FORD','JENNIFER','D',669,7566); +INSERT INTO EMPLOYEE VALUES + (7916,'ROBERTS','GRACE','M',669,7569); +INSERT INTO EMPLOYEE VALUES + (7919,'DOUGLAS','MICHAEL','A',667,7799); +INSERT INTO EMPLOYEE VALUES + (7934,'MILLER','BARBARA','M',670,7782); +INSERT INTO EMPLOYEE VALUES + (7950,'JENSEN','ALICE','B',667,7505); +INSERT INTO EMPLOYEE VALUES + (7954,'MURRAY','JAMES','T',670,7506); + + +INSERT INTO EXP_REPORT VALUES + (1,7954,667,SYSDATE-3,SYSDATE,'Customer Visit'); + +INSERT INTO EXP_REPORT VALUES + (2,7950,670,SYSDATE,NULL,'Customer Visit'); +INSERT INTO EXP_REPORT VALUES + (3,7954,670,SYSDATE,NULL,'Customer Visit'); +INSERT INTO EXP_REPORT VALUES + (4,7954,671,SYSDATE,NULL,'Customer Visit'); +INSERT INTO EXP_REPORT VALUES + (5,7934,670,SYSDATE-1,NULL,'Training '); +INSERT INTO EXP_REPORT VALUES + (6,7698,670,SYSDATE-7,NULL,'Training '); +INSERT INTO EXP_REPORT VALUES + (7,7698,670,SYSDATE-7,NULL,'Customer Visit '); +INSERT INTO EXP_REPORT VALUES + (8,7934,671,SYSDATE-7,NULL,'Training '); +INSERT INTO EXP_REPORT VALUES + (9,7934,670,SYSDATE-7,NULL,'Training '); +INSERT INTO EXP_REPORT VALUES + (10,7954,670,SYSDATE-20,SYSDATE-20,'Customer Visit'); +INSERT INTO EXP_REPORT VALUES + (11,7954,670,SYSDATE-20,SYSDATE-17,'Customer Visit'); +INSERT INTO EXP_REPORT VALUES + (12,7569,670,SYSDATE-22,SYSDATE-19,'Customer Visit'); + + +INSERT INTO EXP_LINE VALUES + (1,1,1,500.2,1,SYSDATE-33,1); +INSERT INTO EXP_LINE VALUES + (1,2,8,12.2,1,SYSDATE-33,1); +INSERT INTO EXP_LINE VALUES + (1,3,9,20.0,1,SYSDATE-33,1); +INSERT INTO EXP_LINE VALUES + (2,1,2,21.0,1,SYSDATE-23,1); +INSERT INTO EXP_LINE VALUES + (2,2,5,200.0,1,SYSDATE-23,1); +INSERT INTO EXP_LINE VALUES + (2,3,9,12.0,1,SYSDATE-23,1); +INSERT INTO EXP_LINE VALUES + (2,4,10,20.0,1,SYSDATE-23,1); +INSERT INTO EXP_LINE VALUES + (3,1,9,10.2,1,SYSDATE-33,1); +INSERT INTO EXP_LINE VALUES + (4,1,5,210.3,1,SYSDATE-31,1); +INSERT INTO EXP_LINE VALUES + (4,2,6,21.0,1,SYSDATE-31,1); +INSERT INTO EXP_LINE VALUES + (4,3,7,12.1,1,SYSDATE-31,1); +INSERT INTO EXP_LINE VALUES + (4,4,8,10.3,1,SYSDATE-31,1); +INSERT INTO EXP_LINE VALUES + (5,1,10,53.2,1,SYSDATE-28,1); +INSERT INTO EXP_LINE VALUES + (6,1,10,23.2,1,SYSDATE-44,2); +INSERT INTO EXP_LINE VALUES + (7,1,5,210.3,1,SYSDATE-28,1); +INSERT INTO EXP_LINE VALUES + (7,2,6,21.0,1,SYSDATE-28,1); +INSERT INTO EXP_LINE VALUES + (7,3,7,12.1,1,SYSDATE-28,1); +INSERT INTO EXP_LINE VALUES + (7,4,8,10.3,1,SYSDATE-28,1); +INSERT INTO EXP_LINE VALUES + (8,1,5,1120.3,1,SYSDATE-27,3); +INSERT INTO EXP_LINE VALUES + (8,2,6,20.0,1,SYSDATE-27,3); +INSERT INTO EXP_LINE VALUES + (8,3,7,17.1,1,SYSDATE-27,3); +INSERT INTO EXP_LINE VALUES + (8,4,8,20.3,1,SYSDATE-27,3); + +INSERT INTO EXP_LINE VALUES + (9,1,5,1120.3,1,SYSDATE-20,3); +INSERT INTO EXP_LINE VALUES + (9,2,6,20.0,1,SYSDATE-20,3); +INSERT INTO EXP_LINE VALUES + (9,3,7,17.1,1,SYSDATE-20,3); +INSERT INTO EXP_LINE VALUES + (9,4,8,20.3,1,SYSDATE-20,3); +INSERT INTO EXP_LINE VALUES + (9,5,5,1120.3,1,SYSDATE-20,3); +INSERT INTO EXP_LINE VALUES + (9,6,6,20.0,1,SYSDATE-20,3); + +INSERT INTO EXP_LINE VALUES + (10,1,5,1120.3,1,SYSDATE-45,1); +INSERT INTO EXP_LINE VALUES + (11,1,5,1120.3,1,SYSDATE-38,1); +INSERT INTO EXP_LINE VALUES + (12,1,5,1120.3,1,SYSDATE-38,2); +INSERT INTO EXP_LINE VALUES + (12,2,5,1120.3,1,SYSDATE-38,2); + + +rem Create indexes + +CREATE UNIQUE INDEX I_EMPLOYEE$EMPLOYEE_ID ON EMPLOYEE (EMPLOYEE_ID); +CREATE UNIQUE INDEX I_COST_CENTER$COST_CENTER_ID + ON COST_CENTER (COST_CENTER_ID); +CREATE UNIQUE INDEX I_EXP_REPORT$REPORT_ID ON EXP_REPORT (REPORT_ID); +CREATE UNIQUE INDEX I_EXP_LINE ON EXP_LINE (REPORT_ID,LINE_ID); +CREATE UNIQUE INDEX I_EXP_TYPE$TYPE_ID ON EXP_TYPE (TYPE_ID); +CREATE UNIQUE INDEX I_EXP_CURRENCY$CURRENCY_ID ON EXP_CURRENCY (CURRENCY_ID); + +rem Add constraints + +ALTER TABLE EMPLOYEE ADD + CHECK (EMPLOYEE_ID IS NOT NULL); + +ALTER TABLE EXP_REPORT ADD + CHECK (REPORT_ID IS NOT NULL); +ALTER TABLE EXP_REPORT ADD + CHECK (EMPLOYEE_ID IS NOT NULL); +ALTER TABLE EXP_REPORT ADD + CHECK (COST_CENTER_ID IS NOT NULL); + +rem PK +ALTER TABLE EMPLOYEE ADD + PRIMARY KEY (EMPLOYEE_ID); +ALTER TABLE COST_CENTER ADD + PRIMARY KEY (COST_CENTER_ID); +ALTER TABLE EXP_REPORT ADD + PRIMARY KEY (REPORT_ID); +ALTER TABLE EXP_LINE ADD + PRIMARY KEY (REPORT_ID,LINE_ID); +ALTER TABLE EXP_TYPE ADD + PRIMARY KEY (TYPE_ID); +ALTER TABLE EXP_CURRENCY ADD + PRIMARY KEY (CURRENCY_ID); + +rem FK +ALTER TABLE EMPLOYEE ADD + FOREIGN KEY (COST_CENTER_ID) REFERENCES COST_CENTER; +ALTER TABLE EMPLOYEE ADD + FOREIGN KEY (MANAGER_ID) REFERENCES EMPLOYEE; +ALTER TABLE EXP_REPORT ADD + FOREIGN KEY (EMPLOYEE_ID) REFERENCES EMPLOYEE; +ALTER TABLE EXP_REPORT ADD + FOREIGN KEY (COST_CENTER_ID) REFERENCES COST_CENTER; +ALTER TABLE EXP_LINE ADD + FOREIGN KEY (REPORT_ID) REFERENCES EXP_REPORT; +ALTER TABLE EXP_LINE ADD + FOREIGN KEY (TYPE_ID) REFERENCES EXP_TYPE; +ALTER TABLE EXP_LINE ADD + FOREIGN KEY (CURRENCY_ID) REFERENCES EXP_CURRENCY; + + + +rem ======================================================================== +rem Now setting Oracle8i Security features +rem ======================================================================== + +rem ================================================================= +rem Creation of the application context +rem ================================================================= +rem +rem SECDEMO User must have the CREATE ANY CONTEXT system privilege +rem + +CONNECT SECDEMO/SECDEMO + +CREATE CONTEXT expenses_reporting USING secdemo.exprep_ctx; + +rem ================================================================= +rem Creation of the package witch implements the context +rem ================================================================= + +CREATE OR REPLACE PACKAGE exprep_ctx AS + PROCEDURE set_ctx; +END; +/ +SHOW ERRORS + +CREATE OR REPLACE PACKAGE BODY exprep_ctx IS + + PROCEDURE set_ctx IS + empnum number; + countrec number; + cc number; + + role varchar2(20); + BEGIN + + -- SET emp_number + select EMPLOYEE_ID into empnum from employee + where last_name = sys_context('userenv', 'session_user'); + + dbms_session.set_context('expenses_reporting','emp_number', empnum); + + -- SET ROLE ? + select count(*) into countrec from cost_center where manager_id=empnum; + IF (countrec > 0) THEN + dbms_session.set_context('expenses_reporting','exp_role', 'MANAGER'); + ELSE + dbms_session.set_context('expenses_reporting','exp_role', 'EMPLOYEE'); + END IF; + + -- SET cc_number + select COST_CENTER_ID into cc from employee + where last_name = sys_context('userenv', 'session_user'); + dbms_session.set_context('expenses_reporting','cc_number', cc); + + + END; +END; +/ +SHOW ERRORS +/ +rem CREATE PUBLIC SYNONYM exprep_ctx FOR secdemo.exprep_ctx; +GRANT EXECUTE ON secdemo.exprep_ctx TO public; +/ + +rem ================================================================= +rem Creation of the policy function +rem ================================================================= + +CREATE OR REPLACE PACKAGE exp_security AS + FUNCTION empview_sec(owner varchar2, objname varchar2) RETURN varchar2; + FUNCTION empnum_sec(owner varchar2, objname varchar2) RETURN varchar2; + FUNCTION empnumline_sec(owner varchar2, objname varchar2) RETURN varchar2; + FUNCTION ccid_mgr_sec(owner varchar2, objname varchar2) RETURN varchar2; + +END exp_security; +/ +SHOW ERRORS + +CREATE OR REPLACE PACKAGE BODY exp_security IS + + FUNCTION empview_sec(owner varchar2, objname varchar2) RETURN varchar2 IS + predicate varchar2(2000); + BEGIN + + IF (sys_context('expenses_reporting', 'exp_role') = 'MANAGER') THEN + predicate := + 'COST_CENTER_ID = sys_context(''expenses_reporting'',''cc_number'')'; + ELSE + predicate := + 'EMPLOYEE_ID = sys_context(''expenses_reporting'',''emp_number'')'; + END IF; + + RETURN predicate; + END empview_sec; + + FUNCTION empnum_sec(owner varchar2, objname varchar2) RETURN varchar2 IS + predicate varchar2(2000); + BEGIN + predicate := + 'EMPLOYEE_ID = sys_context(''expenses_reporting'',''emp_number'')'; + RETURN predicate; + END empnum_sec; + + FUNCTION empnumline_sec(owner varchar2, objname varchar2) RETURN varchar2 IS + predicate varchar2(2000); + BEGIN + predicate := 'REPORT_ID IN (SELECT REPORT_ID FROM EXP_REPORT WHERE \ + EMPLOYEE_ID = sys_context(''expenses_reporting'',''emp_number''))'; + RETURN predicate; + END empnumline_sec; + + FUNCTION ccid_mgr_sec(owner varchar2, objname varchar2) RETURN varchar2 IS + predicate varchar2(2000); + BEGIN + predicate := + 'COST_CENTER_ID = (SELECT COST_CENTER_ID FROM COST_CENTER WHERE \ + MANAGER_ID = sys_context(''expenses_reporting'',''emp_number''))'; + RETURN predicate; + END ccid_mgr_sec; + + +END; +/ +SHOW ERRORS + + +rem ================================================================= +rem Association of the policy function with a table or a view +rem ================================================================= +rem SELECT POLICY_NAME FROM ALL_POLICIES; + +rem POLICY #1 +rem YOU CAN SELECT ONLY YOUR REPORTS IF YOU ARE A EMPLOYEE +rem YOU CAN SELECT YOUR REPORTS AND ALL THE REPORT IN YOUR COST CENTER +rem IF YOU ARE THE COST CENTER MANAGER +EXECUTE DBMS_RLS.DROP_POLICY('secdemo','EXP_REPORT_SUM_VIEW', 'exp_report_VIEW_policy'); +EXECUTE DBMS_RLS.ADD_POLICY('secdemo','EXP_REPORT_SUM_VIEW', 'exp_report_VIEW_policy','secdemo','exp_security.empview_sec','SELECT'); + +rem POLICY #2 +rem YOU CAN DELETE YOUR REPORTS ONLY +EXECUTE DBMS_RLS.DROP_POLICY('secdemo','exp_report','exp_report_policy'); +EXECUTE DBMS_RLS.ADD_POLICY('secdemo','exp_report','exp_report_policy', 'secdemo','exp_security.empnum_sec','DELETE'); + +rem POLICY #2 +rem YOU CAN INSET A REPORT FOR YOURSELF ONLY +EXECUTE DBMS_RLS.DROP_POLICY('secdemo','exp_report', 'exp_report_insert_policy'); +EXECUTE DBMS_RLS.ADD_POLICY('secdemo','exp_report','exp_report_insert_policy', 'secdemo','exp_security.empnum_sec','INSERT'); + +rem POLICY #4 +rem YOU CAN DELETE A LINE IN YOUR REPORT ONLY +rem IF YOU ARE THE OWNER OF THE REPORT +EXECUTE DBMS_RLS.DROP_POLICY('secdemo','exp_line','exp_line_policy'); +EXECUTE DBMS_RLS.ADD_POLICY('secdemo','exp_line','exp_line_policy','secdemo', 'exp_security.empnumline_sec','DELETE'); + +rem POLICY #5 +rem YOU CAN APPROVE (UPDATE) AN REPORT ONLY +rem IF YOU ARE THE COST CENTER MANAGER +EXECUTE DBMS_RLS.DROP_POLICY('secdemo','exp_report', 'exp_report_Approve_policy'); +EXECUTE DBMS_RLS.ADD_POLICY('secdemo','exp_report', 'exp_report_Approve_policy','secdemo','exp_security.ccid_mgr_sec','UPDATE'); + +rem LIST ALL POLICIES +SELECT POLICY_NAME FROM ALL_POLICIES; + +rem ================================================================= +rem Create a trigger on logon on database to setup the context +rem ================================================================= +rem COMPATIBLE parameter needs to be 8.1.0.0.0 or greater +rem This trigger should be created by an account with BDA role + +rem CONNECT SYSTEM/MANAGER +rem CREATE OR REPLACE TRIGGER SECDEMO.SET_EXPENSE_CTX +rem AFTER LOGON +rem ON DATABASE +rem BEGIN +rem SECDEMO.EXPREP_CTX.SET_CTX; +rem END; +rem / + + + + + + + + + + + + + diff --git a/giffile.dat b/giffile.dat new file mode 100644 index 0000000..aa5faa0 Binary files /dev/null and b/giffile.dat differ diff --git a/inhdemo.sql b/inhdemo.sql new file mode 100644 index 0000000..3094fe8 --- /dev/null +++ b/inhdemo.sql @@ -0,0 +1,737 @@ +Rem +Rem $Header: inhdemo.sql 24-jan-2002.15:48:51 cbarclay Exp $ +Rem +Rem inhdemo.sql +Rem +Rem Copyright (c) 2001, 2002, Oracle Corporation. All rights reserved. +Rem +Rem NAME +Rem inhdemo.sql - Demonstrate Inheritance feature +Rem +Rem DESCRIPTION +Rem Demonstrate Inheritance feature +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem cbarclay 01/24/02 - demo updated +Rem cbarclay 01/15/02 - plsql is of and treat +Rem hyeh 05/01/01 - fix query format +Rem hyeh 04/10/01 - Merged hyeh_inh_tyev_demos +Rem hyeh 04/09/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +COLUMN mysubtype FORMAT A70 +SET ECHO ON + +connect system/manager +drop user inhdemo1 cascade; +drop user inhdemo3 cascade; + +grant connect, resource to inhdemo1 identified by inhdemo1; +grant connect, resource to inhdemo3 identified by inhdemo3; + +connect inhdemo1/inhdemo1 + +Rem +Rem Inheriting Attributes +Rem + +create or replace type Person_t as object +( ssn number, + name varchar2(30), + address varchar2(100), + map member function mapfn return number, + static function check_type (in1 Person_t) return varchar2, + member function whatami return varchar2 +) not final; +/ +show error + +create or replace type Student_t under Person_t +( deptid number, + major varchar2(30) +) not final; +/ +show error + +create or replace type Employee_t under Person_t +( empid number, + mgr varchar2(30), + salary number(10,2), + overriding map member function mapfn return number, + member function raise_salary return Employee_t, + overriding member function whatami return varchar2 +) not final; +/ +show error + +create type PartTimeStudent_t under Student_t +( numhours number, + overriding map member function mapfn return number +); +/ +show error + +create or replace type body PartTimeStudent_t as +overriding map member function mapfn return number as + begin + return self.numhours; + end; +end; +/ +show errors + +create type dup_t as object +(dup student_t); +/ +show errors + +/* create and populate tables depend on types */ +create table person_obj of Person_t + not substitutable at all levels + (constraint pobj_pkey primary key(ssn)); +create table employee_obj of Employee_t + not substitutable at all levels + (constraint eobj_pkey primary key(ssn,empid), + mgr not null); +create table employee_obj2 of Employee_t + not substitutable at all levels; +create table student_obj of Student_t + not substitutable at all levels + (unique (name, deptid)); + +create table all_person (PersRefCol REF Person_t, tabname varchar2(20)); + +create table dup_students (ssn number, p student_t) + column p not substitutable at all levels; + +insert into person_obj values(12345, 'Joe','SF'); +insert into employee_obj values (2345, 'Max','LA',56, 'King',100.20); +insert into employee_obj2 values (2345, 'Max','LA',56, 'King',100.20); +insert into student_obj values (2345, 'Max','LA',300,'PLAY'); + +insert into all_person select REF(p), 'PERSON_OBJ' from person_obj p; +insert into all_person select REF(p), 'EMPLOYEE_OBJ' from employee_obj p; +insert into all_person select REF(p), 'EMPLOYEE_OBJ2' from employee_obj2 p; +insert into all_person select REF(p), 'EMPLOYEE_OBJ2-2' from employee_obj2 p; +insert into all_person select REF(p), 'STUDENT_OBJ' from student_obj p; + +insert into dup_students select ssn, value(p) from student_obj p; + +commit; + +select * from person_obj; +select * from employee_obj; +select * from employee_obj2; +select * from student_obj; +select * from dup_students; + +select deref(p.persrefcol), tabname from all_person p order by p.tabname; + +/* cannot insert subtype to non-substitutable column/table */ +insert into person_obj values + (Employee_t(12345, 'Joe','SF',null,null,null)); +insert into person_obj select treat(value(p) as person_t) from employee_obj p; + +update dup_students set p=PartTimeStudent_t(2345, 'Max','LA',300,'PLAY',0); + +/* create type body */ +create or replace type body Person_t as + map member function mapfn return number as + begin + return self.ssn; + end; + + static function check_type (in1 Person_t) return varchar2 as + n varchar2(40); + begin + n := + case + when in1 is of (ONLY Person_t) then 'PERSON_T' + when in1 is of (ONLY Employee_t) then 'EMPLOYEE_T' + when in1 is of (ONLY Student_t) then 'STUDENT_T' + when in1 is of (ONLY PartTimeStudent_t) then 'PARTTIMESTUDENT_T' + else 'UNKNOWN' end; + return n; + end; + + member function whatami return varchar2 as + begin + return 'PERSON_T'; + end; +end; +/ +show error + +create or replace type body Employee_t as + overriding map member function mapfn return number as + begin + return self.empid; + end; + + member function raise_salary return Employee_t as + e_v1 Employee_t; + begin + update employee_obj e set salary = self.salary + 999.99 + where self.ssn = ssn and self.salary is null + returning value(e) into e_v1; + return e_v1; + end; + + overriding member function whatami return varchar2 as + begin + return 'EMPLOYEE_T'; + end; +end; +/ +show error + +Rem +Rem Assignments +Rem + +Rem Object (REF) assignment + +create table t +( perscol Person_t, + empcol Employee_t, + stucol Student_t) +column perscol not substitutable at all levels, +column empcol not substitutable at all levels, +column stucol not substitutable at all levels +; + +insert into t values +( Person_t(12345, 'Joe','SF'), + Employee_t(9876, 'Bill','SJ',1111,NULL,100), + Student_t(2345, 'Max','LA',300,'PLAY') +); + +commit; + +Rem Widening + +update t set perscol = empcol; +select * from t; + +set serveroutput on +declare + var1 Person_t; + var2 Employee_t; + var3 Employee_t; +begin + select empcol into var2 from t t where t.perscol.ssn=12345; + var1 := var2; + dbms_output.put_line('ssn:'||to_char(var1.ssn)); + var3 := treat(var1 as Employee_t); + dbms_output.put_line('empid:'||to_char(var3.empid)); + insert into t values (Person_t(999,'Boss','KS'), + treat(var1 as Employee_t),null); + select empcol into var3 from t t where t.perscol.ssn=999; + dbms_output.put_line('empid:'||to_char(var3.empid)); +end; +/ + +rollback; + +Rem Narrowing + +update t set empcol = TREAT(perscol AS Employee_t); +select * from t; + +rollback; + +Rem Compile Error + +update t set empcol = perscol; +update t set empcol = stucol; + +declare + var1 Student_t; + var2 Employee_t; +begin + var1 := var2; +end; +/ + +rollback; + +Rem Collection Assignment + +create type PersonSet as table of Person_t; +/ +create type StudentSet as table of Student_t; +/ + +declare + var1 PersonSet; var2 StudentSet; + elem1 Person_t; elem2 Student_t; +begin + var1 := var2; /* ILLEGAL - collections not of same type */ +end; +/ + +declare + var1 PersonSet; var2 StudentSet; + elem1 Person_t; elem2 Student_t; +begin + var1 := PersonSet (elem1, elem2); /* LEGAL : Element is of subtype */ +end; +/ + +Rem +Rem Comparison +Rem + +Rem Object Comparison + +insert into t values +(Person_t(99, 'Joey', 'LA'), + Employee_t(99, 'Joey', 'LA', 1,'Max',90.99), + Student_t(99, 'Joey', 'LA', 2022, 'Minor')); + +select * from t where perscol=empcol or perscol=stucol; +select * from t where perscol=treat(empcol as person_t); +select * from t where treat(stucol as person_t)=treat(empcol as person_t); +select * from t where stucol=empcol; + +Rem REF Comparison + +select count(distinct(persrefcol)) from all_person; +select count(distinct(deref(persrefcol))) from all_person; + +/* valid compare */ +select deref(p.persrefcol), p.tabname + from all_person p where + exists (select p2.persrefcol from all_person p2 where + p.persrefcol = p2.persrefcol and p.tabname != p2.tabname) + order by p.tabname; + +select p.tabname + from all_person p where + (select ref(s) from person_obj s) = (select ref(k) from employee_obj k); + +select p.tabname + from all_person p where + (select ref(s) from student_obj s) = persrefcol; + +select p.tabname + from all_person p where + (select treat(ref(s) as ref person_t) from student_obj s) = + (select ref(k) from employee_obj k); + +/* invalid compare */ +select p.tabname + from all_person p where + (select ref(s) from student_obj s) = (select ref(k) from employee_obj k); + +Rem +Rem SQL Operators +Rem + +create view Person_v of Person_t with object identifier(ssn) as + select * from person_obj p; +create view Student_v of Student_t under Person_v as + select * from student_obj p; + +Rem VALUE + +select VALUE(p) from Person_v p order by p.ssn; +select VALUE(p) from ONLY(Person_v) p order by p.ssn; + +Rem REF + +select REF(p) from Person_v p; + +select REF(p) from Person_v p +minus +select REF(p) from person_obj p +minus +select REF(p) from student_obj p; + +Rem DEREF + +select DEREF(REF(p)) from person_v p order by p.ssn desc; + +/* Do some PL/SQL with VALUE, REF, DEREF of person_v */ + +Rem TREAT + +select TREAT(VALUE(p) as Student_t) from Person_v p order by p.ssn desc; + +select DEREF(a) from + (select TREAT(REF(p) as REF Student_t) a from Person_v p) k + order by k.a.ssn; + +insert into employee_obj values + (Employee_t(2929, 'Billy', 'TX', 9, 'Max', NULL)); + +create global temporary table tmptb1 (a Employee_t) + column a not substitutable at all levels; + +set serveroutput on +declare + var1 Person_t := Employee_t(2929, 'Billy', 'TX', 9, 'Max', NULL); + var2 Person_t; + var3 Employee_t; + v_type varchar2(20); +begin + insert into tmptb1 values(TREAT(var1 as Employee_t)) + returning a into var2; + if var2 is null then + dbms_output.put_line('var2 is null - WRONG'); + else + var3 := TREAT(var2 as Employee_t); + v_type := Person_t.check_type(var3); + if v_type = 'EMPLOYEE_T' then + dbms_output.put_line('row updated, ssn:'||var3.ssn||', salary:'|| + to_char(var3.salary)); + else + dbms_output.put_line('var3 is of type is '||v_type||' - WRONG'); + end if; + end if; +end; +/ + +select * from employee_obj order by ssn; + +rollback; + +Rem IS OF + +select REF(p) from person_v p + where VALUE(p) IS OF (Employee_t, Student_t); + +select VALUE(p) from person_v p + where VALUE(p) IS OF (ONLY Person_t); + +select TREAT(VALUE(p) AS Student_t) + from Person_v p + where VALUE(p) IS OF (ONLY Student_t); + +select * from all_person + where DEREF(PersRefCol) IS OF (Student_t); + +Rem +Rem View Hierarchy +Rem +create table persons ( + ssn number constraint pers_pkey primary key, + name varchar2(30), + address varchar2(100)); + +create table employees ( + ssn number constraint emp_pkey primary key, + name varchar2(30), + address varchar2(100), + empid number, + mgr varchar2(30), + salary number(7,2)); + +create table students ( + ssn number constraint stu_pkey primary key, + name varchar2(30), + address varchar2(100), + deptid number, + major varchar2(30)); + +insert into employees select * from employee_obj; +insert into students select * from student_obj; +insert into persons select * from person_obj; +commit; + +create or replace view person_v of person_t with object id(ssn) as + select ssn, name, address from person_obj; + +create or replace view student_v of student_t under person_v as + select Student_t(ssn, name, address, deptid, major) from students; + +select * from person_v p order by p.ssn; +select value(p) from person_v p order by p.ssn; +select * from ONLY (person_v) order by ssn; +select * from student_v order by ssn; + +Rem Polymorphic Views + +create view Persons_view of Person_t with object id(ssn) as + select Person_t(ssn, name, address) from persons + union all + select TREAT(Employee_t(ssn, name, address, empid, mgr, salary) as Person_t) + from employees; + +select value(p) from Persons_view p order by p.ssn; +select (TREAT(value(p) as Employee_t)).empid, ssn from Persons_view p + where value(p) IS OF (Employee_t) + order by ssn; + +Rem +Rem Substitutable columns/table +Rem + +drop table person_obj; +drop table employee_obj; +drop table employee_obj2; +drop table student_obj; +drop table all_person; +drop table dup_students; + +/* create and populate tables depend on types */ +create table person_obj of Person_t + (constraint pobj_pkey primary key(ssn)); +create table employee_obj of Employee_t + (constraint eobj_pkey primary key(ssn,empid), + mgr not null); +create table student_obj of Student_t + (unique (name, deptid)); + +create table all_person (PersRefCol REF Person_t, tabname varchar2(20)); + +create table dup_students (ssn number, p student_t); + +insert into person_obj values(12345, 'Joe','SF'); +insert into employee_obj values (2345, 'Max','LA',56, 'King',100.20); +insert into student_obj values (2345, 'Max','LA',300,'PLAY'); +insert into student_obj values + (PartTimeStudent_t(90, 'Kay', 'TX', 300, 'PLAY',3)); +insert into person_obj values + (Employee_t(9999, 'Joe','SF',null,null,null)); +insert into person_obj select value(p) from student_obj p; + +insert into all_person select REF(p), 'PERSON_OBJ' from person_obj p; +insert into all_person select REF(p), 'EMPLOYEE_OBJ' from employee_obj p; +insert into all_person select REF(p), 'STUDENT_OBJ' from student_obj p; + +insert into dup_students select ssn, value(p) from student_obj p; +update dup_students set p=PartTimeStudent_t(2345, 'Max','LA',300,'PLAY',0) + where p IS OF (ONLY student_t); + +commit; + +select value(p) from person_obj p order by p.ssn; +select value(p) from employee_obj p order by p.ssn; +select value(p) from student_obj p order by p.ssn; +select d.ssn from dup_students d where p is of (only student_t); +select d.ssn, d.p.ssn, Person_t.check_type(p) + from dup_students d order by d.ssn; + +select deref(p.persrefcol), tabname from all_person p + order by p.tabname, p.persrefcol.ssn; + +delete from person_obj p where value(p) IS OF (Employee_t, PartTimeStudent_t); +select value(p) from person_obj p order by p.ssn; +select deref(p.persrefcol), tabname from all_person p + where persrefcol is not dangling + order by p.tabname, p.persrefcol.ssn; + +rollback; + +select value(p) from person_obj p order by p.ssn; + +select deref(p.persrefcol), tabname from all_person p + order by p.tabname, p.persrefcol.ssn; + +Rem +Rem Overriding Methods +Rem + +create or replace type MyBaseType as object +( a1 number, + final member procedure foo (in1 varchar2), + static function foo1 (in1 number) return number, + static function foo3 (in1 number) return number, + member function foo2 (in1 varchar2) return date +) not instantiable not final; +/ +show error + +Rem can only redefines (override) NOT final method +create or replace type MySubType under MyBaseType +( a2 number, + a3 date, + overriding member procedure foo (in1 varchar2) +) not final; +/ +show error + +/* overloading final method ok */ +create or replace type MySubType under MyBaseType +( a2 number, + a3 date, + member procedure foo (in2 IN OUT varchar2) +) not final; +/ +show error + +create or replace type MySubType under MyBaseType +( a2 number, + a3 date, + static function foo1 (in2 char) return varchar2, + member function foo2 (in1 varchar2, in2 number) return varchar2, + overriding member function foo2 (in1 varchar2) return date +) not final; +/ +show error + +/* can't have not instantiable static method */ +create or replace type MySubType2 under MySubType +(not instantiable static function foo3 (in1 varchar2) return number) +not instantiable not final; +/ +show errors + +create or replace type MySubType2 under MySubType +(not instantiable member function foo3 (in1 varchar2) return number, + not instantiable member function foo5 (in1 varchar2) return number +) +not instantiable not final; +/ +show errors + +Rem +Rem Dynamic Method Dispatch +Rem + +create or replace type body MyBaseType as + final member procedure foo (in1 varchar2) as + begin + dbms_output.put_line('MyBaseType.foo:'||in1); + end; + + static function foo1 (in1 number) return number as + begin + return in1; + end; + + static function foo3 (in1 number) return number as + begin + return in1+3; + end; + + member function foo2 (in1 varchar2) return date as + begin + return to_date(in1,'MM/DD/YYYY'); + end; +end; +/ +show error + +create or replace type body MySubType as + static function foo1 (in2 char) return varchar2 as + begin + return ('MySubType.foo1:'||in2); + end; + + member function foo2 (in1 varchar2, in2 number) return varchar2 as + begin + return ('MySubType.foo2:'||in1||' '||in2); + end; + + overriding member function foo2 (in1 varchar2) return date as + begin + return to_date(in1,'DD/MM/YYYY'); + end; +end; +/ +show error + +/* cannot instantiate type */ +select MyBaseType(1) from dual; + +select treat(MySubType(1,2,to_date('10/20/2000','MM/DD/YYYY')) as MyBaseType) + mysubtype + from dual; +select treat(MySubType2(1,2,to_date('10/20/2000','MM/DD/YYYY')) as MySubType) + from dual; + +/* ok */ +select MySubType(1,2,to_date('10/20/2000','MM/DD/YYYY')) mysubtype from dual; +select MySubType2.foo1(3) from dual; + +set serveroutput on + +declare + v1 MyBaseType; + v2 MySubType; + v3 date; +begin + v3 := to_date('09/30/2000','MM/DD/YYYY'); + v1 := MySubType(1,2,v3); + v2 := MySubType(1,2,v3); + dbms_output.put_line('MySubType.foo1(1):'||MySubType.foo1(1)); + dbms_output.put_line('MySubType.foo1(''1''):'||MySubType.foo1('1')); + dbms_output.put_line('MySubType.foo3(2):'||MySubType.foo3(2)); + dbms_output.put_line('MyBaseType.foo3(3):'||MyBaseType.foo3(3)); + v2.foo('a'); + v1.foo('a'); +end; +/ + +declare + v1 MyBaseType; + v2 MySubType; + v3 date; +begin + v3 := to_date('09/30/2000','MM/DD/YYYY'); + v1 := MySubType(1,2,v3); + dbms_output.put_line('v1.foo2(''11/12/1999''):'||v1.foo2('11/12/1999')); +end; +/ + +Rem +Rem Rights Model +Rem + +create or replace type deftype1 as object +( a1 number, + a2 varchar2(10) +) not final; +/ +show error + +create or replace type subtype1 under deftype1 (a3 date); +/ +show error + +grant execute on deftype1 to inhdemo3; +grant under on deftype1 to inhdemo3; + +connect inhdemo3/inhdemo3 +Rem can't create subtype in different schema +create or replace type inhdemo3.subtype2 under inhdemo1.deftype1 +(a3 number); +/ +show error + +connect inhdemo1/inhdemo1 +Rem create root type with INVOKER RIGHT +create or replace type invtype1 authid current_user as object +( a1 number, + a2 varchar2(10) +) not final; +/ +show error + +grant execute on invtype1 to inhdemo3; +grant under on invtype1 to inhdemo3; + +connect inhdemo3/inhdemo3 +Rem ok to create subtype in different schema +create or replace type inhdemo3.subtype2 under inhdemo1.invtype1 +(a3 varchar2(10)); +/ +show error + +Rem cleanup + +connect system/manager +drop user inhdemo1 cascade; +drop user inhdemo3 cascade; + diff --git a/maporder.sql b/maporder.sql new file mode 100644 index 0000000..ad778b8 --- /dev/null +++ b/maporder.sql @@ -0,0 +1,308 @@ +rem +rem $Header: maporder.sql 12-aug-2004.06:03:09 rsriragh Exp $ +rem +rem maporder.sql +rem +rem Copyright (c) 1996, 2004, Oracle. All rights reserved. +rem +rem NAME +rem maporder.sql - Oracle 8 demo of map and order functions +rem +rem DESCRIPTION +rem This demo features Oracle8's object extensions, specifically map and +rem order functions of abstract data types +rem +rem NOTES +rem +rem MODIFIED (MM/DD/YY) +rem rsriragh 08/12/04 - fix order by diffs +rem ytsai 05/12/04 - order by +rem hyeh 08/10/99 - use sqlplus syntax +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem yaggarwa 08/06/98 - Add New syntax changes +rem cchau 08/18/97 - enable dictionary protection +rem mchien 05/29/97 - fix type syntax +rem mchien 07/17/96 - +rem mchien 07/16/96 - Created +rem + +REMARK >>>> Set System Variables For Current SQLPlus Session <<<< +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET PAGESIZE 24 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET DEFINE '^' + +set echo on +connect sys/knl_test7 as sysdba; +grant connect, resource to mmo2 identified by mmo2; + +connect mmo2/mmo2 + +REM create type with MAP function with parameters should error! +create type rational AS OBJECT ( + numerator INTEGER, + denominator INTEGER, + MAP MEMBER FUNCTION rat_to_real (x number) RETURN REAL, + PRAGMA RESTRICT_REFERENCES + (rat_to_real, RNDS, WNDS, RNPS, WNPS) +); +/ +show errors + +create or replace type rational AS OBJECT ( + numerator INTEGER, + denominator INTEGER, + MAP MEMBER FUNCTION rat_to_real RETURN REAL, + PRAGMA RESTRICT_REFERENCES + (rat_to_real, RNDS, WNDS, RNPS, WNPS) +); +/ +show errors + +REM create body with missing MAP specification in the body should error +create type body rational AS + MEMBER FUNCTION rat_to_real RETURN REAL IS + BEGIN + IF denominator = 0 THEN + RETURN 0; + ELSE + RETURN numerator/denominator; + END IF; + --Unqualified attributes refer to the "self" object. + END; +END; +/ +show errors + +REM create body with ORDER function instead of MAP as specified in type spec +REM should error +create or replace type body rational AS + ORDER MEMBER FUNCTION rat_to_real RETURN REAL IS + BEGIN + IF denominator = 0 THEN + RETURN 0; + ELSE + RETURN numerator/denominator; + END IF; + --Unqualified attributes refer to the "self" object. + END; +END; +/ +show errors +create or replace type body rational AS + MAP MEMBER FUNCTION rat_to_real RETURN REAL IS + BEGIN + IF denominator = 0 THEN + RETURN 0; + ELSE + RETURN numerator/denominator; + END IF; + --Unqualified attributes refer to the "self" object. + END; +END; +/ +show errors + + +create table tb1( + c1 varchar2(10), + c2 rational, + c3 rational, + c4 real); + +insert into tb1 values('row1', rational(9,10), rational(9,10), .9); +insert into tb1 values('row2', rational(7,8), rational(7,8), .8); +insert into tb1 values('row3', rational(5,6), rational(5,6), .7); +insert into tb1 values('row4', rational(3,4), rational(3,4), .6); +insert into tb1 values('row5', rational(1,2), rational(1,2), .5); +insert into tb1 values('row6', rational(0,1), rational(0,1), .4); +insert into tb1 values('bomb1', rational(1,0), rational(1,0), .3); +insert into tb1 values('bomb2', rational(1,null), rational(1,null), null); +insert into tb1 values('bomb3', rational(null,1), rational(null,1), null); +insert into tb1 + values('bomb4', rational(null,null), rational(null,null), null); +insert into tb1 values('bomb5', null, null, null); +select c1, sys_op_dump(c2), sys_op_dump(c3) from tb1 order by c2, c3, c1; +select c1, sys_op_dump(c2), sys_op_dump(c3) from tb1 order by c2, c3 desc, c1; +select c1, sys_op_dump(c3) from tb1 order by c3 desc, c1; +select c1, sys_op_dump(c2), sys_op_dump(c3) from tb1 order by c3, c2, c1; +select c1, sys_op_dump(c2), sys_op_dump(c3) from tb1 order by c3, c2 desc, c1; +select c1, sys_op_dump(c2) from tb1 order by c2 desc, c1; + +update tb1 p set c4 = p.c2.rat_to_real(); +select sys_op_dump(c2), c4 from tb1 order by 1, c4; +update tb1 p set c4 = p.c3.rat_to_real(); +select sys_op_dump(c3), c4 from tb1 order by c4, c1; + +select c1, sys_op_dump(c2-c3) from tb1 order by c2, c3, c1; +select c1 from tb1 where c2-c3 = 0 order by c1; + +select sys_op_dump(c2) from tb1 where c2 > c3 order by c2, c1; +select sys_op_dump(c2) from tb1 where c2 > rational(20,1) order by c1; +select sys_op_dump(c2) from tb1 where c2 = rational(9,10) order by c1; + +select sys_op_dump(c3) from tb1 where c3 > rational(1,20) order by c3, c1; +select sys_op_dump(c3) from tb1 where c3 = rational(9,10) order by c1; +select sys_op_dump(c3) from tb1 where c3 in (rational(9,10), rational(1,2)) + order by c3, c1; + +REM Now test order function for rational numbers +REM error case where order function does not have arguments! +create type rat AS OBJECT ( + numerator INTEGER, + denominator INTEGER, + ORDER MEMBER FUNCTION order_rat RETURN INTEGER, + PRAGMA RESTRICT_REFERENCES + (order_rat, RNDS, WNDS, RNPS, WNPS) +); +/ + +show errors + +create or replace type rat AS OBJECT ( + numerator INTEGER, + denominator INTEGER, + ORDER MEMBER FUNCTION order_rat (rat1 rat) RETURN INTEGER, + PRAGMA RESTRICT_REFERENCES + (order_rat, RNDS, WNDS, RNPS, WNPS) +); +/ +show errors + +create type body rat AS + ORDER MEMBER FUNCTION order_rat(rat1 rat) RETURN INTEGER IS + den1 INTEGER; + den2 INTEGER; + num1 INTEGER; + num2 INTEGER; + BEGIN + den1 := nvl(self.denominator, 0); + den2 := nvl(rat1.denominator, 0); + num1 := nvl(self.numerator, 0); + num2 := nvl(rat1.numerator, 0); + if den1 = den2 then + return num1 - num2; + elsif (den1=0) then + return 1; + elsif (den2=0) then + return -1; + else + return (num1*den2) - (den1*num2); + END IF; +END; +END; +/ +show errors + + +create table tb2( + c1 varchar2(10), + c2 rat, + c3 rat, + c4 real); + +insert into tb2 values('row1', rat(9,10), rat(9,10), .9); +insert into tb2 values('row2', rat(7,8), rat(7,8), .8); +insert into tb2 values('row3', rat(5,6), rat(5,6), .7); +insert into tb2 values('row4', rat(3,4), rat(3,4), .6); +insert into tb2 values('row5', rat(1,2), rat(1,2), .5); +insert into tb2 values('row6', rat(0,1), rat(0,1), .4); +insert into tb2 values('bomb1', rat(1,0), rat(1,0), .3); +insert into tb2 values('bomb2', rat(1,null), rat(1,null), null); +insert into tb2 values('bomb3', rat(null,1), rat(null,1), null); +insert into tb2 values('bomb4', rat(null,null), rat(null,null), null); +insert into tb2 values('bomb5', null, null, null); +select c1, sys_op_dump(c2), sys_op_dump(c3) from tb2 order by c2, c3, c1; +select c1, sys_op_dump(c2), sys_op_dump(c3) from tb2 order by c2, c3 desc, c1; +select c1, sys_op_dump(c3) from tb1 order by c3 desc, c1; +select c1, sys_op_dump(c2), sys_op_dump(c3) from tb2 order by c3, c2, c1; +select c1, sys_op_dump(c2), sys_op_dump(c3) from tb2 order by c3, c2 desc, c1; +select c1, sys_op_dump(c2) from tb1 order by c2 desc, c1; +update tb2 p set c4 = p.c2.order_rat(rat(3,10)); +select sys_op_dump(c2), c4 from tb2 order by c4, c1; +update tb2 p set c4 = p.c2.order_rat(c3); +select sys_op_dump(c2), sys_op_dump(c3), c4 from tb2 order by c4, c1; +select sys_op_dump(c2) from tb1 minus select sys_op_dump(c2) from tb2; +select sys_op_dump(c2) from tb1 minus select sys_op_dump(c3) from tb2; +select sys_op_dump(c3) from tb1 minus select sys_op_dump(c3) from tb2; + +select sys_op_dump(c2) from tb1 intersect select sys_op_dump(c2) from tb2; +select sys_op_dump(c2) from tb1 intersect select sys_op_dump(c3) from tb2; +select sys_op_dump(c3) from tb1 intersect select sys_op_dump(c3) from tb2; + +select sys_op_dump(c3) from tb2 where c2 in (select c2 from tb2) order by c3; +select sys_op_dump(c3) from tb2 + where c3 between rat(1,100) and rat(99,100) order by c3; +select sys_op_dump(c2) from tb2 + where c2 = ANY (SELECT c2 from tb2 where c3 = rat(9,10)); +select sys_op_dump(c3) from tb2 where c2 >= ALL (rat(1,10), rat(9,10)); +select c1 from tb2 where c2-c3 = 0 order by c1; + +REM #### test a recursive method +REM method is the factorial function + +REM note: pragma for map method is not required! + +create or replace type tfact AS OBJECT (c1 int, +map member function mfact return int, +member function fact(a int) return int , +PRAGMA RESTRICT_REFERENCES(fact,WNDS,RNDS,WNPS,RNPS) ); +/ +show errors + +create or replace type body tfact AS + member function fact(a int) return int is + begin + if a is null then return 0; + elsif a = 0 then return 1; + else return a*fact(a-1); + end if; + end; + map member function mfact return int is + begin + return c1; + end; +END; +/ +show errors + +CREATE TABLE tbfact (a tfact, b int, constraint aci check (a.c1 >= 0), + constraint bci check (b >= 0)); +INSERT INTO tbfact values(tfact(3), 4); +INSERT INTO tbfact values(tfact(-1), 1); +INSERT INTO tbfact values(tfact(1), -1); +INSERT INTO tbfact values(tfact(0), 1); +INSERT INTO tbfact values(tfact(null), 0); +INSERT INTO tbfact values (null,0); +INSERT INTO tbfact values(tfact(2), 3); +SELECT p.a.c1 a, p.a.fact(p.a.c1) afact, b, p.a.fact(b) bfact FROM tbfact p +WHERE a is not null ORDER by a; +SELECT p.a.c1 a, p.a.fact(p.a.c1) afact, b, p.a.fact(b) bfact FROM tbfact p +WHERE a is not null ORDER by a desc; + +drop type body rat; + +create or replace type body rat as + ORDER MEMBER FUNCTION order_rat(rat1 rat) RETURN INTEGER IS + BEGIN + if self.denominator = rat1.denominator then + return self.numerator - rat1.numerator; + else + return (self.numerator * rat1.denominator) - + (self.denominator * rat1.numerator); + END IF; + END; +END; +/ + +select c1, sys_op_dump(c2), sys_op_dump(c3) from tb2 order by c2, c3; +select c1, sys_op_dump(c2), sys_op_dump(c3) from tb2 order by c2, c3 desc; +select c1, sys_op_dump(c2), sys_op_dump(c3) from tb2 order by c3, c2; + +connect sys/knl_test7 as sysdba +drop user mmo2 cascade; + + diff --git a/mddemo.sql b/mddemo.sql new file mode 100644 index 0000000..94a4f57 --- /dev/null +++ b/mddemo.sql @@ -0,0 +1,271 @@ +rem +rem $Header: mddemo.sql 01-nov-00.16:13:33 gclaborn Exp $ +rem +rem Copyright (c) 1996, 1999, 2000 Oracle Corporation. All rights reserved. +rem +rem NAME +rem mddemo.sql - Oracle 9i demo of the Metadata API +rem +rem DESCRIPTON +rem This demo shows how to programmatically extract database object +rem definitions using the DBMS_METADATA package. +rem +rem MODIFIED (MM/DD/YY) +rem gclaborn 11/01/00 - Created + +-- This script demonstrates how to use the Metadata API. It first +-- establishes a schema (MDDEMO) and some payroll users, then creates three +-- payroll-like tables within it along with associated indexes, triggers +-- and grants. + +-- It then creates a package PAYROLL_DEMO that shows common usage of the +-- Metadata API. The procedure GET_PAYROLL_TABLES retrieves the DDL for the +-- two tables in this schema that start with 'PAYROLL' then for each one, +-- retrieves the DDL for its associate dependent objects; indexes, grants +-- and triggers. All the DDL is written to a table named "MDDEMO"."DDL". + +-- First, Install the demo. cd to rdbms/demo: +-- > sqlplus system/manager +-- SQL> @mddemo + +-- Then, run it. +-- > sqlplus mddemo/mddemo +-- SQL> set long 40000 +-- SQL> set pages 0 +-- SQL> call payroll_demo.get_payroll_tables(); +-- SQL> select ddl from DDL order by seqno; + +Rem Set up schema for demo pkg. PAYROLL_DEMO. + +connect system/manager +drop user mddemo cascade; +drop user mddemo_clerk cascade; +drop user mddemo_mgr cascade; + +create user mddemo identified by mddemo; +GRANT resource, connect, create session + , create table + , create procedure + , create sequence + , create trigger + , create view + , create synonym + , alter session +TO mddemo; + +create user mddemo_clerk identified by clerk; +create user mddemo_mgr identified by mgr; + +connect mddemo/mddemo + +Rem Create some payroll-like tables... + +create table payroll_emps +( lastname varchar2(60) not null, + firstname varchar2(20) not null, + mi varchar2(2), + suffix varchar2(10), + DOB date not null, + badge_no number(6) primary key, + exempt varchar(1) not null, + salary number (9,2), + hourly_rate number (7,2) +) +/ +create table payroll_timecards +( badge_no number(6) references payroll_emps (badge_no), + week number(2), + job_id number(5), + hours_worked number(4,2) +) +/ +-- This is a dummy table used only to show that tables NOT starting with +-- 'PAYROLL' are NOT retrieved by payroll_demo.get_payroll_tables + +create table audit_trail +( action_time DATE, + lastname VARCHAR2(60), + action LONG +) +/ + +Rem Then, create some grants... + +grant update (salary,hourly_rate) on payroll_emps to mddemo_clerk; +grant ALL on payroll_emps to mddemo_mgr with grant option; + +grant insert,update on payroll_timecards to mddemo_clerk; +grant ALL on payroll_timecards to mddemo_mgr with grant option; + +Rem Then, create some indexes... + +create index i_payroll_emps_name on payroll_emps(lastname); +create index i_payroll_emps_dob on payroll_emps(DOB); + +create index i_payroll_timecards_badge on payroll_timecards(badge_no); + +Rem Then, create some triggers (and required procedure)... + +create or replace procedure check_sal( salary in number) as +begin + return; -- Fairly loose security here... +end; +/ + +create or replace trigger salary_trigger before insert or update of salary on payroll_emps +for each row when (new.salary > 150000) +call check_sal(:new.salary) +/ + +create or replace trigger hourly_trigger before update of hourly_rate on payroll_emps +for each row +begin :new.hourly_rate:=:old.hourly_rate;end; +/ + +-- +-- Set up a table to hold the generated DDL +-- +CREATE TABLE ddl (ddl CLOB, seqno NUMBER); + +Rem Finally, create the PAYROLL_DEMO package itself. + +CREATE OR REPLACE PACKAGE payroll_demo AS + + PROCEDURE get_payroll_tables; +END; +/ +CREATE OR REPLACE PACKAGE BODY payroll_demo AS + +-- GET_PAYROLL_TABLES: Fetch DDL for payroll tables and their dependent objects + +PROCEDURE get_payroll_tables IS + +tableOpenHandle NUMBER; +depObjOpenHandle NUMBER; +tableTransHandle NUMBER; +indexTransHandle NUMBER; +schemaName VARCHAR2(30); +tableName VARCHAR2(30); +tableDDLs sys.ku$_ddls; +tableDDL sys.ku$_ddl; +parsedItems sys.ku$_parsed_items; +depObjDDL CLOB; +seqNo NUMBER := 1; + +TYPE obj_array_t IS VARRAY(3) OF VARCHAR2(30); + +-- Load this array with the dependent object classes to be retrieved... +obj_array obj_array_t := obj_array_t('OBJECT_GRANT', 'INDEX', 'TRIGGER'); + +BEGIN + +-- Open a handle for tables in the current schema. + tableOpenHandle := dbms_metadata.open('TABLE'); + +-- Tell mdAPI to retrieve one table at a time. This call is not actually +-- necessary since 1 is the default... just showing the call. + dbms_metadata.set_count(tableOpenHandle, 1); + +-- Retrieve tables whose name starts with 'PAYROLL'. When the filter is +-- 'NAME_EXPR', the filter value string must include the SQL operator. This +-- gives the caller flexibility to use LIKE, IN, NOT IN, subqueries, etc. + dbms_metadata.set_filter(tableOpenHandle, 'NAME_EXPR', 'LIKE ''PAYROLL%'''); + +-- There are no index-organized tables in the MDDEMO schema, so tell the API. +-- This eliminates one of the views it'll need to look in. + dbms_metadata.set_filter(tableOpenHandle, 'IOT', FALSE); + +-- Tell the mdAPI to parse out each table's schema and name separately so we +-- can use them to set up the calls to retrieve its dependent objects. + dbms_metadata.set_parse_item(tableOpenHandle, 'SCHEMA'); + dbms_metadata.set_parse_item(tableOpenHandle, 'NAME'); + +-- Add the DDL transform so we get SQL creation DDL + tableTransHandle := dbms_metadata.add_transform(tableOpenHandle, 'DDL'); + +-- Tell the XSL stylesheet we don't want physical storage information (storage, +-- tablespace, etc), and that we want a SQL terminator on each DDL. Notice that +-- these calls use the transform handle, not the open handle. + dbms_metadata.set_transform_param(tableTransHandle, + 'SEGMENT_ATTRIBUTES', FALSE); + dbms_metadata.set_transform_param(tableTransHandle, + 'SQLTERMINATOR', TRUE); + +-- Ready to start fetching tables. We use the FETCH_DDL interface (rather than +-- FETCH_XML or FETCH_CLOB). This interface returns a SYS.KU$_DDLS; a table of +-- SYS.KU$_DDL objects. This is a table because some object types return +-- multiple DDL statements (like types / pkgs which have create header and +-- body statements). Each KU$_DDL has a CLOB containing the 'CREATE foo' +-- statement plus a nested table of the parse items specified. In our case, +-- we asked for two parse items; Schema and Name. (NOTE: See admin/dbmsmeta.sql +-- for a more detailed description of these types) + + LOOP + tableDDLs := dbms_metadata.fetch_ddl(tableOpenHandle); + EXIT WHEN tableDDLs IS NULL; -- Get out when no more payroll tables + +-- In our case, we know there is only one row in tableDDLs (a KU$_DDLS tbl obj) +-- for the current table. Sometimes tables have multiple DDL statements; +-- eg, if constraints are applied as ALTER TABLE statements, but we didn't ask +-- for that option. So, rather than writing code to loop through tableDDLs, +-- we'll just work with the 1st row. +-- +-- First, write the CREATE TABLE text to our output table then retrieve the +-- parsed schema and table names. + tableDDL := tableDDLs(1); + INSERT INTO ddl VALUES(tableDDL.ddltext, seqNo); + seqNo := seqNo + 1; + parsedItems := tableDDL.parsedItems; + +-- Must check the name of the returned parse items as ordering isn't guaranteed + FOR i IN 1..2 LOOP + IF parsedItems(i).item = 'SCHEMA' + THEN + schemaName := parsedItems(i).value; + ELSE + tableName := parsedItems(i).value; + END IF; + END LOOP; + +-- Now, we want to retrieve all the dependent objects defined on the current +-- table: indexes, triggers and grants. Since all 'dependent' object types +-- have BASE_OBJECT_NAME and BASE_OBJECT_SCHEMA in common as filter criteria, +-- we'll set up a loop to get all objects of the 3 types, just changing the +-- OPEN context in each pass through the loop. Transform parameters are +-- different for each object type, so we'll only use one that's common to all; +-- SQLTERMINATOR. + + FOR i IN 1..3 LOOP + depObjOpenHandle := dbms_metadata.open(obj_array(i)); + dbms_metadata.set_filter(depObjOpenHandle,'BASE_OBJECT_SCHEMA', + schemaName); + dbms_metadata.set_filter(depObjOpenHandle,'BASE_OBJECT_NAME',tableName); + +-- Add the DDL transform and say we want a SQL terminator + indexTransHandle := dbms_metadata.add_transform(depObjOpenHandle, 'DDL'); + dbms_metadata.set_transform_param(indexTransHandle, + 'SQLTERMINATOR', TRUE); + +-- Retrieve dependent object DDLs as CLOBs and write them to table DDL. + LOOP + depObjDDL := dbms_metadata.fetch_clob(depObjOpenHandle); + EXIT WHEN depObjDDL IS NULL; + INSERT INTO ddl VALUES(depObjDDL, seqNo); + seqNo := seqNo + 1; + END LOOP; + +-- Free resources allocated for current dependent object stream. + dbms_metadata.close(depObjOpenHandle); + + END LOOP; -- End of fetch dependent objects loop + + END LOOP; -- End of fetch table loop + +-- Free resources allocated for table stream and close output file. + dbms_metadata.close(tableOpenHandle); + RETURN; + +END; -- of procedure get_payroll_tables + +END payroll_demo; +/ diff --git a/mddemo2.sql b/mddemo2.sql new file mode 100644 index 0000000..00026a4 --- /dev/null +++ b/mddemo2.sql @@ -0,0 +1,470 @@ +Rem +Rem $Header: mddemo2.sql 16-apr-2001.16:44:33 nmeng Exp $ +Rem +Rem mddemo2.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem mddemo2.sql - MetaData API Demo Part II +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem Oracle 9i demo of Metadata API Part II +Rem This script continues to demonstrate how to use the Metadata API. +Rem It first establishes a schema (mddemo) with associated grants. +Rem It then creates various objects for the demo purpose, including +Rem tables, indexes, fuctions and procedures. +Rem +Rem This demo shows the usage of Metadata API's browsing and +Rem programmatic APIs. Instead of writing the retrieved DDLs +Rem to a table, this script creates a procedure PRINT_DDL to +Rem display them. +Rem +Rem To run the demo, first cd to rdbms/demo directory. Then, +Rem % sqlplus /nolog +Rem SQL> @mddemo2 +Rem +Rem MODIFIED (MM/DD/YY) +Rem nmeng 04/16/01 - Merged nmeng_metadata_api_demo_010412 +Rem nmeng 04/13/01 - Created +Rem + +REM +REM initialize environment +REMARK >>>> Set System Variables For Current SQLPlus Session <<<< +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET PAGESIZE 0 +SET LINESIZE 200 +SET TRIMSPOOL ON +SET TAB OFF +SET DEFINE '^' + +set echo on +connect system/manager +drop user mddemo cascade; + +REM create new user: mddemo +grant connect, resource, select_catalog_role to mddemo identified by mddemo; + +REM grant select on scott.emp to mddemo +connect scott/tiger +grant select on emp to mddemo; + +REM start session as new user +connect mddemo/mddemo +set long 200000 +set serveroutput on size 1000000 + +REM create objects for demo +REM TABLE +CREATE TABLE EMP AS SELECT * FROM SCOTT.EMP; + +CREATE TABLE DEPT ( + DEPTNO NUMBER CONSTRAINT dept_pk PRIMARY KEY, + DNAME VARCHAR2(20), + LOCATION VARCHAR2(80) +); + +CREATE TABLE NEWEMP( + ENO NUMBER, + ENAME VARCHAR2(40), + DEPTNO NUMBER CONSTRAINT emp_fk REFERENCES DEPT +); + + +REM COMPOSITE INDEX +CREATE UNIQUE INDEX dept_uk1 ON DEPT(DNAME,LOCATION) +pctfree 40 +initrans 10 +maxtrans 20 +logging +compute statistics +compress 1 +nosort +STORAGE(INITIAL 8K NEXT 12K MINEXTENTS 1 MAXEXTENTS 120 PCTINCREASE 40 +FREELISTS 1 FREELIST GROUPS 4 BUFFER_POOL DEFAULT) TABLESPACE "SYSTEM" +parallel ( degree 5 instances 2); + +REM BITMAP INDEX +CREATE BITMAP INDEX dept_bitmap ON DEPT(LOCATION, DNAME) PARALLEL; + +REM FUNCTION +CREATE OR REPLACE FUNCTION f1( + arg1 NUMBER, + arg2 IN INTEGER, + arg3 OUT NOCOPY FLOAT, + arg4 IN OUT VARCHAR2 +) RETURN BLOB DETERMINISTIC PARALLEL_ENABLE +AUTHID CURRENT_USER IS + BEGIN + /* function body + . + . + . + */ + null; + END; +/ + + +REM PACKAGE +CREATE OR REPLACE PACKAGE MyPkg IS + FUNCTION sqr(x IN NUMBER) RETURN NUMBER; + PROCEDURE hello(name IN VARCHAR2); +END; +/ + +CREATE OR REPLACE PACKAGE BODY MyPkg AS + + FUNCTION sqr(x IN NUMBER) RETURN NUMBER IS + BEGIN + return x*x; + END; + + PROCEDURE hello(name IN VARCHAR2) IS + BEGIN + dbms_output.put_line('Hello ' || name); + END; +END; +/ + +CREATE OR REPLACE PACKAGE emp_mgmt AS + FUNCTION hire(ename VARCHAR2, + job VARCHAR2, + mgr NUMBER, + sal NUMBER, + comm NUMBER, + deptno NUMBER) + RETURN NUMBER; + FUNCTION create_dept(dname VARCHAR2,loc VARCHAR2) + RETURN NUMBER; + PROCEDURE remove_emp(empno NUMBER); + PROCEDURE remove_dept(deptno NUMBER); + PROCEDURE increase_sal(empno NUMBER, sal_incr NUMBER); + PROCEDURE increase_comm(empno NUMBER, comm_incr NUMBER); + no_comm EXCEPTION; + no_sal EXCEPTION; +END emp_mgmt; +/ + +CREATE OR REPLACE PACKAGE BODY emp_mgmt AS + tot_emps NUMBER; + tot_depts NUMBER; + + FUNCTION hire( + ename VARCHAR2, + job VARCHAR2, + mgr NUMBER, + sal NUMBER, + comm NUMBER, + deptno NUMBER) + RETURN NUMBER IS + new_empno NUMBER(4); + BEGIN + new_empno:=1; + RETURN(new_empno); + END; + + FUNCTION create_dept(dname VARCHAR2, loc VARCHAR2) + RETURN NUMBER IS + new_deptno NUMBER(4); + BEGIN + return 101; + END; + + PROCEDURE remove_emp(empno NUMBER) IS + BEGIN + null; + END; + + PROCEDURE remove_dept(deptno NUMBER) IS + BEGIN + null; + END; + + PROCEDURE increase_sal(empno NUMBER, sal_incr NUMBER) IS + curr_sal NUMBER(7,2); + BEGIN + null; + END; + + PROCEDURE increase_comm(empno NUMBER, comm_incr NUMBER) IS + curr_comm NUMBER(7,2); + BEGIN + null; + END; + +END emp_mgmt; +/ + + + + +REM *********** +REM * DEMOS * +REM *********** + +REM CREATE procedure PRINT_DDL to display fetched DDLs +CREATE OR REPLACE PROCEDURE Print_DDL(DDLString IN CLOB) +IS + str varchar2(32767); + tmpstr varchar2(32767); + len integer; + idx integer := 1; + nlidx integer; + newline character := chr(10); + BEGIN + str := substr(DDLString,1,31*1024); + + len := length(str); + loop + exit when idx >len; + nlidx := instr(str,newline,idx); + if (nlidx = 0) then + nlidx := len+1; + end if; + tmpstr := substr(str,idx,nlidx-idx); + + if(length(tmpstr) > 250) then + --print line or 250 bytes per line + tmpstr := '| '||tmpstr; + loop + exit when tmpstr is null; + dbms_output.put_line(substr(tmpstr,1,250)); + tmpstr := substr(tmpstr,251); + end loop; + else + dbms_output.put_line('| '||tmpstr); + end if; + + idx := nlidx+1; + end loop; + END Print_DDL; +/ + +REM create procedure PRINT_XML to print fetched XML +CREATE OR REPLACE PROCEDURE PRINT_XML (XMLString IN CLOB) IS +BEGIN + PRINT_DDL(XMLString); +END PRINT_XML; +/ + +REM BROWSING API: GET_XML, GET_DDL + +REM EXAMPLE 1 +REM Fetch the XML representation of EMP ( object in same schema) +SELECT DBMS_METADATA.GET_XML('TABLE','EMP') FROM DUAL; + +REM EXAMPLE 2 +REM Fetch the DDL of SCOTT.EMP (object in different schema) +-- first, get the complete DDL by not setting session transform parameter +SELECT DBMS_METADATA.GET_DDL('TABLE','EMP','SCOTT') FROM DUAL; + +-- then, get the ddl without the segment attributes. +-- we need to call SET_TRANSFORM_PARAM using SESSION_TRANSFORM to +-- set transform parameters for the whole session. +EXEC DBMS_METADATA.SET_TRANSFORM_PARAM( - + dbms_metadata.SESSION_TRANSFORM, - + 'SEGMENT_ATTRIBUTES', false); +SELECT DBMS_METADATA.GET_DDL('TABLE','EMP','SCOTT') FROM DUAL; +-- we now reset the transform parameters to default +EXEC DBMS_METADATA.SET_TRANSFORM_PARAM( - + dbms_metadata.SESSION_TRANSFORM, - + 'DEFAULT', true); + + +REM PROGRAMMATIC API + +REM EXAMPLE 3 +REM Retrieve all tables in the current schema as XML documents +DECLARE + handle NUMBER; + MyTable SYS.XMLType; + XMLString CLOB; +BEGIN + handle := DBMS_METADATA.OPEN('TABLE'); + LOOP + MyTable := DBMS_METADATA.FETCH_XML(handle); + EXIT WHEN MyTable IS NULL; + -- get the CLOB value of the XML document and print it + XMLString := MyTable.getClobVal; + PRINT_XML(XMLString); + END LOOP; + DBMS_METADATA.CLOSE(handle); +END; +/ + +REM You can also fetch the XML as CLOB directly +REM by using DBMS_METADATA.FETCH_CLOB +DECLARE + handle NUMBER; + XMLString CLOB; +BEGIN + handle := DBMS_METADATA.OPEN('TABLE'); + DBMS_METADATA.SET_FILTER(handle, 'NAME', 'NEWEMP'); + LOOP + XMLString := dbms_metadata.fetch_clob(handle); + EXIT when XmlString is NULL; + PRINT_XML(XMLString); + END LOOP; + DBMS_METADATA.CLOSE(handle); +END; +/ + + + +REM EXAMPLE 4 +REM Retrieve a package and package body as DDL +DECLARE + handle NUMBER; + tHandle NUMBER; + PkgTable SYS.KU$_DDLS; + PkgSpec CLOB; + PkgBody CLOB; +BEGIN + handle := DBMS_METADATA.OPEN('PACKAGE'); + DBMS_METADATA.SET_FILTER(handle,'NAME','MYPKG'); + -- setting SCHEMA filter to MDDEMO is Optional because + -- it is the current Schema + DBMS_METADATA.SET_FILTER(handle,'SCHEMA','MDDEMO'); + tHandle := DBMS_METADATA.ADD_TRANSFORM(handle, 'DDL'); + PkgTable := DBMS_METADATA.FETCH_DDL(Handle); + if (PkgTable is NOT NULL) then + -- Extract DDL text from the PkgTable + -- A package has two parts: specification and body + -- which are stored as two rows in the ddl table PkgTable + -- To retrieve the complete DDL for a package, + -- we need to get both PkgSpec and PkgBody ddls. + PkgSpec := PkgTable(1).ddlText; + PkgBody := PkgTable(2).ddlText; + Print_DDL(PkgSpec); + Print_DDL(PkgBody); + else + dbms_output.put_line('OBJECT NOT FOUND IN SCHEMA'); + end if; + DBMS_METADATA.CLOSE(handle); +END; +/ + +REM EXAMPLE 5 +REM Using dbms_metadata.set_filter to set filters +declare + h1 number; + th1 number; + ddls sys.ku$_ddls; + ddlstring clob; +begin + h1 := dbms_metadata.open('PACKAGE'); + -- Besides providing exact name and schema, we can also using + -- expressions: NAME_EXPR, and SCHEMA_EXPR for more flexiblity + dbms_metadata.set_filter(h1,'NAME_EXPR','IN (''EMP_MGMT'',''MYPKG'')'); + dbms_metadata.set_filter(h1,'SCHEMA_EXPR', 'like ''MDDEMO'' '); + + th1 := dbms_metadata.add_transform(h1, 'DDL'); + -- using default tranformation parameters + dbms_metadata.set_transform_param(th1,'DEFAULT', true); + ddls := dbms_metadata.fetch_ddl(h1); + + -- get all the fetched ddls by using a for loop + for i in ddls.FIRST..ddls.LAST loop + ddlstring :=ddls(i).ddlText; + Print_DDL(ddlstring); + end loop; + + dbms_metadata.close(h1); +end; +/ + +REM EXAMPLE 6 +REM Retrieving DDL for a function is the same as other objects. +REM This example shows how to use dbms_metadata.set_transform_param +declare + h1 number; + th1 number; + functionDDLs sys.ku$_ddls; + ddlstring clob; +begin + h1 := dbms_metadata.open('FUNCTION'); + + dbms_metadata.set_filter(h1,'NAME', 'F1'); + + th1 := dbms_metadata.add_transform(h1, 'DDL'); + + dbms_metadata.set_transform_param(th1,'PRETTY', true); + dbms_metadata.set_transform_param(th1,'SQLTERMINATOR', true); + functionDDLs := dbms_metadata.fetch_ddl(h1); + ddlstring := functionDDLs(1).ddlText; + Print_DDL(ddlstring); + dbms_metadata.close(h1); +end; +/ + +REM EXAMPLE 7 +REM A more complicated example +REM Example: Retrieve all tables in the current schema. For each table +REM return its indexes. This example shows the use of SET_PARSE_ITEM +REM to enable output parsing. + +DECLARE + handle1 NUMBER; + handle2 NUMBER; + tHandle1 NUMBER; + tHandle2 NUMBER; + SchemaName VARCHAR2(30); + TableName VARCHAR2(30); + TableDDLs sys.ku$_ddls; + TableDDL sys.ku$_ddl; + TableDDLtext CLOB; + parsedItems sys.ku$_parsed_items; + IndexDDLtext CLOB; +BEGIN + handle1 := dbms_metadata.open('TABLE'); + tHandle1 := dbms_metadata.add_transform(handle1,'DDL'); + dbms_metadata.set_parse_item(handle1,'NAME'); + dbms_metadata.set_parse_item(handle1,'SCHEMA'); + LOOP + TableDDLs := dbms_metadata.fetch_ddl(handle1); + EXIT WHEN TableDDLs IS NULL; + TableDDL := TableDDLs(1); + TableDDLtext := TableDDL.ddltext; + parsedItems := TableDDL.parsedItems; + + FOR i IN parsedItems.FIRST..parsedItems.LAST LOOP + IF parsedItems(i).item = 'SCHEMA' THEN + SchemaName := parsedItems(i).value; + ELSE + TableName := parsedItems(i).value; + END IF; + END LOOP; + -- open a second stream to fetch the table's indexes. + -- use the parsed schema and table names to construct + -- the filters + handle2 := dbms_metadata.open('INDEX'); + dbms_metadata.set_filter(handle2, 'BASE_OBJECT_SCHEMA', + SchemaName); + dbms_metadata.set_filter(handle2, 'BASE_OBJECT_NAME', + TableName); + tHandle2 := dbms_metadata.add_transform(handle2, 'DDL'); + -- do not fetch segment attributes + dbms_metadata.set_transform_param(tHandle2,'SEGMENT_ATTRIBUTES',false); + LOOP + IndexDDLtext := dbms_metadata.fetch_clob(handle2); + EXIT WHEN IndexDDLtext IS NULL; + -- print fetched DDLs + Print_DDL(IndexDDLtext); + END LOOP; + dbms_metadata.close(handle2); + END LOOP; + dbms_metadata.close(handle1); +END; +/ + + +REM cleanup +connect system/manager +drop user mddemo cascade; diff --git a/mdemo1.cpp b/mdemo1.cpp new file mode 100644 index 0000000..4d4a3ad --- /dev/null +++ b/mdemo1.cpp @@ -0,0 +1,98 @@ +#include "mdemo1.h" +#include "mdemo1m.h" + +// global Oracle variables + +Environment *env; +Connection *conn; +Statement *stmt; +ResultSet *rs; + +void initialize() { + + // Create environment + env = Environment::createEnvironment(Environment::OBJECT); + + // Call the OTT generated function to register the mappings + mdemo1m(env); + + // Create Connection + conn = env->createConnection( USERNAME, PASSWORD ); + + // Create a statement + stmt = conn->createStatement(); +} + +void terminateit() { + + //Terminate statement + conn->terminateStatement(stmt); + + //Terminate connection + env->terminateConnection(conn); + + //Terminate environment + Environment::terminateEnvironment(env); +} + +/* Do the work. + The environment is set up. + A single new entry is created in the Address table. + Then it is committed. +*/ +void dowrite() { + + // Create an Address + ADDRESS_O *addr1 = new(conn, "ADDR_TAB") ADDRESS_O("GE", "1211"); + Ref addr1_ref = (Ref) addr1->getRef(); + + // Create joe black + FullName *name1= new FullName("Joe", "Black"); + + Person *person1 = + new(conn, "PERSON_TAB") Person(1,name1,addr1_ref); + Ref person1_ref = (Ref) person1->getRef(); + + // Display, using reference + cout<<"-------------------"<displayInfo(); + cout<<"-------------------"<commit(); + +} + +void doread() +{ + // Retrieve joe black + string sel_joe = "SELECT REF(p) from person_tab p where \"id\" = 1"; + + rs =stmt->executeQuery (sel_joe); + + // Get reference + rs->next(); + Ref joe_ref = (Ref) rs->getRef(1); + + // Display, using reference + cout<<"-------------------"<displayInfo(); + cout<<"-------------------"<closeResultSet(rs); + +} + +int main() { + + try { + initialize(); + dowrite(); + doread(); + terminateit(); + } + catch (SQLException &e) { + cout << "SQL exception :" << e.getMessage() << endl; + } + + return 0; +} diff --git a/mdemo1.h b/mdemo1.h new file mode 100644 index 0000000..ba7b80f --- /dev/null +++ b/mdemo1.h @@ -0,0 +1,201 @@ +#ifndef MDEMO1_ORACLE +# define MDEMO1_ORACLE + +#ifndef OTT_USERCODE_START +# define OTT_USERCODE_START +#endif + +#ifndef OTT_USERCODE_END +# define OTT_USERCODE_END +#endif + +#ifndef OCCI_ORACLE +# include +#endif + +OTT_USERCODE_START +#include "mymdemo1.h" +OTT_USERCODE_END + + +/************************************************************/ +// generated declarations for the FULL_NAME_O object type. +/************************************************************/ + +class FULL_NAME_O : public oracle::occi::PObject { + +protected: + + OCCI_STD_NAMESPACE::string first_name; + OCCI_STD_NAMESPACE::string last_name; + +public: + + void *operator new(size_t size); + + void *operator new(size_t size, const oracle::occi::Connection * sess, + const OCCI_STD_NAMESPACE::string& table); + + void *operator new(size_t, void *ctxOCCI_); + + void *operator new(size_t size, const oracle::occi::Connection *sess, + const OCCI_STD_NAMESPACE::string &tableName, + const OCCI_STD_NAMESPACE::string &typeName, + const OCCI_STD_NAMESPACE::string &tableSchema, + const OCCI_STD_NAMESPACE::string &typeSchema); + + OCCI_STD_NAMESPACE::string getSQLTypeName() const; + + void getSQLTypeName(oracle::occi::Environment *env, void **schemaName, + unsigned int &schemaNameLen, void **typeName, + unsigned int &typeNameLen) const; + + FULL_NAME_O(); + + FULL_NAME_O(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { }; + + static void *readSQL(void *ctxOCCI_); + + virtual void readSQL(oracle::occi::AnyData& streamOCCI_); + + static void writeSQL(void *objOCCI_, void *ctxOCCI_); + + virtual void writeSQL(oracle::occi::AnyData& streamOCCI_); + + ~FULL_NAME_O(); + +}; + +OTT_USERCODE_START + +class FullName : public FULL_NAME_O { +public: + FullName(void *ctxOCCI_); + FullName(string FirstName, string LastName); + void displayInfo(); + const string getFirstName() const { return first_name;} + ~FullName(); +} ; + +OTT_USERCODE_END + +/************************************************************/ +// generated declarations for the ADDRESS_O object type. +/************************************************************/ + +class ADDRESS_O : public oracle::occi::PObject { + +protected: + + OCCI_STD_NAMESPACE::string state; + OCCI_STD_NAMESPACE::string zip; + +public: + + void *operator new(size_t size); + + void *operator new(size_t size, const oracle::occi::Connection * sess, + const OCCI_STD_NAMESPACE::string& table); + + void *operator new(size_t, void *ctxOCCI_); + + void *operator new(size_t size, const oracle::occi::Connection *sess, + const OCCI_STD_NAMESPACE::string &tableName, + const OCCI_STD_NAMESPACE::string &typeName, + const OCCI_STD_NAMESPACE::string &tableSchema, + const OCCI_STD_NAMESPACE::string &typeSchema); + + OCCI_STD_NAMESPACE::string getSQLTypeName() const; + + void getSQLTypeName(oracle::occi::Environment *env, void **schemaName, + unsigned int &schemaNameLen, void **typeName, + unsigned int &typeNameLen) const; + + ADDRESS_O(); + + ADDRESS_O(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { }; + + static void *readSQL(void *ctxOCCI_); + + virtual void readSQL(oracle::occi::AnyData& streamOCCI_); + + static void writeSQL(void *objOCCI_, void *ctxOCCI_); + + virtual void writeSQL(oracle::occi::AnyData& streamOCCI_); + + ~ADDRESS_O(); + +OTT_USERCODE_START + + ADDRESS_O(string state_i, string zip_i); + void displayInfo(); + +OTT_USERCODE_END + +}; + +/************************************************************/ +// generated declarations for the PERSON_O object type. +/************************************************************/ + +class PERSON_O : public oracle::occi::PObject { + +protected: + + oracle::occi::Number id; + FullName * name; + oracle::occi::Ref< ADDRESS_O > addr; + +public: + + void *operator new(size_t size); + + void *operator new(size_t size, const oracle::occi::Connection * sess, + const OCCI_STD_NAMESPACE::string& table); + + void *operator new(size_t, void *ctxOCCI_); + + void *operator new(size_t size, const oracle::occi::Connection *sess, + const OCCI_STD_NAMESPACE::string &tableName, + const OCCI_STD_NAMESPACE::string &typeName, + const OCCI_STD_NAMESPACE::string &tableSchema, + const OCCI_STD_NAMESPACE::string &typeSchema); + + OCCI_STD_NAMESPACE::string getSQLTypeName() const; + + void getSQLTypeName(oracle::occi::Environment *env, void **schemaName, + unsigned int &schemaNameLen, void **typeName, + unsigned int &typeNameLen) const; + + PERSON_O(); + + PERSON_O(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { }; + + static void *readSQL(void *ctxOCCI_); + + virtual void readSQL(oracle::occi::AnyData& streamOCCI_); + + static void writeSQL(void *objOCCI_, void *ctxOCCI_); + + virtual void writeSQL(oracle::occi::AnyData& streamOCCI_); + + ~PERSON_O(); + +}; + +OTT_USERCODE_START + +class Person : public PERSON_O { +public: + Person(void *ctxOCCI_); + Person(int id_i, + FullName* name_i, + Ref& addr_i); + void move(const Ref& new_addr); + void displayInfo(); + ~Person(); +}; + +OTT_USERCODE_END + +#endif diff --git a/mdemo1.sql b/mdemo1.sql new file mode 100644 index 0000000..5b46b33 --- /dev/null +++ b/mdemo1.sql @@ -0,0 +1,34 @@ +connect scott/tiger; + +DROP TABLE PERSON_TAB; +DROP TABLE ADDR_TAB; +DROP TYPE PERSON_O; +DROP TYPE ADDRESS_O; +DROP TYPE FULL_NAME_O; + + +CREATE TYPE ADDRESS_O AS OBJECT ( + "state" CHAR(20), + "zip" CHAR(20) +) +/ + +CREATE TABLE ADDR_TAB OF ADDRESS_O; + +CREATE TYPE FULL_NAME_O AS OBJECT ( + "first_name" CHAR(20), + "last_name" CHAR(20) +) +/ + +CREATE TYPE PERSON_O AS OBJECT ( + "id" integer, + "name" FULL_NAME_O, + "addr" REF ADDRESS_O +) +/ + + +CREATE TABLE PERSON_TAB OF PERSON_O; + +QUIT; diff --git a/mdemo1.typ b/mdemo1.typ new file mode 100644 index 0000000..88c6ce0 --- /dev/null +++ b/mdemo1.typ @@ -0,0 +1,7 @@ +CASE=SAME +MAPFILE=mdemo1m.cpp +TYPE FULL_NAME_O + GENERATE FULL_NAME_O AS FullName +TYPE ADDRESS_O +TYPE PERSON_O + GENERATE PERSON_O AS Person diff --git a/mdemo1o.cpp b/mdemo1o.cpp new file mode 100644 index 0000000..b47eafc --- /dev/null +++ b/mdemo1o.cpp @@ -0,0 +1,422 @@ +#ifndef OTT_USERCODE_START +# define OTT_USERCODE_START +#endif + +#ifndef OTT_USERCODE_END +# define OTT_USERCODE_END +#endif + +#ifndef MDEMO1_ORACLE +# include "mdemo1.h" +#endif + + +/*****************************************************************/ +// generated method implementations for the FULL_NAME_O object type. +/*****************************************************************/ + +void *FULL_NAME_O::operator new(size_t size) +{ + return oracle::occi::PObject::operator new(size); +} + +void *FULL_NAME_O::operator new(size_t size, const oracle::occi::Connection * sess, + const OCCI_STD_NAMESPACE::string& table) +{ + return oracle::occi::PObject::operator new(size, sess, table, + (char *) "SCOTT.FULL_NAME_O"); +} + +void *FULL_NAME_O::operator new(size_t size, void *ctxOCCI_) +{ + return oracle::occi::PObject::operator new(size, ctxOCCI_); +} + +void *FULL_NAME_O::operator new(size_t size, + const oracle::occi::Connection *sess, + const OCCI_STD_NAMESPACE::string &tableName, + const OCCI_STD_NAMESPACE::string &typeName, + const OCCI_STD_NAMESPACE::string &tableSchema, + const OCCI_STD_NAMESPACE::string &typeSchema) +{ + return oracle::occi::PObject::operator new(size, sess, tableName, + typeName, tableSchema, typeSchema); +} + +OCCI_STD_NAMESPACE::string FULL_NAME_O::getSQLTypeName() const +{ + return OCCI_STD_NAMESPACE::string("SCOTT.FULL_NAME_O"); +} + +void FULL_NAME_O::getSQLTypeName(oracle::occi::Environment *env, void **schemaName, + unsigned int &schemaNameLen, void **typeName, unsigned int &typeNameLen) const +{ + PObject::getSQLTypeName(env, &FULL_NAME_O::readSQL, schemaName, + schemaNameLen, typeName, typeNameLen); +} + +FULL_NAME_O::FULL_NAME_O() +{ +} + +OTT_USERCODE_START + +FullName::FullName(void *ctxOCCI_): FULL_NAME_O(ctxOCCI_) +{ +} + +OTT_USERCODE_END + +void *FULL_NAME_O::readSQL(void *ctxOCCI_) +{ + FullName *objOCCI_ = new(ctxOCCI_) FullName(ctxOCCI_); + oracle::occi::AnyData streamOCCI_(ctxOCCI_); + + try + { + if (streamOCCI_.isNull()) + objOCCI_->setNull(); + else + objOCCI_->readSQL(streamOCCI_); + } + catch (oracle::occi::SQLException& excep) + { + delete objOCCI_; + excep.setErrorCtx(ctxOCCI_); + return (void *)NULL; + } + return (void *)objOCCI_; +} + +void FULL_NAME_O::readSQL(oracle::occi::AnyData& streamOCCI_) +{ + first_name = streamOCCI_.getString(); + last_name = streamOCCI_.getString(); +} + +void FULL_NAME_O::writeSQL(void *objectOCCI_, void *ctxOCCI_) +{ + FULL_NAME_O *objOCCI_ = (FULL_NAME_O *) objectOCCI_; + oracle::occi::AnyData streamOCCI_(ctxOCCI_); + + try + { + if (objOCCI_->isNull()) + streamOCCI_.setNull(); + else + objOCCI_->writeSQL(streamOCCI_); + } + catch (oracle::occi::SQLException& excep) + { + excep.setErrorCtx(ctxOCCI_); + } + return; +} + +void FULL_NAME_O::writeSQL(oracle::occi::AnyData& streamOCCI_) +{ + streamOCCI_.setString(first_name); + streamOCCI_.setString(last_name); +} + +FULL_NAME_O::~FULL_NAME_O() +{ + int i; +} + +OTT_USERCODE_START + +// initialize FullName +FullName::FullName(string FirstName, string LastName) +{ + first_name = FirstName; + last_name = LastName; +} + +// display all the information in FullName +void FullName::displayInfo() +{ + cout << "FIRST NAME is " << first_name << endl; + cout << "LAST NAME is " << last_name << endl; +} + +FullName::~FullName() +{ +} + +OTT_USERCODE_END + +/*****************************************************************/ +// generated method implementations for the ADDRESS_O object type. +/*****************************************************************/ + +void *ADDRESS_O::operator new(size_t size) +{ + return oracle::occi::PObject::operator new(size); +} + +void *ADDRESS_O::operator new(size_t size, const oracle::occi::Connection * sess, + const OCCI_STD_NAMESPACE::string& table) +{ + return oracle::occi::PObject::operator new(size, sess, table, + (char *) "SCOTT.ADDRESS_O"); +} + +void *ADDRESS_O::operator new(size_t size, void *ctxOCCI_) +{ + return oracle::occi::PObject::operator new(size, ctxOCCI_); +} + +void *ADDRESS_O::operator new(size_t size, + const oracle::occi::Connection *sess, + const OCCI_STD_NAMESPACE::string &tableName, + const OCCI_STD_NAMESPACE::string &typeName, + const OCCI_STD_NAMESPACE::string &tableSchema, + const OCCI_STD_NAMESPACE::string &typeSchema) +{ + return oracle::occi::PObject::operator new(size, sess, tableName, + typeName, tableSchema, typeSchema); +} + +OCCI_STD_NAMESPACE::string ADDRESS_O::getSQLTypeName() const +{ + return OCCI_STD_NAMESPACE::string("SCOTT.ADDRESS_O"); +} + +void ADDRESS_O::getSQLTypeName(oracle::occi::Environment *env, void **schemaName, + unsigned int &schemaNameLen, void **typeName, unsigned int &typeNameLen) const +{ + PObject::getSQLTypeName(env, &ADDRESS_O::readSQL, schemaName, + schemaNameLen, typeName, typeNameLen); +} + +ADDRESS_O::ADDRESS_O() +{ +} + +void *ADDRESS_O::readSQL(void *ctxOCCI_) +{ + ADDRESS_O *objOCCI_ = new(ctxOCCI_) ADDRESS_O(ctxOCCI_); + oracle::occi::AnyData streamOCCI_(ctxOCCI_); + + try + { + if (streamOCCI_.isNull()) + objOCCI_->setNull(); + else + objOCCI_->readSQL(streamOCCI_); + } + catch (oracle::occi::SQLException& excep) + { + delete objOCCI_; + excep.setErrorCtx(ctxOCCI_); + return (void *)NULL; + } + return (void *)objOCCI_; +} + +void ADDRESS_O::readSQL(oracle::occi::AnyData& streamOCCI_) +{ + state = streamOCCI_.getString(); + zip = streamOCCI_.getString(); +} + +void ADDRESS_O::writeSQL(void *objectOCCI_, void *ctxOCCI_) +{ + ADDRESS_O *objOCCI_ = (ADDRESS_O *) objectOCCI_; + oracle::occi::AnyData streamOCCI_(ctxOCCI_); + + try + { + if (objOCCI_->isNull()) + streamOCCI_.setNull(); + else + objOCCI_->writeSQL(streamOCCI_); + } + catch (oracle::occi::SQLException& excep) + { + excep.setErrorCtx(ctxOCCI_); + } + return; +} + +void ADDRESS_O::writeSQL(oracle::occi::AnyData& streamOCCI_) +{ + streamOCCI_.setString(state); + streamOCCI_.setString(zip); +} + +ADDRESS_O::~ADDRESS_O() +{ + int i; +} + +OTT_USERCODE_START + +// initialize ADDRESS_O +ADDRESS_O::ADDRESS_O(string state_i, string zip_i) +{ + state = state_i; + zip = zip_i; +} + +// display all the information in ADDRESS_O +void ADDRESS_O::displayInfo() +{ + cout << "STATE is " << state << endl; + cout << "ZIP is " << zip << endl; +} + +OTT_USERCODE_END + +/*****************************************************************/ +// generated method implementations for the PERSON_O object type. +/*****************************************************************/ + +void *PERSON_O::operator new(size_t size) +{ + return oracle::occi::PObject::operator new(size); +} + +void *PERSON_O::operator new(size_t size, const oracle::occi::Connection * sess, + const OCCI_STD_NAMESPACE::string& table) +{ + return oracle::occi::PObject::operator new(size, sess, table, + (char *) "SCOTT.PERSON_O"); +} + +void *PERSON_O::operator new(size_t size, void *ctxOCCI_) +{ + return oracle::occi::PObject::operator new(size, ctxOCCI_); +} + +void *PERSON_O::operator new(size_t size, + const oracle::occi::Connection *sess, + const OCCI_STD_NAMESPACE::string &tableName, + const OCCI_STD_NAMESPACE::string &typeName, + const OCCI_STD_NAMESPACE::string &tableSchema, + const OCCI_STD_NAMESPACE::string &typeSchema) +{ + return oracle::occi::PObject::operator new(size, sess, tableName, + typeName, tableSchema, typeSchema); +} + +OCCI_STD_NAMESPACE::string PERSON_O::getSQLTypeName() const +{ + return OCCI_STD_NAMESPACE::string("SCOTT.PERSON_O"); +} + +void PERSON_O::getSQLTypeName(oracle::occi::Environment *env, void **schemaName, + unsigned int &schemaNameLen, void **typeName, unsigned int &typeNameLen) const +{ + PObject::getSQLTypeName(env, &PERSON_O::readSQL, schemaName, + schemaNameLen, typeName, typeNameLen); +} + +PERSON_O::PERSON_O() +{ + name = (FullName *) 0; +} + +OTT_USERCODE_START + +Person::Person(void *ctxOCCI_): PERSON_O(ctxOCCI_) +{ +} + +OTT_USERCODE_END + +void *PERSON_O::readSQL(void *ctxOCCI_) +{ + Person *objOCCI_ = new(ctxOCCI_) Person(ctxOCCI_); + oracle::occi::AnyData streamOCCI_(ctxOCCI_); + + try + { + if (streamOCCI_.isNull()) + objOCCI_->setNull(); + else + objOCCI_->readSQL(streamOCCI_); + } + catch (oracle::occi::SQLException& excep) + { + delete objOCCI_; + excep.setErrorCtx(ctxOCCI_); + return (void *)NULL; + } + return (void *)objOCCI_; +} + +void PERSON_O::readSQL(oracle::occi::AnyData& streamOCCI_) +{ + id = streamOCCI_.getNumber(); + name = (FullName *) streamOCCI_.getObject(&FullName::readSQL); + addr = streamOCCI_.getRef(); +} + +void PERSON_O::writeSQL(void *objectOCCI_, void *ctxOCCI_) +{ + PERSON_O *objOCCI_ = (PERSON_O *) objectOCCI_; + oracle::occi::AnyData streamOCCI_(ctxOCCI_); + + try + { + if (objOCCI_->isNull()) + streamOCCI_.setNull(); + else + objOCCI_->writeSQL(streamOCCI_); + } + catch (oracle::occi::SQLException& excep) + { + excep.setErrorCtx(ctxOCCI_); + } + return; +} + +void PERSON_O::writeSQL(oracle::occi::AnyData& streamOCCI_) +{ + streamOCCI_.setNumber(id); + streamOCCI_.setObject(name); + streamOCCI_.setRef(addr); +} + +PERSON_O::~PERSON_O() +{ + int i; + delete name; +} + +OTT_USERCODE_START + +// initialize Person +Person::Person(int id_i, + FullName *name_i, + Ref& addr_i) +{ + id = id_i; + name = name_i; + addr =addr_i ; +} + +// Move Person from curr_addr to new_addr +void Person::move(const Ref& new_addr) +{ + addr = new_addr; + this->markModified(); // mark the object as dirty +} + +// Display all the information of Person +void Person::displayInfo() { + cout << "ID is " << (int)id << endl; + name->displayInfo(); + + // de-referencing the Ref attribute using -> operator + addr->displayInfo(); + +} + +Person::~Person() +{ +} + +OTT_USERCODE_END diff --git a/mymdemo1.h b/mymdemo1.h new file mode 100644 index 0000000..f7d0897 --- /dev/null +++ b/mymdemo1.h @@ -0,0 +1,8 @@ +# include + +#define USERNAME "scott" +#define PASSWORD "tiger" + +using namespace oracle::occi; +using namespace std; + diff --git a/nchdemo1.c b/nchdemo1.c new file mode 100644 index 0000000..2b6fd77 --- /dev/null +++ b/nchdemo1.c @@ -0,0 +1,586 @@ +/* Copyright (c) 2001, 2009, Oracle and/or its affiliates. +All rights reserved. */ + +/* + + NAME + nchdemo1.c - show nchar implicit conversion feature and codepoint feature + + DESCRIPTION + * Demo description: + * 1.Implicit conversion: + * the data being inserted into nchar column of this table is in + * zhs16gbk encoding, you don't need specify charsetfm to + * SQLCS_NCHAR in bind/define. implicit conversion will happend + * and automatic convert zhs16gbk data into al16utf16 while + * insert and convert it back while doing select. + * 2.Benefit from codepoint semantics: Client side application + * independent of server character set. + * Since Nchar is always in codepoint semantics, via implict + * describe, you can get the char size of nchar column, the number + * is always in characters, so the client side buffer is allocated + * as number of characters times max char-width of client side + * charset. even server side ncharset is changed from al16utf16 + * to utf8, you don't need re-allocate the client side buffer. + * + * Setup: to show the implicit conversion feature, you need create your + * database with database character set is utf8, otherwise, data loss will + * happened when doing implicit conversion. + * + * Note: the data is in zhs16gbk encoding, other platform can't display the + * chinese character correctly. + * + + + EXPORT FUNCTION(S) + + + INTERNAL FUNCTION(S) + + + STATIC FUNCTION(S) + + + NOTES + + + MODIFIED (MM/DD/YY) + wezhu 05/28/09 - remove hard tabs + wezhu 05/21/09 - provide errhp to checkerr function call. + chli 11/04/02 - fix bug2840920 + chli 07/20/01 - fix bug1891086 + chli 06/20/01 - fix compile warning + chli 03/15/01 - Merged chli_fixdiff_0313 + chli 03/15/01 - Creation + +*/ + + +#ifndef STDIO +#include +#endif + +#ifndef CTYPE +#include +#endif + +#ifndef OCI_ORACLE +#include +#endif + +#define OCI_UNICODE_U OCI_UNICODE +#define OCI_UNICODE_D OCI_DEFAULT +#define OCI_UNICODE_N OCI_NON_UNICODE + +OCIEnv *envhp; +OCIServer *srvhp; +OCIError *errhp; +OCISvcCtx *svchp; +OCISession *authp; + + +void main(); +static void checkerr(/*errhp, status*/); +sword init_env(/*_envhp, svchp, errhp, srvhp, authp, env_mode_*/); +sword attach_server(/*_server_mode, srvhp, errhp, svchp_*/); +sword log_on(/*_authp, errhp, svchp, uid, pwd, credt, session_mode_*/); +sword free_handles(); + + +void main() +{ + +ub4 env_mode = OCI_UNICODE_D; +ub4 server_mode = OCI_UNICODE_D; +ub4 session_mode = OCI_UNICODE_D; +ub4 stmt_mode = OCI_UNICODE_D; +ub4 bind_mode = OCI_UNICODE_D; +ub4 def_mode = OCI_UNICODE_D; + +text *uid = (text *)"oe"; +text *pwd = (text *)"oe"; + +static text *stmt=(text *)"INSERT INTO product_descriptions VALUES (:product_id, :language_id, :translated_name, :translated_description)"; +static text *sel_stmt=(text *)"SELECT * FROM product_descriptions where product_id= :id"; +static text *del_stmt=(text *)"DELETE FROM product_descriptions where product_id= :id"; + +OCIStmt *stmt1p; +OCIStmt *stmt2p; +OCIStmt *stmt3p; + +OCIParam *mypard; + +static OCIBind *bnd1p = (OCIBind *)0; +static OCIBind *bnd2p = (OCIBind *)0; +static OCIBind *bnd3p = (OCIBind *)0; +static OCIBind *bnd4p = (OCIBind *)0; +static OCIBind *bnd5p = (OCIBind *)0; + +static OCIDefine *dfn1p,*dfn4p,*dfn2p,*dfn3p; + +static text *colname1 = (text *)":product_id"; +static text *colname2 = (text *)":language_id"; +static text *colname3 = (text *)":translated_name"; +static text *colname4 = (text *)":translated_description"; +static text *colname5 = (text *)":id"; + +ub2 sqltype1 = SQLT_INT; +ub2 sqltype2 = SQLT_DAT; +ub2 sqltype3 = SQLT_STR; +ub2 sqltype4 = SQLT_STR; +ub2 sqltype5 = SQLT_BIN; + + +ub4 credt = OCI_CRED_RDBMS; +char char1_in[4],char2_in[50],char3_in[100]; +sb2 ind=0; +dvoid *tmp; +sword err, status, i; +sword in_id, out_id; + +/*char *char1_outp, *char2_outp, *char3_outp;*/ +char char1_outp[40], char2_outp[40], char3_outp[40]; + +ub4 bmaxsiz = 20; +ub4 cmaxsiz = 20; +ub1 char_semantics; +ub2 col_width2, col_width3, col_width4; +ub2 chrsetid = 852; +ub1 flag2, flag3, flag4; + + + in_id=100081; + strcpy(char1_in,"zhs"); + char1_in[3]='\0'; + strcpy(char2_in,"ÊǸÉ"); + char2_in[8]='\0'; + strcpy(char3_in,"ÒøÁøÊǸɻ¨µÄÒ»ÖÖ£¬·ÅÓÚÊÒÄڿɾ­Ä겻л"); + char3_in[36]='\0'; + +/* + char1_outp=(char *)malloc(40); + char2_outp=(char *)malloc(40); + char3_outp=(char *)malloc(40); +*/ + + for (i=0; i<40; i++) + { + char1_outp[i]='\0'; + char2_outp[i]='\0'; + char3_outp[i]='\0'; + } + + init_env(env_mode); + attach_server(server_mode); + log_on(uid, pwd, credt, session_mode); + +/*---- Insert operation -------*/ + checkerr(errhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **)&stmt1p, + (ub4)OCI_HTYPE_STMT,100, (dvoid **) &tmp)); + checkerr(errhp, OCIStmtPrepare(stmt1p, errhp, stmt, (ub4)strlen((char *)stmt), + (ub4)OCI_NTV_SYNTAX, (ub4)stmt_mode)); + + checkerr(errhp, OCIBindByName(stmt1p, &bnd1p, errhp, (text *)colname1, + (sb4)strlen((char*)colname1), + (dvoid *)&in_id, (sb4)sizeof(sword), sqltype1, (dvoid *)&ind, + (ub2 *) 0, (ub2 *) 0, (ub4) 0,(ub4 *)0,bind_mode)); + + checkerr(errhp, OCIBindByName(stmt1p, &bnd2p, errhp, (text *)colname2, + (sb4)strlen((char*)colname2), + (dvoid *)char1_in, (sb4)sizeof(char1_in), sqltype3, + (dvoid *)&ind, + (ub2 *) 0, (ub2 *) 0, (ub4) 0,(ub4 *)0,bind_mode)); + checkerr(errhp, OCIBindByName(stmt1p, &bnd3p, errhp, (text *)colname3, + (sb4)strlen((char*)colname3), + (dvoid *)char2_in, (sb4)sizeof(char2_in), sqltype3, + (dvoid *)&ind,(ub2 *) 0, (ub2 *) 0, + (ub4) 0,(ub4 *)0,bind_mode)); + checkerr(errhp, OCIBindByName(stmt1p, &bnd4p, errhp, (text *)colname4, + (sb4)strlen((char*)colname4), + (dvoid *)char3_in, (sb4)sizeof(char3_in), sqltype3, + (dvoid *)&ind,(ub2 *) 0, (ub2 *) 0, + (ub4) 0,(ub4 *)0,bind_mode)); + +/* set character id 852(zhs16gbk) for varchar2 and nvarchar2 column + you don't need specify charset_form here, since oracle will do the + implicit conversion from char to nchar for you. +*/ + + + checkerr(errhp,OCIAttrSet((dvoid *)bnd2p, (ub4) OCI_HTYPE_BIND, + (dvoid *)&chrsetid, (ub4) 0, + (ub4) OCI_ATTR_CHARSET_ID, errhp)); + checkerr(errhp,OCIAttrSet((dvoid *)bnd3p, (ub4) OCI_HTYPE_BIND, + (dvoid *)&chrsetid, (ub4) 0, + (ub4) OCI_ATTR_CHARSET_ID, errhp)); + checkerr(errhp,OCIAttrSet((dvoid *)bnd4p, (ub4) OCI_HTYPE_BIND, + (dvoid *)&chrsetid, (ub4) 0, + (ub4) OCI_ATTR_CHARSET_ID, errhp)); + + + err=OCIStmtExecute (svchp, stmt1p, errhp, (ub4)1, (ub4)0, + (OCISnapshot *)NULL,(OCISnapshot *)NULL, (ub4)OCI_DEFAULT); + + if (err == OCI_SUCCESS ) + printf("Insert successful\n"); + else + { + checkerr(errhp,err); + return; + } + + OCITransCommit(svchp, errhp, 0); + +/* end: ------ Insert complete -----------------*/ + + +/* begin: ------ get char counts of each column by call OCIParamGet ---- */ + + checkerr(errhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **)&stmt2p, + (ub4)OCI_HTYPE_STMT,100, (dvoid **) &tmp)); + checkerr(errhp, OCIStmtPrepare(stmt2p, errhp, sel_stmt, (ub4)strlen((char *)sel_stmt), + (ub4)OCI_NTV_SYNTAX, (ub4)stmt_mode)); + + checkerr(errhp, OCIStmtExecute(svchp,stmt2p,errhp,(ub4)1, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, (ub4)OCI_DESCRIBE_ONLY)); + err = OCIParamGet(stmt2p,OCI_HTYPE_STMT,errhp,&mypard, (ub4)2); + if (err == OCI_SUCCESS) + { + checkerr(errhp, OCIAttrGet((dvoid *)mypard,(ub4)OCI_DTYPE_PARAM, + (dvoid *)&char_semantics, (ub4)0, (ub4)OCI_ATTR_CHAR_USED, + (OCIError *)errhp)); + if (char_semantics) { + checkerr(errhp,OCIAttrGet((dvoid *)mypard,(ub4)OCI_DTYPE_PARAM, + (dvoid *)&col_width2,(ub4)0,(ub4)OCI_ATTR_CHAR_SIZE,(OCIError *)errhp)); + flag2=1; + } + else { + checkerr(errhp,OCIAttrGet((dvoid *)mypard,(ub4)OCI_DTYPE_PARAM, + (dvoid *)&col_width2,(ub4)0,(ub4)OCI_ATTR_DATA_SIZE,(OCIError *)errhp)); + flag2=0; + } + } + else + checkerr(errhp,err); + + err = OCIParamGet(stmt2p,OCI_HTYPE_STMT,errhp,&mypard, (ub4)3); + if (err == OCI_SUCCESS) + { + checkerr(errhp, OCIAttrGet((dvoid *)mypard,(ub4)OCI_DTYPE_PARAM, + (dvoid *)&char_semantics, (ub4)0, (ub4)OCI_ATTR_CHAR_USED, + (OCIError *)errhp)); + if (char_semantics) { + checkerr(errhp,OCIAttrGet((dvoid *)mypard,(ub4)OCI_DTYPE_PARAM, + (dvoid *)&col_width3,(ub4)0,(ub4)OCI_ATTR_CHAR_SIZE,(OCIError *)errhp)); + flag3=1; + } + else { + checkerr(errhp,OCIAttrGet((dvoid *)mypard,(ub4)OCI_DTYPE_PARAM, + (dvoid *)&col_width3,(ub4)0,(ub4)OCI_ATTR_DATA_SIZE,(OCIError *)errhp)); + flag3=0; + } + + /* since in codepoint semantics mode, the col_width is always return in + number of characters, the client side buffer size should be the number + of characters tims maximun char-width of client side charset. the max + charwidth for zhs16gbk is 2. */ + /* char2_outp=(char *)malloc(sizeof(char)*col_width3*2); */ + } + else + checkerr(errhp,err); + + /* ---- get char count of second column. ---- */ + err = OCIParamGet(stmt2p,OCI_HTYPE_STMT,errhp,&mypard, (ub4)4); + if (err == OCI_SUCCESS) + { + checkerr(errhp, OCIAttrGet((dvoid *)mypard,(ub4)OCI_DTYPE_PARAM, + (dvoid *)&char_semantics, (ub4)0, (ub4)OCI_ATTR_CHAR_USED, + (OCIError *)errhp)); + if (char_semantics) { + checkerr(errhp,OCIAttrGet((dvoid *)mypard,(ub4)OCI_DTYPE_PARAM, + (dvoid *)&col_width4,(ub4)0,(ub4)OCI_ATTR_CHAR_SIZE,(OCIError *)errhp)); + flag4=1; + } + else { + checkerr(errhp,OCIAttrGet((dvoid *)mypard,(ub4)OCI_DTYPE_PARAM, + (dvoid *)&col_width4,(ub4)0,(ub4)OCI_ATTR_DATA_SIZE,(OCIError *)errhp)); + flag4=0; + } +/* + char3_outp=(char *)malloc(sizeof(char)*col_width4*2); +*/ + } + else + checkerr(errhp,err); + + + /* ---- define the output buffer and do the query ---- */ + checkerr(errhp,OCIDefineByPos(stmt2p, &dfn1p, errhp, 1, (dvoid *)&out_id, + sizeof(out_id), sqltype1, (dvoid *)0, (ub2 *)0, + (ub2 *)0, def_mode)); + checkerr(errhp,OCIDefineByPos(stmt2p, &dfn2p, errhp, 2, (dvoid *)char1_outp, + 9, sqltype3, (dvoid *)0, (ub2 *)0, (ub2 *)0, def_mode)); + checkerr(errhp,OCIDefineByPos(stmt2p, &dfn3p, errhp, 3, (dvoid *)char2_outp, + col_width3, sqltype3, (dvoid *)0, (ub2 *)0, (ub2 *)0, def_mode)); + checkerr(errhp,OCIDefineByPos(stmt2p, &dfn4p, errhp, 4, (dvoid *)char3_outp, + col_width4, sqltype3, (dvoid *)0, (ub2 *)0, (ub2 *)0, def_mode)); + +/* --- set the charset-id to 852 for output buffer ---- */ + + checkerr(errhp,OCIAttrSet((dvoid *)dfn2p, (ub4) OCI_HTYPE_DEFINE, + (dvoid *)&chrsetid, (ub4) 0, + (ub4) OCI_ATTR_CHARSET_ID, errhp)); + + checkerr(errhp,OCIAttrSet((dvoid *)dfn3p, (ub4) OCI_HTYPE_DEFINE, + (dvoid *)&chrsetid, (ub4) 0, + (ub4) OCI_ATTR_CHARSET_ID, errhp)); + + checkerr(errhp,OCIAttrSet((dvoid *)dfn4p, (ub4) OCI_HTYPE_DEFINE, + (dvoid *)&chrsetid, (ub4) 0, + (ub4) OCI_ATTR_CHARSET_ID, errhp)); + + checkerr(errhp, OCIBindByName(stmt2p, &bnd5p, errhp, (text *)colname5, + (sb4)strlen((char*)colname5), + (dvoid *)&in_id, (sb4)sizeof(sword), sqltype1, (dvoid *)&ind, + (ub2 *) 0, (ub2 *) 0, (ub4) 0,(ub4 *)0,bind_mode)); + + err = OCIStmtExecute (svchp, stmt2p, errhp, (ub4)1, (ub4)0, + (OCISnapshot *)NULL,(OCISnapshot *)NULL, (ub4)OCI_DEFAULT); + + checkerr(errhp, err); + if (err == OCI_SUCCESS || err == OCI_SUCCESS_WITH_INFO) + { + do + { + printf("product_id is : %d\n", out_id); + if (flag2==1) + printf("column language id is char semantics and the width is: %d chars\n",col_width2); + else + printf("column language id is byte semantics and the width is: %d bytes\n",col_width2); + printf("language_id is : %s\n\n", char1_outp); + + if (flag3==1) + printf("column translated_name is char semantics and the width is: %d chars\n",col_width3); + else + printf("column translated_name is byte semantics and the width is: %d bytes\n",col_width3); + printf("translated_name is : %s\n\n", char2_outp); + + if (flag4==1) + printf("column product_description is char semantics and the width is: %d chars\n",col_width4); + else + printf("column product_description is byte semantics and the width is: %d bytes\n",col_width4); + printf("product_description is : %s\n\n", char3_outp); + + status = OCIStmtFetch(stmt2p, errhp, (ub4) 1, + (ub4) OCI_FETCH_NEXT, + (ub4) OCI_DEFAULT); + }while (status == OCI_SUCCESS || status == OCI_SUCCESS_WITH_INFO); + } + +/****** delete temporary data *******/ + + checkerr(errhp, OCIHandleAlloc((dvoid *) envhp, (dvoid **)&stmt3p, + (ub4)OCI_HTYPE_STMT,100, (dvoid **) &tmp)); + checkerr(errhp, OCIStmtPrepare(stmt3p, errhp, del_stmt, + (ub4)strlen((char *)del_stmt), + (ub4)OCI_NTV_SYNTAX, (ub4)stmt_mode)); + + checkerr(errhp, OCIBindByName(stmt3p, &bnd5p, errhp, (text *)colname5, + (sb4)strlen((char*)colname5), + (dvoid *)&in_id, (sb4)sizeof(sword), sqltype1, (dvoid *)&ind, + (ub2 *) 0, (ub2 *) 0, (ub4) 0,(ub4 *)0,bind_mode)); + + checkerr(errhp, OCIStmtExecute(svchp,stmt3p,errhp,(ub4)1, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, (ub4)OCI_DEFAULT)); + + /*free(char1_outp); + free(char2_outp); + free(char3_outp); */ + OCIHandleFree((dvoid *) stmt1p, (ub4) OCI_HTYPE_STMT); + OCIHandleFree((dvoid *) stmt2p, (ub4) OCI_HTYPE_STMT); + OCIHandleFree((dvoid *) stmt3p, (ub4) OCI_HTYPE_STMT); + free_handles(); + +} + +static void checkerr(errhp, status) +OCIError *errhp; +sword status; +{ + text errbuf[512]; + ub4 buflen; + sb4 errcode; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + fprintf(stdout, "Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + fprintf(stdout, "Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + fprintf(stdout, "Error - OCI_NO_DATA\n"); + break; + case OCI_ERROR: + OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); + fprintf(stdout, "Error - %s\n", errbuf); + break; + case OCI_INVALID_HANDLE: + fprintf(stdout, "Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + fprintf(stdout, "Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + fprintf(stdout, "Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} + + +/* ----------------------------------------------------------------- */ +/* initialize environment, allocate handles */ +/* ----------------------------------------------------------------- */ + +sword init_env(env_mode) +ub4 env_mode; +{ + + if (OCIEnvCreate((OCIEnv **) &envhp, env_mode, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, + (dvoid * (*)(dvoid *, dvoid *, size_t))0, + (void (*)(dvoid *, dvoid *)) 0, + (size_t) 0, (dvoid **) 0 )) + { + printf("FAILED: OCIEnvCreate()\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on svchp\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on errhp\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on srvhp\n"); + return OCI_ERROR; + } + + if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0)) + { + printf("FAILED: OCIHandleAlloc() on authp\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + +/* ----------------------------------------------------------------- */ +/* attach to server with a given mode. */ +/* ----------------------------------------------------------------- */ + +sword attach_server(server_mode) +ub4 server_mode; +{ + + if (OCIServerAttach(srvhp, errhp, (text *) "", + (sb4) strlen(""), (ub4) server_mode)) + { + printf("FAILED: OCIServerAttach()\n"); + return OCI_ERROR; + } + + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) srvhp, (ub4) 0, (ub4) OCI_ATTR_SERVER, errhp)) + { + printf("FAILED: OCIAttrSet() server attribute\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} +sword log_on(uid, pwd, credt, session_mode) +text *uid; +text *pwd; +ub4 credt; +ub4 session_mode; +{ + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) uid, (ub4) strlen((char *) uid), + (ub4) OCI_ATTR_USERNAME, errhp)) + { + printf("FAILED: OCIAttrSet() userid\n"); + return OCI_ERROR; + } + if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) pwd, (ub4) strlen((char *) pwd), + (ub4) OCI_ATTR_PASSWORD, errhp)) + { + printf("FAILED: OCIAttrSet() passwd\n"); + return OCI_ERROR; + } + + + printf("Logging on as %s ....\n", uid); + + if (OCISessionBegin(svchp, errhp, authp, credt, session_mode)) + { + printf("FAILED: OCIAttrSet() passwd\n"); + return OCI_ERROR; + } + + printf("%s logged on.\n", uid); + + if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) authp, (ub4) 0, (ub4) OCI_ATTR_SESSION, errhp)) + { + printf("FAILED: OCIAttrSet() session\n"); + return OCI_ERROR; + } + + return OCI_SUCCESS; +} + + +sword free_handles() +{ + OCISessionEnd(svchp, errhp, authp, (ub4)OCI_DEFAULT); + OCIServerDetach( srvhp, errhp, (ub4) OCI_DEFAULT ); + OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX); + OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR); + OCIHandleFree((dvoid *) authp, (ub4) OCI_HTYPE_SESSION); + OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER); + return OCI_SUCCESS; + +} + + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + STATIC FUNCTION DECLARATIONS + ---------------------------------------------------------------------------*/ + + +/* end of file nchdemo1.c */ + diff --git a/nlsdemo0.sql b/nlsdemo0.sql new file mode 100644 index 0000000..403af32 --- /dev/null +++ b/nlsdemo0.sql @@ -0,0 +1,133 @@ +Rem +Rem $Header: nlsdemo0.sql 23-jul-2003.12:21:16 chli Exp $ +Rem +Rem nlsdemo0.sql +Rem +Rem Copyright (c) 2001, 2003, Oracle Corporation. All rights reserved. +Rem +Rem NAME +Rem nlsdemo0.sql - +Rem +Rem DESCRIPTION +Rem This is the first sql that must be run before run NLS demo +Rem Insert extra multibyte data for nls linguistic index test +Rem create 3 linguistic index, plustrace role and plan_table +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem tnallath 05/09/02 - bug 2368367:. +Rem huwang 02/22/01 - Merged huwang_nlsdemo +Rem huwang 02/22/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +CONNECT OE/OE + +insert into product_information(product_id) values(2728); +insert into product_information(product_id) values(2729); +insert into product_information(product_id) values(2730); +insert into product_information(product_id) values(2731); +insert into product_information(product_id) values(2732); +insert into product_information(product_id) values(2734); + +insert into product_descriptions values (2728,'D','abcd','abcd'); +insert into product_descriptions values (2729,'D','Abcd','Abcd'); +insert into product_descriptions values (2730,'D',Unistr('\00e4bcd'),'bcd'); +insert into product_descriptions values (2731,'D',Unistr('\00c4bcd'),'bcd'); + + +insert into product_descriptions values (2728 +, 'ZHS' +, UNISTR('\6db2\6676\663e\793a\5668') +, 'LED DISPLAYER' +); + +insert into product_descriptions values (2729 +, 'ZHS' +, UNISTR('\7535\89c6\673a') +, 'TV set' +); + +insert into product_descriptions values(2730 +,'ZHS' +,UNISTR('\6fc0\5149\5531\76d8') +,'Laser CD' +); + +insert into product_descriptions values(2731 +,'ZHS' +,UNISTR('\79fb\52a8\7535\8bdd') +,'Celluar phone' +); + +insert into product_descriptions values(2732 +,'ZHS' +,UNISTR('\7535\51b0\7bb1') +,'Refrigerator'); + +Commit; + + +REM Create Linguistic Index on Product_Descriptions Table's Translated_Description + +CONNECT OE/OE + +ALTER SESSION SET NLS_COMP=ANSI; + +ALTER SESSION SET QUERY_REWRITE_ENABLED=TRUE; + +rem pause Create Generic_M Index on Translated_name NVARCHAR2 Column, Please Press < Enter> to continue... + +ALTER SESSION SET NLS_SORT=GENERIC_M; + +DROP INDEX NLS_GENERIC; + +CREATE INDEX NLS_GENERIC ON product_descriptions( NLSSORT(translated_name, 'NLS_SORT=GENERIC_M')); + +rem pause Create Simplified Chinese Storke sorting Index on Translated_name NVARCHAR2 Column, Please Press to continue + +ALTER SESSION SET NLS_SORT=SCHINESE_STROKE_M; + +DROP INDEX NLS_ZHSSTROKE; + +CREATE INDEX NLS_ZHSSTROKE ON product_descriptions( NLSSORT(translated_name, 'NLS_SORT=SCHINESE_STROKE_M')); + +rem pause Create Simplified Chinese Pinyin sorting Index on Translated_name NVARCHAR2 Column, Please Press to continue + +ALTER SESSION SET NLS_SORT=SCHINESE_PINYIN_M; + +DROP INDEX NLS_ZHSPINYIN; + +CREATE INDEX NLS_ZHSPINYIN ON product_descriptions( NLSSORT(translated_name, 'NLS_SORT=SCHINESE_PINYIN_M')); + +ANALYZE TABLE Product_descriptions COMPUTE STATISTICS; + +Rem Set Autotrace On to see the execution plan + +Prompt Please Input the password for User sys + +CONNECT SYS/change_on_install AS SYSDBA + +Rem Run ?/sqlplus/admin/plustrce.sql to Create role + +@?/sqlplus/admin/plustrce.sql + +GRANT plustrace To OE; + +CONNECT OE/OE + +Rem Run ?/rdbms/admin/utlxplan.sql to Create PLAN_TABLE + +DROP TABLE PLAN_TABLE; + +@?/rdbms/admin/utlxplan.sql + diff --git a/nlsdemo1.sql b/nlsdemo1.sql new file mode 100644 index 0000000..b3046c0 --- /dev/null +++ b/nlsdemo1.sql @@ -0,0 +1,60 @@ +Rem +Rem $Header: nlsdemo1.sql 23-jul-2003.11:27:27 chli Exp $ +Rem +Rem nlsdemo1.sql +Rem +Rem Copyright (c) 2001, 2003, Oracle Corporation. All rights reserved. +Rem +Rem NAME +Rem nlsdemo1.sql - +Rem +Rem DESCRIPTION +Rem to continue +SELECT * FROM PRODUCT_DESCRIPTIONS +ORDER BY TRANSLATED_NAME; + +rem pause The following three ALTER statements change the sort setting to Generic_M linguistic sort + +ALTER SESSION SET NLS_COMP=ANSI; + +ALTER SESSION SET NLS_SORT='GENERIC_M'; + +ALTER SESSION SET QUERY_REWRITE_ENABLED=TRUE; + +rem pause Now you will see the generic_m sorting result for Translated_name NVARCHAR2 Column, Please press to continue + +SELECT * FROM PRODUCT_DESCRIPTIONS +WHERE TRANSLATED_NAME > UNISTR('\0000') +ORDER BY TRANSLATED_NAME; + + + + + diff --git a/nlsdemo2.sql b/nlsdemo2.sql new file mode 100644 index 0000000..1c2b256 --- /dev/null +++ b/nlsdemo2.sql @@ -0,0 +1,60 @@ +Rem +Rem $Header: nlsdemo2.sql 23-jul-2003.11:28:40 chli Exp $ +Rem +Rem nlsdemo2.sql +Rem +Rem Copyright (c) 2001, 2003, Oracle Corporation. All rights reserved. +Rem +Rem NAME +Rem nlsdemo2.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem chli 07/23/03 - +Rem huwang 02/22/01 - Merged huwang_nlsdemo +Rem huwang 02/22/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +REM Create Policy Function + +CONNECT OE/OE + +DROP FUNCTION secure_person; + +CREATE OR REPLACE FUNCTION secure_person ( object_schema IN VARCHAR2, object_name IN VARCHAR2) return VARCHAR2 IS +BEGIN + RETURN( 'language_id=SYS_CONTEXT(''USERENV'',''LANG'')'); +END; +/ + +SHOW ERRORS + +REM Add and Enable The Policy + +Prompt Please enter the password for User SYS + +connect sys/change_on_install as sysdba + +BEGIN + DBMS_RLS.DROP_POLICY('OE','PRODUCT_DESCRIPTIONS','NCHARFEATURE'); +END; +/ + +BEGIN + DBMS_RLS.ADD_POLICY('OE','PRODUCT_DESCRIPTIONS','NCHARFEATURE','OE','SECURE_PERSON','SELECT'); +END; +/ + diff --git a/nlsdemo3.sql b/nlsdemo3.sql new file mode 100644 index 0000000..b360d38 --- /dev/null +++ b/nlsdemo3.sql @@ -0,0 +1,68 @@ +Rem +Rem $Header: nlsdemo3.sql 23-jul-2003.11:29:13 chli Exp $ +Rem +Rem nlsdemo3.sql +Rem +Rem Copyright (c) 2001, 2003, Oracle Corporation. All rights reserved. +Rem +Rem NAME +Rem nlsdemo3.sql - +Rem +Rem DESCRIPTION +Rem Using fine gained access control to show only chinese data in 3 different sorting mode: Generic_m, stroke and Pinyin +Rem NOTES +Rem We suppose to show chinese data , please set NLS_LANG to 'Simplified Chinese_China.zhs16gbk' +Rem Before you run this sql file, please run nlsdemo2.sql so that you can see the fine gained access control demo +Rem +Rem MODIFIED (MM/DD/YY) +Rem chli 07/23/03 - +Rem huwang 02/22/01 - Merged huwang_nlsdemo +Rem huwang 02/22/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + + +REM +REM Before you run the sql file, you must run nlsdemo2.sql +REM Please don't Forget to set NLS_LANG to 'Simplified Chinese_China.zhs16gbk' +REM + +CONNECT OE/OE + +COL LANGUANE_ID FORMAT A3 +COL TRANSLATED_NAME FORMAT A20 +COL TRANSLATED_DESCRIPTION FORMAT A20 + +SET AUTOTRACE ON EXPLAIN + +ALTER SESSION SET NLS_COMP=ANSI; + +ALTER SESSION SET QUERY_REWRITE_ENABLED=TRUE; + +rem pause You will see the Generic_M sorting result for only Chinese translated name + +ALTER SESSION SET NLS_SORT=GENERIC_M; + +SELECT * FROM Product_descriptions WHERE translated_name > UNISTR('\0000') ORDER BY translated_name; + +rem pause You will see the Storke sorting result for only Chinese translated name + +ALTER SESSION SET NLS_SORT=SCHINESE_STROKE_M; + +SELECT * FROM Product_descriptions WHERE translated_name > UNISTR('\0000') ORDER BY translated_name; + +rem pause You will see the Pinyin sorting result for only Chinese translated name + +ALTER SESSION SET NLS_SORT=SCHINESE_PINYIN_M; + +SELECT * FROM Product_descriptions WHERE translated_name > UNISTR('\0000') ORDER BY translated_name; + + + diff --git a/nlsdemo4.sql b/nlsdemo4.sql new file mode 100644 index 0000000..2f0bd09 --- /dev/null +++ b/nlsdemo4.sql @@ -0,0 +1,49 @@ +Rem +Rem $Header: nlsdemo4.sql 23-jul-2003.11:29:59 chli Exp $ +Rem +Rem nlsdemo4.sql +Rem +Rem Copyright (c) 2001, 2003, Oracle Corporation. All rights reserved. +Rem +Rem NAME +Rem nlsdemo3.sql - +Rem +Rem DESCRIPTION +Rem Using fine gained access control to show only one language data which is depending on your NLS_LANG setting +Rem Say, if you set NLS_LANG to japanese_japan.ja16sjis, only japanese data is shown, if you set NLS_LANG to 'Simplified Chinese +Rem _china.zhs16cgb231280', only chinese data is shown +Rem NOTES +Rem Before you run this sql file, please run nlsdemo2.sql so that you can see the fine gained access control demo +Rem +Rem MODIFIED (MM/DD/YY) +Rem chli 07/23/03 - +Rem huwang 02/22/01 - Merged huwang_nlsdemo +Rem huwang 02/22/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + + +REM +REM Before you run the sql file, you must run nlsdemo2.sql +REM Please don't Forget to set NLS_LANG to what you want +REM + +CONNECT OE/OE + +COL LANGUANE_ID FORMAT A3 +COL TRANSLATED_NAME FORMAT A20 +COL TRANSLATED_DESCRIPTION FORMAT A20 + +SET AUTOTRACE ON EXPLAIN + +rem pause You will see only one language data + +SELECT * FROM Product_descriptions; + diff --git a/nlsdemo5.sql b/nlsdemo5.sql new file mode 100644 index 0000000..04637e8 --- /dev/null +++ b/nlsdemo5.sql @@ -0,0 +1,57 @@ +Rem +Rem $Header: nlsdemo5.sql 23-jul-2003.11:34:27 chli Exp $ +Rem +Rem nlsdemo5.sql +Rem +Rem Copyright (c) 2001, 2003, Oracle Corporation. All rights reserved. +Rem +Rem NAME +Rem nlsdemo5.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem huwang 02/22/01 - Merged huwang_nlsdemo +Rem huwang 02/22/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +REM Clean the indexes and Policy for the demo + +Prompt Please enter the password for User SYS + +connect sys/change_on_install as sysdba + +BEGIN + DBMS_RLS.DROP_POLICY('OE','PRODUCT_DESCRIPTIONS','NCHARFEATURE'); +END; +/ + +CONNECT OE/OE + +DROP FUNCTION secure_person; + +Delete from product_descriptions where language_id in ('D','ZHS') and product_id in (2728,2729,2730,2731,2732); + +Delete from product_information where product_id in (2728,2729,2730,2731,2732); + +DROP INDEX NLS_GENERIC; + +DROP INDEX NLS_ZHSSTROKE; + +DROP INDEX NLS_ZHSPINYIN; + +DROP TABLE PLAN_TABLE; + + diff --git a/o8demo.sql b/o8demo.sql new file mode 100644 index 0000000..ee1c416 --- /dev/null +++ b/o8demo.sql @@ -0,0 +1,317 @@ +rem +rem $Header: o8demo.sql 30-jan-2003.13:53:32 hyeh Exp $ +rem +rem o8demo.sql +rem +rem Copyright (c) 1996, 2003, Oracle Corporation. All rights reserved. +rem +rem NAME +rem o8demo.sql - Oracle8 demo +rem +rem DESCRIPTION +rem This demo features Oracle8's object extensions, such as, abstract +rem data types (ADTs) and methods. +rem +rem NOTES +rem Schema - +rem A standalone instance of the typed table Orders contains REFs to +rem instances of Companies and SalesReps., and an embedded instance of an +rem order Status. An Order also contains two methods, "totalCost" and +rem "statusSummary". +rem +rem MODIFIED (MM/DD/YY) +rem hyeh 01/30/03 - add ORDER BY to all select +rem hyeh 08/10/99 - use sqlplus syntax +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem yaggarwa 08/06/98 - Add select statements +rem mchien 01/22/98 - name resolution +rem cchau 08/18/97 - enable dictionary protection +rem mchien 05/29/97 - fix type syntax +rem mchien 07/16/96 - Created (adopted from kschultz & dherkime) +rem + +REMARK >>>> Set System Variables For Current SQLPlus Session <<<< +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET PAGESIZE 24 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET DEFINE '^' + +set echo on +connect system/manager + +grant connect,resource, unlimited tablespace to demo8 identified by demo8; +connect demo8/demo8 + +create or replace type product_t AS OBJECT ( + productId number, + productName varchar2(64), + cost number(9,2)); +/ + +create table products of product_t; + +create or replace type salesrep_t AS OBJECT ( + repId number, + repName varchar2(64)); +/ + +create table salesreps of salesrep_t; + +create or replace type company_t AS OBJECT ( + companyId number, + companyName varchar2(64)); +/ + +create table companies of company_t; + +CREATE TABLE tempTot ( + total number, orderID number); + +create table tempResult (result number); + +create table tempStat (status varchar2(64)); + +create or replace type status_t AS OBJECT ( + status varchar2(16), + statusDate date, + comments varchar2(32)); +/ + +create OR REPLACE type order_t AS OBJECT ( + orderId number, + orderDate date, + salesRep ref salesrep_t, + company ref company_t, + status status_t, + MEMBER FUNCTION totalCost RETURN NUMBER, + MEMBER FUNCTION statusSummary RETURN VARCHAR2 + ); +/ + +create table orders of order_t; + +CREATE OR REPLACE TYPE BODY Order_t AS + MEMBER FUNCTION totalCost RETURN NUMBER IS + tot NUMBER; + BEGIN + SELECT total INTO tot + FROM tempTot + WHERE tempTot.orderID = SELF.orderID; + RETURN tot; + END; + MEMBER FUNCTION statusSummary RETURN VARCHAR2 IS + st VARCHAR2(64); + BEGIN + SELECT status INTO st + FROM tempStat; + RETURN st; + END; +END; +/ +show errors +/ + + +create or replace type item_t AS OBJECT ( + itemId number, + quantity number, + product REF product_t, + orderRef ref order_t); +/ + +create table items of item_t; + +insert into products values (101,'ISDN Phone',50.00); +insert into products values (201,'ISDN Switch',5000.00); +insert into products values (301,'100 Yd. Cable',25.00); +insert into products values (401,'Installation Guide',29.95); + +select * from products order by productId; + +insert into salesReps values (16473,'Karl J. Schultz'); +insert into salesReps values (10000,'Don J. Herkimer'); +insert into salesReps values (20000,'Robin A. Wada'); + +select * from salesReps order by repId; + +insert into companies values (1111, 'ABC Graphics, Inc'); +insert into companies values (2222, 'First National Bank'); +insert into companies values (3333, 'United Carbonation, Ltd'); + +select * from companies order by companyId; + +insert into orders values(11,sysdate,NULL,NULL, + status_t('Shipped',TO_DATE('01-JUN-96'),'UPS Ground')); +insert into orders values(12,sysdate,NULL,NULL, + status_t('Pending',TO_DATE('02-JUN-96'),'BO ISDN Switch')); +insert into orders values(13,sysdate,NULL,NULL, + status_t('Shipped',TO_DATE('03-JUN-96'),'UPS Ground')); +insert into orders values(21,sysdate,NULL,NULL, + status_t('On Hold',TO_DATE('04-JUN-96'),'Waiting for PO')); +insert into orders values(22,sysdate,NULL,NULL, + status_t('Pending',TO_DATE('05-JUN-96'),'BO Cable')); +insert into orders values(23,sysdate,NULL,NULL, + status_t('Shipped',TO_DATE('06-JUN-96'),'UPS Ground')); +insert into orders values(31,sysdate,NULL,NULL, + status_t('Shipped',TO_DATE('07-JUN-96'),'UPS Ground')); +insert into orders values(32,sysdate,NULL,NULL, + status_t('Shipped',TO_DATE('08-JUN-96'),'UPS Ground')); +insert into orders values(33,sysdate,NULL,NULL, + status_t('On Hold',TO_DATE('09-JUN-96'),'Waiting for PO')); + +select o.orderId, o.orderDate, + o.status.status, o.status.statusDate, o.status.comments + from orders o order by orderId; + +update orders + set salesrep = (select ref(s) from salesreps s where repId = 16473) + where orderId between 10 and 20; + +update orders + set salesrep = (select ref(s) from salesreps s where repId = 20000) + where orderId between 20 and 30; + +update orders + set salesrep = (select ref(s) from salesreps s where repId = 10000) + where orderId between 30 and 40; + +update orders + set company = (select ref(c) from companies c where companyId = 1111) + where orderId in (11,21,31); + +update orders + set company = (select ref(c) from companies c where companyId = 2222) + where orderId in (12,22,32); + +update orders + set company = (select ref(c) from companies c where companyId = 3333) + where orderId in (13,23,33); + +select o.orderId, o.orderDate, + o.status.status, o.status.statusDate, o.status.comments + from orders o order by orderId; + +select o.orderId, o.orderDate, o.status.status, + o.status.statusDate, o.status.comments, + o.salesRep.repId, o.salesRep.repName, + o.company.companyId, o.company.companyName + from orders o order by orderId; + + +insert into items values(1,100,NULL,NULL); +insert into items values(2,1,NULL,NULL); +insert into items values(3,2,NULL,NULL); +insert into items values(4,3,NULL,NULL); + +insert into items values(5,200,NULL,NULL); +insert into iteMs values(6,2,NULL,NULL); +insert into items values(7,4,NULL,NULL); + +update items + set product = (select ref(p) from products p where productId = 101) + where itemId = 1; + +update items + set product = (select ref(p) from products p where productId = 201) + where itemId = 2; + +update items + set product = (select ref(p) from products p where productId = 301) + where itemId = 3; + +update items + set product = (select ref(p) from products p where productId = 401) + where itemId = 4; + +update items + set product = (select ref(p) from products p where productId = 101) + where itemId = 5; + +update items + set product = (select ref(p) from products p where productId = 201) + where itemId = 6; + +update items + set product = (select ref(p) from products p where productId = 301) + where itemId = 7; + +update items + set orderRef = (select ref(o) from orders o where orderId = 11) + where itemId = 1; + +update items + set orderRef = (select ref(o) from orders o where orderId = 11) + where itemId = 2; + +update items + set orderRef = (select ref(o) from orders o where orderId = 11) + where itemId = 3; + +update items + set orderRef = (select ref(o) from orders o where orderId = 11) + where itemId = 4; + +update items + set orderRef = (select ref(o) from orders o where orderId = 12) + where itemId = 5; + +update items + set orderRef = (select ref(o) from orders o where orderId = 12) + where itemId = 6; + +update items + set orderRef = (select ref(o) from orders o where orderId = 12) + where itemId = 7; + +select i.itemId, i.quantity, + i.product.productId, i.product.productName, i.product.cost, + i.orderRef.orderId, i.orderRef.orderDate, + i.orderRef.status.status, i.orderRef.status.comments, + i.orderRef.salesRep.repId, i.orderRef.salesRep.repName, + i.orderRef.company.companyId, i.orderRef.company.companyName + from items i order by itemId; + +CREATE OR REPLACE PACKAGE utils AS +FUNCTION computeTotalForOrder(ordID NUMBER) RETURN NUMBER; +FUNCTION getStatusForOrder(ordID NUMBER) RETURN VARCHAR2; +END; +/ + +CREATE OR REPLACE PACKAGE BODY utils AS +FUNCTION computeTotalForOrder(ordID NUMBER) RETURN NUMBER IS + anOrder order_t; +BEGIN + anOrder.OrderID := ordID; + RETURN anOrder.totalCost; +End; +FUNCTION getStatusForOrder(ordID NUMBER) RETURN VARCHAR2 IS + anOrder order_t; +BEGIN + anOrder.OrderID := ordID; + RETURN anOrder.statusSummary; +End; +END; +/ +show errors + +commit; + +-- Three-way join required in Oracle7 to do a simple select in Oracle8 +--. +-- SELECT OrderID, SalesReps.repName, Company.companyName, +-- FROM Orders o, SalesReps reps, Companies c, OrderStatuses st +-- WHERE o.ID = 11 AND +-- o.ID = st.OrderID AND +-- o.RepID = reps.ID AND +-- o.CompanyID = c.ID; + +SELECT orderId, o.salesRep.repName, o.company.companyName, o.status.status + FROM Orders o + WHERE o.orderID = 11 order by orderId; + +connect sys/knl_test7 as sysdba; +drop user demo8 cascade; +set echo off diff --git a/o8idemo.sql b/o8idemo.sql new file mode 100644 index 0000000..237ad90 --- /dev/null +++ b/o8idemo.sql @@ -0,0 +1,988 @@ +rem +rem $Header: o8idemo.sql 31-oct-2006.13:40:56 ytsai Exp $ +rem +rem o8idemo.sql +rem +rem Copyright (c) 1998, 2006, Oracle. All rights reserved. +rem +rem NAME +rem o8idemo.sql - Purchase Order example and DDL sample on object view +rem +rem DESCRIPTION +rem This demonstrate the Purchase Order example described in manual +rem Application Developer's Guide +rem and some extra examples on object view DDL +rem +rem NOTES +rem In order to run this sample, the database must be started up with +rem option compatible=8.1.0.0.0 (or a higher compatible value) +rem +rem MODIFIED (MM/DD/YY) +rem ytsai 10/31/06 - fix connect +rem hyeh 01/30/03 - add ORDER BY to all SELECT +rem mchien 11/04/99 - 8.1.6 additions from KOSINSKI +rem hyeh 08/11/99 - set session format +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem hyeh 01/06/99 - use compressed nested iot +rem hyeh 12/22/98 - do not use compressed index - bug 785326, 785403 +rem mkrishna 10/22/98 - add FORCE option for MAKE_REF +rem mchien 10/21/98 - do not use compressed index for now - bug 740405 +rem yaggarwa 10/13/98 - +rem yaggarwa 10/13/98 - Created +rem + +REMARK >>>> Set System Variables For Current SQLPlus Session <<<< +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET PAGESIZE 24 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET DEFINE '^' + +SET ECHO ON +CONNECT system/manager; +DROP USER po CASCADE +/ +GRANT RESOURCE,DBA TO po IDENTIFIED BY po +/ +CONNECT po/po + +CREATE TABLE Customer_reltab ( + Custno NUMBER, -- Customer NUMBER + Custname VARCHAR2(200), -- Customer name + Street VARCHAR2(200), -- Customer Street + City VARCHAR2(200), -- Customer City + State CHAR(2), + Zip VARCHAR2(20), -- Customer Zip + Phone1 VARCHAR2(20), + Phone2 VARCHAR2(20), + Phone3 VARCHAR2(20), + PRIMARY KEY (Custno) + ) +/ +CREATE TABLE PurchaseOrder_reltab ( + PONo NUMBER, -- purchase order no + Custno NUMBER references Customer_reltab , + -- foreign KEY referencing customer + OrderDate DATE, -- Date OF order + ShipDate DATE, -- Date to be shipped + ToStreet VARCHAR2(200), -- shipto Address + ToCity VARCHAR2(200), + ToState CHAR(2), + ToZip VARCHAR2(20), + PRIMARY KEY(PONo) + ) +/ +CREATE TABLE Stock_reltab ( + StockNo NUMBER PRIMARY KEY, + Price NUMBER, + TaxRate NUMBER + ) +/ +CREATE TABLE LineItems_reltab ( + LineItemNo NUMBER, + PONo NUMBER references PurchaseOrder_reltab, + StockNo NUMBER references Stock_reltab, + Quantity NUMBER, + Discount NUMBER, + PRIMARY KEY (PONo,LineItemNo) + ); + + +-- 2. Values Inserted + +INSERT INTO Customer_reltab + VALUES(1,'Jean Nance','2, Avocet Drive','Redwood Shores','CA','95054', + '801-010-0090',NULL,NULL); +INSERT INTO Customer_reltab + VALUES(2,'John Nike','323, College Drive','Edison','NJ','08820', + '901-090-0000','908-201-1002',NULL); +INSERT INTO PurchaseOrder_reltab + VALUES(1001,1,SYSDATE,'10-MAY-1997',NULL,NULL,NULL,NULL); +INSERT INTO PurchaseOrder_reltab + VALUES(2001,2,SYSDATE,'20-MAY-1997','55, Madison Ave','Madison','WI', + '53715'); + +INSERT INTO Stock_reltab VALUES(1004,6750.00,2); +INSERT INTO Stock_reltab VALUES(1011,4500.23,2); +INSERT INTO Stock_reltab VALUES(1534,2234.00,2); +INSERT INTO Stock_reltab VALUES(1535,3456.23,2); + +INSERT INTO LineItems_reltab VALUES(01,1001,1534,12,0) +/ +INSERT INTO LineItems_reltab VALUES(02,1001,1535,10,10) +/ +INSERT INTO LineItems_reltab VALUES(10,2001,1004,1,0) +/ +INSERT INTO LineItems_reltab VALUES(11,2001,1011,2,1) +/ +-- 3. Selection :- + +-- List Customer and Lineitems FOR a given Purchase Order + +SELECT c.Custno, c.Custname, c.Street, c.City, c.State, c.Zip, c.Phone1, + c.Phone2, c.Phone3, + p.PONo, p.OrderDate, + l.StockNo, l.LineItemNo, l.Quantity, l.Discount +FROM Customer_reltab c, PurchaseOrder_reltab p, LineItems_reltab l +WHERE c.Custno = p.Custno AND p.PONo = l.PONo +AND p.PONo = 1001 ORDER BY c.Custno, l.LineItemNo; + +-- List the Total value OF Purchase Orders + +SELECT p.PONo, SUM(s.Price * l.Quantity) +FROM PurchaseOrder_reltab p, LineItems_reltab l, Stock_reltab s +WHERE p.PONo = l.PONo AND l.StockNo = s.StockNo +GROUP BY p.PONo ORDER BY p.PONo; + +-- List all the Purchase Order information and the Line Item information +-- FOR those LineItems_tab that use the stock WITH StockNo 1004 + +SELECT p.PONo, p.Custno, + l.StockNo, l.LineItemNo, l.Quantity, l.Discount +FROM PurchaseOrder_reltab p, LineItems_reltab l +WHERE p.PONo = l.PONo (+) AND + l.StockNo = 1004 +ORDER BY p.PONo, l.LineItemNo; + + +-- ======================================================================== +-- THE OBJECT-RELATIONAL SYSTEM (Oracle 8.0.3) + + +CREATE TYPE StockItem_objtyp +/ + +CREATE TYPE LineItem_objtyp +/ + +CREATE TYPE PurchaseOrder_objtyp +/ + +CREATE TYPE PhoneList_vartyp AS VARRAY(10) OF VARCHAR2(20) +/ + +CREATE TYPE Address_objtyp AS OBJECT ( + Street VARCHAR2(200), + City VARCHAR2(200), + State CHAR(2), + Zip VARCHAR2(20), + + MEMBER PROCEDURE + display + ) +/ + + +CREATE OR REPLACE TYPE Customer_objtyp AS OBJECT ( + Custno NUMBER, + Custname VARCHAR2(200), + Address_obj Address_objtyp, + PhoneList_var PhoneList_vartyp, + + ORDER MEMBER FUNCTION + compareCustOrders(x IN Customer_objtyp) RETURN INTEGER, + + MEMBER PROCEDURE + display + ) +/ + +CREATE TYPE LineItem_objtyp AS OBJECT ( + LineItemNo NUMBER, + Stock_ref REF StockItem_objtyp, + Quantity NUMBER, + Discount NUMBER, + + MEMBER PROCEDURE + display + ) +/ +CREATE TYPE LineItemList_ntabtyp AS TABLE OF LineItem_objtyp +/ +CREATE TYPE PurchaseOrder_objtyp AS OBJECT ( + PONo NUMBER, + Cust_ref REF Customer_objtyp, + OrderDate DATE, + ShipDate DATE, + LineItemList_ntab LineItemList_ntabtyp, + ShipToAddr_obj Address_objtyp, + + MAP MEMBER FUNCTION + getPONo RETURN NUMBER, + + MEMBER FUNCTION + sumLineItems RETURN NUMBER, + + MEMBER PROCEDURE + purchase_item (item NUMBER, + qty NUMBER, + discount NUMBER), + + MEMBER PROCEDURE + update_item (lineno NUMBER, + item NUMBER, + qty NUMBER, + discount NUMBER), + + MEMBER PROCEDURE + display + ) +/ + +CREATE TYPE StockItem_objtyp AS OBJECT ( + StockNo NUMBER, + Price NUMBER, + TaxRate NUMBER + ) +/ + +-- If no relational data exist, and tables need to be created, then create the + +-- following object tables + +CREATE TABLE Customer_objtab OF Customer_objtyp (Custno PRIMARY KEY) + OBJECT ID PRIMARY KEY +/ + +CREATE TABLE Stock_objtab OF StockItem_objtyp (StockNo PRIMARY KEY) + OBJECT ID PRIMARY KEY +/ + +CREATE TABLE PurchaseOrder_objtab OF PurchaseOrder_objtyp + (PRIMARY KEY (PONo), + FOREIGN KEY (Cust_ref) REFERENCES Customer_objtab) + OBJECT ID PRIMARY KEY + NESTED TABLE LineItemList_ntab STORE AS PoLine_ntab( + (PRIMARY KEY(NESTED_TABLE_ID, LineItemNo)) + ORGANIZATION INDEX COMPRESS + ) RETURN AS LOCATOR +/ + +ALTER TABLE PoLine_ntab ADD (SCOPE FOR (Stock_ref) IS stock_objtab); + +-- Following statement creates an INDEX on the internal column +-- "NESTED_TABLE_ID" OF a storage TABLE. +CREATE INDEX Po_nidx on PoLine_ntab (NESTED_TABLE_ID) +/ +-- Insertion OF VALUES -- + +INSERT INTO Stock_objtab VALUES(StockItem_objtyp(1004,6750.00,2)); +INSERT INTO Stock_objtab VALUES(StockItem_objtyp(1011,4500.23,2)); +INSERT INTO Stock_objtab VALUES(StockItem_objtyp(1534,2234.00,2)); +INSERT INTO Stock_objtab VALUES(1535,3456.23,2) +/ +INSERT INTO Customer_objtab + VALUES(1,'Jean Nance', + Address_objtyp('2 Avocet Drive','Redwood Shores','CA','95054'), + PhoneList_vartyp('415-904-0940','408-506-2020')); +INSERT INTO Customer_objtab + VALUES(2,'John Nike', + Address_objtyp('323 College Drive','Edison','NJ','08820'), + PhoneList_vartyp('908-904-0940')); + +INSERT INTO PurchaseOrder_objtab + SELECT 1001,REF(C),SYSDATE,'10-MAY-1997',LineItemList_ntabtyp(),NULL + FROM Customer_objtab C + WHERE C.Custno = 1; + +INSERT INTO PurchaseOrder_objtab + SELECT 2001,REF(C),SYSDATE,'20-MAY-1997', + CAST(MULTISET(SELECT 01, + REF(S), + 12, + 0 + FROM Stock_objtab S + WHERE S.StockNo = 1534) AS LineItemList_ntabtyp), + Address_objtyp('55, Madison Ave','Madison','WI','53715') + FROM Customer_objtab C + WHERE C.Custno = 2; + +INSERT INTO TABLE(SELECT P.LineItemList_ntab + FROM PurchaseOrder_objtab P WHERE P.PONo = 1001) + SELECT 01,REF(S),10,10 FROM Stock_objtab S WHERE S.StockNo = 1535; + +INSERT INTO TABLE(SELECT P.LineItemList_ntab + FROM PurchaseOrder_objtab P WHERE P.PONo = 2001) + SELECT 10,REF(S), 1,0 FROM Stock_objtab S WHERE S.StockNo = 1004; + +INSERT INTO TABLE(SELECT P.LineItemList_ntab + FROM PurchaseOrder_objtab P WHERE P.PONo = 2001 ) + VALUES(LineItem_objtyp( 11,NULL,2,1)) +/ +UPDATE TABLE(SELECT P.LineItemList_ntab + FROM PurchaseOrder_objtab P WHERE P.PONo = 2001) plist + SET plist.Stock_ref = (SELECT REF(S) + FROM Stock_objtab S WHERE S.StockNo = 1011) + WHERE plist.LineItemNo = 11 +/ + + -- Functional definitions +CREATE OR REPLACE TYPE BODY PurchaseOrder_objtyp AS + MEMBER FUNCTION sumLineItems RETURN NUMBER IS + i INTEGER; + StockVal StockItem_objtyp; + LineItem LineItem_objtyp; + Total NUMBER := 0; + + BEGIN + IF (UTL_COLL.IS_LOCATOR(LineItemList_ntab)) + THEN + SELECT SUM(L.Quantity * L.Stock_ref.Price) INTO Total + FROM TABLE(CAST(LineItemList_ntab AS LineItemList_ntabtyp)) L; + ELSE + FOR i IN 1..SELF.LineItemList_ntab.COUNT LOOP + LineItem := SELF.LineItemList_ntab(i); + UTL_REF.SELECT_OBJECT(LineItem.Stock_ref, StockVal); + Total := Total + LineItem.Quantity * StockVal.Price * + (1 - LineItem.Discount/100); + END LOOP; + END IF; + RETURN Total; + END; + + MAP MEMBER FUNCTION getPONo RETURN NUMBER is + BEGIN + RETURN PONo; + END; + + MEMBER PROCEDURE purchase_item (item NUMBER, + qty NUMBER, + discount NUMBER) IS + StockRef REF StockItem_objtyp; + BEGIN + SELECT REF(s) INTO StockRef + FROM Stock_objtab s + WHERE s.StockNo = item; + + LineItemList_ntab.EXTEND; + LineItemList_ntab(LineItemList_ntab.LAST) := + lineitem_objtyp(LineItemList_ntab.LAST, StockRef, qty, discount); + END; + + MEMBER PROCEDURE update_item (lineno NUMBER, + item NUMBER, + qty NUMBER, + discount NUMBER) IS + StockRef REF StockItem_objtyp; + BEGIN + SELECT REF(s) INTO StockRef + FROM Stock_objtab s + WHERE s.StockNo = item; + + LineItemList_ntab(lineno).Stock_ref := StockRef; + LineItemList_ntab(lineno).Quantity := qty; + LineItemList_ntab(lineno).Discount := discount; + END; + + MEMBER PROCEDURE display IS + cust Customer_objtyp; + BEGIN + dbms_output.put_line('Purchase Order ' || pono); + dbms_output.put_line(' '); + SELECT DEREF(Cust_ref) INTO cust FROM DUAL; + cust.display; + IF (ShipToAddr_obj IS NOT NULL) THEN + dbms_output.put_line('Shipping address:'); + ShipToAddr_obj.display; + END IF; + dbms_output.put_line(' '); + dbms_output.put_line('Order date: ' || OrderDate); + dbms_output.put_line('Ship date: ' || ShipDate); + dbms_output.put_line(' '); + dbms_output.put_line('Line Item Quantity Price ' || + 'Discount Extension'); + FOR i IN 1 .. LineItemList_ntab.COUNT LOOP + LineItemList_ntab(i).display; + END LOOP; + dbms_output.put_line(' '); + dbms_output.put_line('Total cost: ' || + to_char(sumLineItems, '$999,999,990.99')); + END; +END; +/ + +CREATE OR REPLACE TYPE BODY Customer_objtyp AS + ORDER MEMBER FUNCTION compareCustOrders (x IN Customer_objtyp) + RETURN INTEGER IS + BEGIN + RETURN Custno - x.Custno; + END; + + MEMBER PROCEDURE display IS + BEGIN + dbms_output.put_line(CustName); + Address_obj.display; + FOR i IN 1 .. PhoneList_var.COUNT LOOP + dbms_output.put_line(PhoneList_var(i)); + END LOOP; + END; +END; +/ + +CREATE OR REPLACE TYPE BODY Address_objtyp AS + MEMBER PROCEDURE display IS + BEGIN + dbms_output.put_line(Street); + dbms_output.put_line(City || ', ' || State || ' ' || Zip); + END; +END; +/ + +CREATE OR REPLACE TYPE BODY LineItem_objtyp AS + MEMBER PROCEDURE display IS + item StockItem_objtyp; + ext NUMBER; + textline VARCHAR2(255); + BEGIN + SELECT DEREF(Stock_Ref) INTO item FROM DUAL; + ext := Quantity * item.Price * (1 - Discount/100); + + textline := to_char(LineItemNo, '999') || ' ' || + to_char(item.StockNo, '0999') || ' ' || + to_char(Quantity, '9999999') || ' ' || + to_char(item.Price, '$99,999.99') || ' ' || + to_char(Discount, '90.99') || '% ' || + to_char(ext, '$999,999.99'); + dbms_output.put_line(textline); + END; +END; +/ + +-- Select the line item list and the Custname FOR each purchase order +SELECT DEREF(p.Cust_ref) CUSTOMER_INFO, + p.ShipToAddr_obj DESTINATION, + p.PONo PURCHASE_ORDER_NUMBER, + p.OrderDate ORDER_DATE, + CURSOR(SELECT LineItemNo, + Quantity, Discount + FROM TABLE(p.LineItemList_ntab) li + ORDER BY LineItemNo) +FROM PurchaseOrder_objtab p +WHERE p.PONo = 1001 +/ + +-- Select the line item list and the Custname FOR each purchase order. +-- Please note this is the same query as above but unnesting feature +-- of Oracle8i has been used using TABLE() operator. +SELECT DEREF(p.Cust_ref) CUSTOMER_INFO, + p.ShipToAddr_obj DESTINATION, + p.PONo PURCHASE_ORDER_NUMBER, + p.OrderDate ORDER_DATE, li.LineItemNo, li.Quantity, li.Discount +FROM PurchaseOrder_objtab p, TABLE(p.LineItemList_ntab) li +WHERE p.PONo = 1001 +ORDER BY p.PONo, li.LineItemNo +/ + +-- Select the Total value FOR each purchse_order +SELECT p.PONo PURCHASE_ORDER_NUMBER, + p.sumLineItems() SUM_LINE_ITEMS +FROM PurchaseOrder_objtab p +ORDER BY p.PONo +/ + +-- Select the line items and the purchase numbers FOR all those poUs having +-- a StockNo 1535 + +SELECT po.PONo PURCHASE_ORDER_NUMBER, + po.Cust_ref.Custno CUSTOMER_NUMBER, + li.LineItemNo LINE_ITEM_NO, + li.Stock_ref.StockNo STOCK_NO, + li.Quantity QUANTITY, + li.Discount DISCOUNT +FROM PurchaseOrder_objtab po, TABLE(po.LineItemList_ntab) li +WHERE li.Stock_ref.StockNo = 1535 +ORDER BY po.PONo, li.LineItemNo +/ + +-- Example of how Varray column can be unnested/flattened in +-- Oracle8i using TABLE() operator. +SELECT p1.custno, p2.* +FROM Customer_objtab p1, TABLE( p1.PhoneList_var)p2 +ORDER BY 1, 2 +/ + +-- USING PL/SQL TO CALL TYPE METHODS -- + +-- Required for DBMS_OUTPUT +SET SERVEROUTPUT ON FORMAT WRAPPED + +-- Display all customer info + +DECLARE + cref REF Customer_objtyp; + cust Customer_objtyp; + CURSOR cr IS SELECT REF(c) FROM Customer_objtab c ORDER BY Custname; +BEGIN + OPEN cr; + LOOP + FETCH cr INTO cref; + EXIT WHEN cr%NOTFOUND; + UTL_REF.SELECT_OBJECT(cref, cust); + cust.display; + dbms_output.put_line(' '); + END LOOP; + CLOSE cr; +END; +/ + +-- Display purchase order + +CREATE OR REPLACE PROCEDURE display_order (ponum NUMBER) IS + poref REF PurchaseOrder_objtyp; + po PurchaseOrder_objtyp; +BEGIN + SELECT REF(p) INTO poref FROM PurchaseOrder_objtab p WHERE p.pono = ponum; + UTL_REF.SELECT_OBJECT(poref, po); + po.display; +END; +/ + +BEGIN + display_order(1001); +END; +/ + +-- Add to purchase order +-- This procedure uses the LOCK_OBJECT and UPDATE_OBJECT procedures in +-- package UTL_REF to modify the nested table of line items + +CREATE OR REPLACE PROCEDURE add_item (ponum NUMBER, stockno NUMBER, + qty NUMBER, discount NUMBER) IS + poref REF PurchaseOrder_objtyp; + po PurchaseOrder_objtyp; +BEGIN + SELECT REF(p) INTO poref + FROM PurchaseOrder_objtab p + WHERE p.pono = ponum; + + UTL_REF.LOCK_OBJECT(poref, po); + po.purchase_item(stockno, qty, discount); + UTL_REF.UPDATE_OBJECT(poref, po); +END; +/ + +BEGIN + add_item(1001, 1534, 6, 20); + display_order(1001); +END; +/ + +-- Change a line item +-- This procedure updates the line items list using SQL instead of UTL_REF. + +CREATE OR REPLACE PROCEDURE change_item (ponum NUMBER, lineno NUMBER, + stockno NUMBER, qty NUMBER, + discount NUMBER) IS + poref REF PurchaseOrder_objtyp; + po PurchaseOrder_objtyp; +BEGIN + SELECT REF(p) INTO poref + FROM PurchaseOrder_objtab p + WHERE p.pono = ponum + FOR UPDATE OF p.LineItemList_ntab; + + UTL_REF.SELECT_OBJECT(poref, po); + po.update_item(lineno, stockno, qty, discount); + + UPDATE PurchaseOrder_objtab p + SET p.LineItemList_ntab = po.LineItemList_ntab + WHERE p.pono = ponum; +END; +/ + +BEGIN + change_item(1001, 1, 1011, 7, 35); + display_order(1001); +END; +/ + +-- Object Views +-- If relational schema exists WITH relational tables containing the +-- purchase order, lineitem and customer data, then objects may be +-- materialized from the relational data WITH the help of object views. + +CREATE OR REPLACE VIEW Customer_objview OF Customer_objtyp + WITH OBJECT OID(Custno) + AS SELECT C.Custno, + C.Custname, + Address_objtyp(C.Street,C.City,C.State,C.Zip), + PhoneList_vartyp(Phone1,Phone2,Phone3) + FROM Customer_reltab C +/ +CREATE OR REPLACE VIEW Stock_objview OF StockItem_objtyp + WITH OBJECT OID(StockNo) + AS SELECT * + FROM Stock_reltab +/ +CREATE OR REPLACE VIEW PurchaseOrder_objview OF PurchaseOrder_objtyp + WITH OBJECT OID (PONo) + AS SELECT P.PONo, + MAKE_REF(Customer_objview,P.Custno), + P.OrderDate, + P.ShipDate, + CAST( + MULTISET(SELECT LineItem_objtyp(L.LineItemNo, + MAKE_REF(Stock_objview,L.StockNo), + L.Quantity, + L.Discount) + FROM LineItems_reltab L + WHERE L.PONo= P.PONo) + AS LineItemList_ntabtyp), + Address_objtyp(P.ToStreet,P.ToCity,P.ToState,P.ToZip) + FROM PurchaseOrder_reltab P +/ +------- +-- Since OBJECT views queries are complex making them inherently non-updatable, +-- Instead-OF triggers may be specified FOR them to make them updatable. +-- For example, the following creates an INSTEAD-OF TRIGGER on the +-- PurchaseOrder_tab VIEW +-- which encapsulates the semantics of inserting into that view. +CREATE OR REPLACE TRIGGER POView_instdinserttr + INSTEAD OF INSERT on PurchaseOrder_objview +DECLARE + LineItems_ntab LineItemList_ntabtyp; + i INTEGER; + CustVar_obj Customer_objtyp; + StockVar_obj StockItem_objtyp; + StockVarTemp_ref REF StockItem_objtyp; + +BEGIN + LineItems_ntab := :new.LineItemList_ntab; + UTL_REF.SELECT_OBJECT(:new.Cust_ref, CustVar_obj); + INSERT INTO PurchaseOrder_reltab + VALUES(:new.PONo,CustVar_obj.Custno,:new.OrderDate,:new.ShipDate, + :new.ShipToAddr_obj.Street,:new.ShipToAddr_obj.City, + :new.ShipToAddr_obj.State,:new.ShipToAddr_obj.Zip) ; + + FOR i in 1..LineItems_ntab.count LOOP + UTL_REF.SELECT_OBJECT(LineItems_ntab(i).Stock_ref, StockVar_obj); + INSERT INTO LineItems_reltab + VALUES(LineItems_ntab(i).LineItemNo,:new.PONo,StockVar_obj.StockNo, + LineItems_ntab(i).Quantity,LineItems_ntab(i).Discount); + END LOOP; +END; +/ + +CREATE OR REPLACE TRIGGER POLineItems_instdinsertr + INSTEAD OF INSERT ON NESTED TABLE LineItemList_ntab OF PurchaseOrder_objview +DECLARE + StockVar StockItem_objtyp; +BEGIN + UTL_REF.SELECT_OBJECT(:NEW.Stock_ref, StockVar); + INSERT INTO LineItems_reltab + VALUES (:NEW.LineItemNo, :PARENT.PONo, StockVar.StockNo, :NEW.Quantity, + :NEW.Discount); +END; +/ +CREATE OR REPLACE TRIGGER POLineItems_instddeltr + INSTEAD OF DELETE ON NESTED TABLE LineItemList_ntab OF PurchaseOrder_objview +BEGIN + DELETE FROM LineItems_reltab + WHERE LineItemNo = :OLD.LineItemNo AND PONo = :PARENT.PONo; +END; +/ + + +CREATE OR REPLACE TRIGGER CustView_instdinserttr + INSTEAD OF INSERT on Customer_objview +DECLARE + Phones_var PhoneList_vartyp; + TPhone1 Customer_reltab.Phone1%TYPE := NULL; + TPhone2 Customer_reltab.Phone2%TYPE := NULL; + TPhone3 Customer_reltab.Phone3%TYPE := NULL; +BEGIN + Phones_var := :new.PhoneList_var; + IF Phones_var.COUNT > 2 then + TPhone3 := Phones_var(3); + END IF; + IF Phones_var.COUNT > 1 then + TPhone2 := Phones_var(2); + END IF; + IF Phones_var.COUNT > 0 then + TPhone1 := Phones_var(1); + END IF; + INSERT INTO Customer_reltab + VALUES(:new.Custno,:new.Custname,:new.Address_obj.Street, + :new.Address_obj.City,:new.Address_obj.State, + :new.Address_obj.Zip, + TPhone1,TPhone2,TPhone3); +END; +/ + +CREATE OR REPLACE TRIGGER StockView_instdinsertr + INSTEAD OF INSERT on Stock_objview +BEGIN + INSERT INTO Stock_reltab + VALUES(:new.StockNo,:new.Price,:new.TaxRate); +END; +/ + +INSERT INTO Customer_objview + VALUES (13,'Ellan White', + Address_objtyp('25, I Street','memphis','TN','05456'), + PhoneList_vartyp('901-000-0000')); +COMMIT +/ + +INSERT INTO PurchaseOrder_objview + SELECT 3001, REF(c),SYSDATE,SYSDATE, + CAST(MULTISET(SELECT LineItem_objtyp(41, REF(S),20,1) + FROM Stock_objview S WHERE S.StockNo = 1535) + AS LineItemList_ntabtyp), + Address_objtyp('22 Nothingame Ave','Cockstown','AZ','44045') + FROM Customer_objview c + WHERE c.Custno = 1 +/ + +DELETE FROM TABLE(SELECT p.LineItemList_ntab + FROM PurchaseOrder_objview p + WHERE p.PONo = 3001) L +WHERE L.LineItemNo = 41 +/ +INSERT INTO TABLE(SELECT p.LineItemList_ntab + FROM PurchaseOrder_objview p + WHERE p.PONo = 3001) + SELECT LineItem_objtyp(41, REF(S),20,1) + FROM Stock_objview S WHERE S.StockNo = 1535 +/ + +SELECT DEREF(p.Cust_ref) CUSTOMER_INFO, + p.ShipToAddr_obj DESTINATION, + p.PONo PURCHASE_ORDER_NUMBER, + p.OrderDate ORDER_DATE, + CURSOR(SELECT LineItemNo, + Quantity, Discount + FROM TABLE(p.LineItemList_ntab) li + ORDER BY LineItemNo) +FROM PurchaseOrder_objview p +WHERE p.PONo = 1001 +/ + +-- Please note this is the same query as above but unnesting feature +-- of Oracle8i has been used using TABLE() operator. +SELECT DEREF(p.Cust_ref) CUSTOMER_INFO, + p.ShipToAddr_obj DESTINATION, + p.PONo PURCHASE_ORDER_NUMBER, + p.OrderDate ORDER_DATE, li.LineItemNo, li.Quantity, li.Discount +FROM PurchaseOrder_objview p, TABLE(p.LineItemList_ntab) li +WHERE p.PONo = 1001 +ORDER BY li.LineItemNo +/ + +-- Select the TotalSELF value FOR each purchse_order +SELECT p.PONo,p.sumLineItems () FROM PurchaseOrder_objview p +ORDER BY p.PONo +/ + +-- SELECT the lineitems and the purchase order numbers +-- returning the linitems as a nested cursor +SELECT po.PONo PURCHASE_ORDER_NUMBER, + po.Cust_ref.Custno CUSTOMER_NUMBER, + CURSOR(SELECT * + FROM TABLE(po.LineItemList_ntab) li + WHERE li.Stock_ref.StockNo = 1535 + ORDER BY LineItemNo) +FROM PurchaseOrder_objview po +ORDER BY PONo +/ + +-- Please note this is the same query as above but unnesting feature +-- of Oracle8i has been used using TABLE() operator. +SELECT po.PONo PURCHASE_ORDER_NUMBER, + po.Cust_ref.Custno CUSTOMER_NUMBER, li.* +FROM PurchaseOrder_objview po, TABLE(po.LineItemList_ntab) li +WHERE li.Stock_ref.StockNo = 1535 +ORDER BY po.PONo, li.LineItemNo; + +-- Select the line items and the purchase numbers FOR all those poUs having +-- a StockNo 1535 + +SELECT po.PONo PURCHASE_ORDER_NUMBER, + po.Cust_ref.Custno CUSTOMER_NUMBER, + li.LineItemNo LINEITEM_NUMBER, + li.Quantity QUANTITY +FROM PurchaseOrder_objview po, TABLE(po.LineItemList_ntab) li +WHERE li.Stock_ref.StockNo = 1535 +ORDER BY po.PONo, li.LineItemNo +/ + +-- Select the Total value FOR each purchse_order +SELECT p.PONo PURCHASE_ORDER_NUMBER, + p.sumLineItems() SUM_LINE_ITEMS +FROM PurchaseOrder_objtab p +ORDER BY PONo +/ + +COMMIT +/ + +CONNECT system/manager +DROP USER po CASCADE +/ + +/* demonstrate creating object views using MAKE_REF and also self-referencing + view */ + +CONNECT system/manager +DROP USER fnd CASCADE; + +GRANT CONNECT, RESOURCE TO fnd IDENTIFIED BY fnd; + +CONNECT fnd/fnd + +CREATE TABLE fnd_application ( + application_id NUMBER PRIMARY KEY, + application_short_name VARCHAR2(50) NOT NULL, + application_name VARCHAR2(240) +); + +CREATE TABLE fnd_form_functions( + function_id NUMBER PRIMARY KEY, + function_name VARCHAR2(30) NOT NULL, + application_id NUMBER, + form_id NUMBER, + parameters VARCHAR2(2000) +); + +CREATE TABLE fnd_menus ( + menu_id NUMBER PRIMARY KEY, + menu_name VARCHAR2(30) NOT NULL +); + +CREATE TABLE fnd_form_vl ( + application_id NUMBER PRIMARY KEY, + form_id NUMBER NOT NULL, + form_name VARCHAR2(30) NOT NULL, + AUDIT_ENABLED_FLAG VARCHAR2(1) NOT NULL, + user_form_name VARCHAR2(80) NOT NULL, + description VARCHAR2(240) +); + +CREATE TABLE fnd_form_functions_vl ( + function_id NUMBER PRIMARY KEY, + function_name VARCHAR2(30) NOT NULL, + application_id NUMBER, + form_id NUMBER, + parameters VARCHAR2(2000), + type VARCHAR2(30), + user_function_name VARCHAR2(80) NOT NULL, + description VARCHAR2(240) +); + + +CREATE TABLE fnd_menu_entries_vl ( + menu_id NUMBER PRIMARY KEY, + entry_sequence NUMBER NOT NULL, + sub_menu_id NUMBER, + function_id NUMBER, + prompt VARCHAR2(30), + description VARCHAR2(240) +); + + +CREATE TABLE fnd_menus_vl ( + menu_id NUMBER PRIMARY KEY, + menu_name VARCHAR2(30) NOT NULL, + user_menu_name VARCHAR2(80) NOT NULL, + description VARCHAR2(240) +); + + +CREATE TYPE fnd_application_t AS OBJECT +( + application_short_name varchar2(50), + application_name varchar2(240) +) +/ + +CREATE OR REPLACE VIEW + fnd_application_object_view OF fnd_application_t + WITH OBJECT OID(application_short_name) AS + SELECT application_short_name, application_name + FROM fnd_application; + +CREATE TYPE fnd_form_t AS OBJECT +( + form_name VARCHAR2(30), + application REF fnd_application_t, + user_form_name varchar2(80), + description varchar2(240) +) +/ + +CREATE OR REPLACE VIEW + fnd_form_view OF fnd_form_t + WITH OBJECT OID(form_name) AS + SELECT F.form_name, + MAKE_REF(fnd_application_object_view, A.application_short_name), + F.user_form_name, F.description + FROM fnd_form_vl F, fnd_application A + WHERE F.application_id = A.application_id; + +CREATE TYPE fnd_function_t AS OBJECT +( + function_name varchar2(30), + form REF fnd_form_t, + type varchar2(30), + parameters varchar2(2000), + user_function_name varchar2(80), + description varchar2(240) +) +/ + +CREATE OR REPLACE VIEW + fnd_function_object_view OF fnd_function_t + WITH OBJECT OID(function_name) AS + SELECT N.function_name, + MAKE_REF(fnd_form_view, F.form_name), + N.type, N.parameters, N.user_function_name, N.description + FROM fnd_form_functions_vl N, fnd_form_vl F + WHERE N.form_id = F.form_id; + +CREATE TYPE fnd_menu_t +/ + +CREATE TYPE fnd_menu_entry_t AS OBJECT +( + entry_sequence number, + prompt varchar2(30), + description varchar2(240), + submenu REF fnd_menu_t, + function REF fnd_function_t +) +/ + +CREATE TYPE fnd_menu_entry_list_t AS TABLE OF fnd_menu_entry_t +/ + +CREATE TYPE fnd_menu_t AS OBJECT +( + menu_name varchar2(30), + user_menu_name varchar2(80), + description varchar2(240), + entries fnd_menu_entry_list_t +) +/ + +/* create self-reference view */ +CREATE OR REPLACE FORCE VIEW + fnd_menu_object_view OF fnd_menu_t + WITH OBJECT OID(menu_name) AS + SELECT M.menu_name, M.user_menu_name, M.description, + CAST( + MULTISET( + SELECT fnd_menu_entry_t( + Q.entry_sequence, Q.prompt, Q.description, + MAKE_REF(fnd_menu_object_view, S.menu_name), NULL) + FROM fnd_menu_entries_vl Q, fnd_menus S + WHERE Q.menu_id = M.menu_id AND Q.sub_menu_id = S.menu_id + ) + AS fnd_menu_entry_list_t) + FROM fnd_menus_vl M; + +CONNECT system/manager; +DROP USER fnd CASCADE +/ +SET ECHO OFF diff --git a/obndra.c b/obndra.c new file mode 100644 index 0000000..0d4cad8 --- /dev/null +++ b/obndra.c @@ -0,0 +1,218 @@ +#ifdef RCSID +static char *RCSid = + "$Header: obndra.c 04-apr-2005.17:13:10 lzhao Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1991, 2005, Oracle. All rights reserved. +*/ + +/* + NAME + obndra.c - + DESCRIPTION + + PUBLIC FUNCTION(S) + + PRIVATE FUNCTION(S) + + RETURNS + + NOTES + + MODIFIED (MM/DD/YY) + lzhao 04/04/05 - bug4184457 + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + azhao 03/21/97 - drop table part_nos at the end + rkooi2 11/28/92 - Creation +*/ + +/* Example program demonstrating an array insert using the obndra + example from Chapter 4 of the OCI Programmer's Guide. */ + +#include +#include +#include +#include +#include + +Cda_Def cda; +Lda_Def lda; + + +/* set up the table */ +text *dt = (text *) "DROP TABLE part_nos"; +text *ct = (text *) "CREATE TABLE part_nos (partno NUMBER, description\ + VARCHAR2(20))"; + +text *cp = (text *) "\ + CREATE OR REPLACE PACKAGE update_parts AS\ + TYPE part_number IS TABLE OF part_nos.partno%TYPE\ + INDEX BY BINARY_INTEGER;\ + TYPE part_description IS TABLE OF part_nos.description%TYPE\ + INDEX BY BINARY_INTEGER;\ + PROCEDURE add_parts (n IN INTEGER,\ + descrip IN part_description,\ + partno IN part_number);\ + END update_parts;"; + +text *cb = (text *) "\ + CREATE OR REPLACE PACKAGE BODY update_parts AS\ + PROCEDURE add_parts (n IN INTEGER,\ + descrip IN part_description,\ + partno IN part_number) is\ + BEGIN\ + FOR i IN 1..n LOOP\ + INSERT INTO part_nos\ + VALUES (partno(i), descrip(i));\ + END LOOP;\ + END add_parts;\ + END update_parts;"; + + +#define DESC_LEN 20 +#define MAX_TABLE_SIZE 1200 + +text *pl_sql_block = (text *) "\ + BEGIN\ + update_parts.add_parts(3, :description, :partno);\ + END;"; + +text descrip[3][20] = {"Frammis", "Widget", "Thingie"}; +sword numbers[] = {12125, 23169, 12126}; + +ub2 descrip_alen[3] = {DESC_LEN, DESC_LEN, DESC_LEN}; +ub2 descrip_rc[3]; +ub4 descrip_cs = (ub4) 3; +ub2 descrip_indp[3]; + +ub2 num_alen[3] = {(ub2) sizeof (sword), + (ub2) sizeof (sword), + (ub2) sizeof (sword)}; +ub2 num_rc[3]; +ub4 num_cs = (ub4) 3; +ub2 num_indp[3]; + +dvoid oci_error(void); + +main() +{ + printf("Connecting to ORACLE..."); + if (olon(&lda, (oratext *)"scott/tiger", -1, NULL, -1, -1)) { + printf("Cannot logon as scott/tiger. Exiting...\n"); + exit(1); + } + + if (oopen(&cda, &lda, NULL, -1, -1, NULL, -1)) { + printf("Cannot open cursor, exiting...\n"); + + exit(1); + } + + /* Drop the table. */ + printf("\nDropping table..."); + if (oparse(&cda, dt, -1, 0, 2)) + if (cda.rc != 942) + oci_error(); + printf("\nCreating table..."); + if (oparse(&cda, ct, -1, 0, 2)) + oci_error(); + + /* Parse and execute the create + package statement. */ + printf("\nCreating package..."); + if (oparse(&cda, cp, -1, 0, 2)) + oci_error(); + if (oexec(&cda)) + oci_error(); + + /* Parse and execute the create + package body statement. */ + printf("\nCreating package body..."); + if (oparse(&cda, cb, -1, 0, 2)) + oci_error(); + if (oexec(&cda)) + oci_error(); + + /* Parse the anonymous PL/SQL block + that calls the stored procedure. */ + printf("\nParsing PL/SQL block..."); + if (oparse(&cda, pl_sql_block, -1, 0, 2)) + oci_error(); + + /* Bind the C arrays to the PL/SQL tables. */ + printf("\nBinding arrays..."); + if (obndra(&cda, + (text *) ":description", + -1, + (ub1 *) descrip, + DESC_LEN, + VARCHAR2_TYPE, + -1, + (sb2 *)descrip_indp, + descrip_alen, + descrip_rc, + (ub4) MAX_TABLE_SIZE, + &descrip_cs, + (text *) 0, + -1, + -1)) + oci_error(); + + if (obndra(&cda, + (text *) ":partno", + -1, + (ub1 *) numbers, + (sword) sizeof (sword), + INT_TYPE, + -1, + (sb2 *)num_indp, + num_alen, + num_rc, + (ub4) MAX_TABLE_SIZE, + &num_cs, + (text *) 0, + -1, + -1)) + oci_error(); + + printf("\nExecuting block..."); + if (oexec(&cda)) + oci_error(); + + /* drop table part_nos */ + if (oparse(&cda, dt, -1, 0, 2)) + oci_error(); + + printf("\n"); + if (oclose(&cda)) + { + printf("Error closing cursor!\n"); + return -1; + } + + if (ologof(&lda)) + { + printf("Error logging off!\n"); + return -1; + } + exit(1); +} + + +dvoid +oci_error(void) +{ + text msg[600]; + sword rv; + + rv = oerhms(&lda, (sb2)cda.rc, msg, 600); + + printf("\n\n%.*s", rv, msg); + printf("Processing OCI function %s\n", oci_func_tab[cda.fc]); + if (oclose(&cda)) + printf("Error closing cursor!\n"); + if (ologof(&lda)) + printf("Error logging off!\n"); + exit(1); +} + diff --git a/occiaqlis.cpp b/occiaqlis.cpp new file mode 100644 index 0000000..6b48202 --- /dev/null +++ b/occiaqlis.cpp @@ -0,0 +1,124 @@ +/* Copyright (c) 2003, 2009, Oracle and/or its affiliates. +All rights reserved. */ +/* + NAME + occiaqlis.cpp - OCCI AQ listener functionality demo + + DESCRIPTION + This demo program explains the use of listener class of advanced + queueing in occi. + This functionality aims at listening on behalf of a bunch of agents + which are specified on 1 or more queues, and return the agent + for whom a message has arrived. + The listen() call listens on one or more queues on behalf + of a list of agents. + This call returns the agent for which there is a message. + Prior to this call, the list of agents on behalf to listen to must been set + This is a blocking call that returns when there is a message ready for + consumption for an agent in the list. + If there are no messages found when the wait time expires, + an error is returned. + + MODIFIED (MM/DD/YY) + sudsrini 07/08/09 - Include string.h, iostream not including it on sles11 + sudsrini 10/22/06 - Username/Password lower case + sudsrini 07/22/04 - Copyright info + sprabhak 03/05/03 - Creation + +*/ + +#include +#include +#include +#include + +using namespace std; +using namespace oracle::occi; +using namespace oracle::occi::aq; + +void test_enqueue(Environment *env, Connection *conn) +{ + cout<<"Enqueuing the message into the queue"<commit(); + cout<<"Enqueue done"< agList; + + agList.push_back(Agent(env, "AGT1", "hr.queue04")); + agList.push_back(Agent(env, "AGT2", "hr.queue04")); + // The listener is to listen for the above 2 agents. + l.setAgentList(agList); + l.setTimeOutForListen(10); + + cout<<"Listening..."<createConnection("hr","hr"); + test_enqueue(env, con); + test_listener(env, con); + env->terminateConnection(con); + } + catch(SQLException &ex) + { + cout<<"Exception thrown "< +#include +#include +#include "occiaqopm.h" + +using namespace oracle::occi; +using namespace std; +using namespace oracle::occi::aq; + +Environment *env; + +void test_raw(Connection *conn); +void test_raw_enqueue(Connection *conn); +void test_raw_dequeue(Connection *conn); +void test_anydata(Connection *conn); +void test_anydata_enqueue(Connection *conn); +void test_anydata_dequeue(Connection *conn); +void test_adt(Connection *conn); +void test_adt_enqueue(Connection *conn); +void test_adt_dequeue(Connection *conn); + +int main (void) +{ + try + { + env = Environment::createEnvironment (Environment::OBJECT); + cout<<"Demo for advanced queuing enqueue/dequeue"<createConnection("hr","hr"); + //Testing AQ operations on raw message + test_raw(conn); + //Testing AQ operations on anydata message + test_anydata(conn); + //Testing AQ operations on adt message + test_adt(conn); + env->terminateConnection(conn); + Environment::terminateEnvironment (env); + cout<<"Demo for advanced queueing enqueue/dequeue done"< list; + Agent a1(env); + a1.setName("AGT"); + a1.setAddress("hr.queue02"); + a1.setProtocol(0); + + //String functions + string in_str1("ANYDATA-MSG"); + any1.setFromString(in_str1); + cout << "Message before enqueue:" << in_str1 << endl; + + //Set the payload + m1.setAnyData(any1); + + //Setting the Recipient list + list.push_back(a1); + m1.setRecipientList(list); + + //Enqueue the message + Producer prod(conn); + prod.setVisibility(Producer::ENQ_ON_COMMIT); + Bytes by_enq=prod.send(m1, "hr.queue02"); + conn->commit(); + cout<<"Enqueue of anydata message done"<setA1 (a1); + obj->setA2 (a2); + m1.setObject(obj); + Producer prod(conn); + cout << "Object data before enqueue " << endl; + cout<<"A1: "<<(int)obj->getA1()<getA2 () << endl; + prod.send(m1, "hr.queue03"); + delete (obj); + cout<<"Enqueue of adt message done"<getA1()<getA2 () << endl; + delete(obnew1); + cout<<"Dequeue of adt message done"< +#include +#include +#include +using namespace oracle::occi; +using namespace std; + +/** + * The demo sample has starts from startDemo method. This method is called + * by main. startDemo calls other methods, the supporting methods for + * startDemo are, + * insertRows - insert the rows into the table + * dataRollBack - deletes the inserted rows + * populateBlob - populates a given blob + * dumpBlob - prints the blob as an integer stream + */ +// These will tell the type of read/write we use +#define USE_NORM 1 +#define USE_CHUN 2 +#define USE_BUFF 3 + +/* Buffer Size */ +#define BUFSIZE 200; + +class occiBlob +{ + public: + string username; + string password; + string url; + + void insertRows (Connection *conn) + throw (SQLException) + { + Statement *stmt = conn->createStatement ("INSERT INTO electronic_media(product_id,ad_id,ad_composite,ad_sourcetext) VALUES (:v1,:v2,:v3,:v4)"); + Blob blob(conn); + blob.setEmpty(); + Clob clob(conn); + clob.setEmpty(); + stmt->setInt(1,6666); + stmt->setInt(2,11001); + stmt->setBlob(3,blob); + stmt->setClob(4,clob); + stmt->executeUpdate(); + stmt->setSQL ("INSERT INTO electronic_media(product_id,ad_id,ad_composite,ad_sourcetext) VALUES (:v1, :v2, :v3, :v4)"); + stmt->setInt(1,7777); + stmt->setInt(2,11001); + stmt->setBlob(3,blob); + stmt->setClob(4,clob); + stmt->executeUpdate(); + stmt->setSQL ("INSERT INTO electronic_media(product_id,ad_id,ad_composite,ad_sourcetext) VALUES (:v1, :v2, :v3, :v4)"); + stmt->setInt(1,8888); + stmt->setInt(2,11001); + stmt->setBlob(3,blob); + stmt->setClob(4,clob); + stmt->executeUpdate(); + conn->commit(); + conn->terminateStatement (stmt); + + } + + void dataRollBack (Connection *conn) + throw (SQLException) + { + Statement *stmt = conn->createStatement ("DELETE FROM electronic_media WHERE product_id=6666 AND ad_id=11001"); + stmt->executeUpdate(); + stmt->setSQL("DELETE FROM electronic_media WHERE product_id=7777 AND ad_id=11001"); + stmt->executeUpdate(); + stmt->setSQL("DELETE FROM electronic_media WHERE product_id=8888 AND ad_id=11001"); + stmt->executeUpdate(); + conn->commit(); + conn->terminateStatement (stmt); + + } + + /** + * populating the blob uses write method; + */ + void populateBlob (Blob &blob,unsigned int way,unsigned int size=0) + throw (SQLException) + { + if (way == USE_NORM) + { + cout << "Populating the Blob using write method" << endl; + unsigned int offset=1; + unsigned char *buffer = new unsigned char[size]; + memset (buffer, (char)10, size); + unsigned int bytesWritten=blob.write (size,buffer, size,offset); + //cout <<"Bytes Written : " << bytesWritten << endl; + delete[] buffer; + } + else if(way==USE_CHUN) + { + cout << "Populating the Blob using writeChunk method" << endl; + unsigned int offset=1; + unsigned int pieceCount = 4; + unsigned char *buffer = new unsigned char[size*pieceCount]; + memset (buffer, (char)10, size*pieceCount); + // Open the blob for writeChunk + blob.open(OCCI_LOB_READWRITE); + for (int i = 0; i < pieceCount; ++i,offset+=size) + blob.writeChunk(size,buffer,size,offset); + cout << "Blob Size " << blob.length() << endl; + delete[] buffer; + blob.close(); + } + else if(way==USE_BUFF) + { + // Uses stream here + unsigned int size; + unsigned int bufsize=BUFSIZE; + cout << "Populating the Blob using writeBuffer(Stream) method" << endl; + char *file = (char *)"blobdemo.dat"; + char *buffer = new char[bufsize]; + ifstream inFile; + inFile.open(file,ios::in); + if (!inFile) + { + cout << "blobdemo.dat file not found\n"; + delete[] buffer; + return; + } + Stream *strm=blob.getStream(); + while(inFile) + { + memset (buffer, NULL, bufsize); + inFile.read(buffer,bufsize); + strm->writeBuffer(buffer,strlen(buffer)); + } + strcpy(buffer,"This piece for writeLastBuffer"); + size=strlen(buffer); + strm->writeLastBuffer(buffer,size); + blob.closeStream(strm); + inFile.close(); + delete[] buffer; + } + cout << "Populating the Blob - Success" << endl; + } + + /** + * printing the blob data as integer stream + */ + void dumpBlob (Blob &blob,unsigned int way) + throw (SQLException) + { + unsigned int size=BUFSIZE; + if (blob.isNull()) + { + cout << "Blob is Null\n"; + return; + } + unsigned int offset= 1,bloblen = blob.length(); + cout << "Length of Blob : "<< bloblen << endl; + if (bloblen == 0) + return; + unsigned char *buffer= new unsigned char[size]; + memset (buffer, NULL, size); + if (way==USE_NORM) + { + cout << "Dumping blob (using read ): "; + int bytesRead=blob.read(bloblen,buffer,bloblen,offset); + for (int i = 0; i < bytesRead; ++i) + cout << (int) buffer[i]; + cout << endl; + } + else if(way==USE_BUFF) + { + Stream *inStream = blob.getStream (1,0); + cout << "Dumping blob(using stream): "; + int bytesRead=(inStream->readBuffer((char *)buffer, size)); + while (bytesRead > 0) + { + for (int i = 0; i < bytesRead; ++i) + { + cout << (int) buffer[i]; + } + bytesRead=(inStream->readBuffer((char *)buffer, size)); + } + cout << endl; + blob.closeStream (inStream); + } + delete []buffer; + } + + occiBlob () + { + /** + * default values of username & password + */ + username = "hr"; + password = "hr"; + url = ""; + } + + void setUsername (string u) + { + username = u; + } + + void setPassword (string p) + { + password = p; + } + + void setUrl (string u) + { + url = u; + } + + void runSample () + throw (SQLException) + { + Environment *env = Environment::createEnvironment ( + Environment::DEFAULT); + Connection *conn = env->createConnection (username, password, url); + insertRows (conn); + + // Selecting and modifying the blob column of the table + string sqlQuery = + "SELECT product_id,ad_id,ad_composite FROM electronic_media FOR UPDATE"; + Statement *stmt1 = conn->createStatement (sqlQuery); + ResultSet *rset1 = stmt1->executeQuery (); + cout << "Query :" << sqlQuery << endl; + unsigned int way=USE_NORM; + while (rset1->next ()) + { + cout << "Product_id : " << (int)rset1->getInt(1) << endl; + cout << "Ad_id : " << (int)rset1->getInt(2) << endl; + Blob blob = rset1->getBlob (3); + dumpBlob (blob, USE_NORM); + if (way==USE_NORM) + { + populateBlob(blob,USE_NORM,20); + way=USE_CHUN; + } + else if(way==USE_CHUN) + { + populateBlob(blob,USE_CHUN,20); + way=USE_BUFF; + } + else if(way==USE_BUFF) + { + populateBlob(blob,USE_BUFF); + way=USE_NORM; + } + } + stmt1->executeUpdate(); + stmt1->closeResultSet (rset1); + + // Printing after updating the blob content. + way = USE_BUFF; + sqlQuery = "SELECT product_id, ad_id, ad_composite FROM electronic_media \ +ORDER BY product_id"; + Statement *stmt2 = conn->createStatement (sqlQuery); + ResultSet *rset2 = stmt2->executeQuery (); + cout << "Query :" << sqlQuery << endl; + while (rset2->next ()) + { + cout << "Product_id : " << (int)rset2->getInt(1) << endl; + cout << "Ad_id : " << (int)rset2->getInt(2) << endl; + Blob blob = rset2->getBlob (3); + if (way==USE_NORM) + { + dumpBlob (blob, USE_NORM); + way=USE_BUFF; + } + else if(way==USE_BUFF) + { + dumpBlob (blob, USE_BUFF); + way=USE_NORM; + } + } + stmt2->closeResultSet (rset2); + + dataRollBack(conn); + + conn->terminateStatement (stmt1); + conn->terminateStatement (stmt2); + env->terminateConnection (conn); + Environment::terminateEnvironment (env); + } + +};//end of class occiBlob + +int main (void) +{ + try + { + occiBlob *b = new occiBlob (); + b->setUsername ("hr"); + b->setPassword ("hr"); + b->runSample (); + delete(b); + } + catch (exception &e) + { + cout << e.what(); + } +} + diff --git a/occiclob.cpp b/occiclob.cpp new file mode 100644 index 0000000..2be18ed --- /dev/null +++ b/occiclob.cpp @@ -0,0 +1,326 @@ +/* Copyright (c) 2001, 2009, Oracle and/or its affiliates. +All rights reserved. */ +/* + NAME + occiclob.cpp - OCCI CLOB Interface demo + + DESCRIPTION + This demo program explains the way of using CLOB interface. + This program inserts an empty clob into the table,selects the + clob from table, modifies it and stores it back into the table. + The Clob content will be printed finally. + This demo uses write , writeChunk and writeBuffer methods to + modify the clob contents, and also uses read and readBuffer + methods for reading. + + MODIFIED (MM/DD/YY) + sudsrini 07/08/09 - Include string.h, iostream not including it on sles11 + sudsrini 10/22/06 - Username/Password lower case + sudsrini 07/22/04 - Copyright Info + idcqe 03/05/01 - Creation + +*/ + +#include +#include +#include +#include +using namespace oracle::occi; +using namespace std; + +/** + * The demo sample has starts from startDemo method. This method is called + * by main. startDemo calls other methods, the supporting methods for + * startDemo are, + * insertRows - insert the rows into the table + * dataRollBack - deletes the inserted rows + * populateClob - populates a given clob + * dumpClob - prints the clob as an integer stream + */ +// These will tell the type of read/write we use +#define USE_NORM 1 +#define USE_CHUN 2 +#define USE_BUFF 3 + +/* Buffer Size */ +#define BUFSIZE 200; + +class occiClob +{ + public: + string username; + string password; + string url; + + void insertRows (Connection *conn) + throw (SQLException) + { + Statement *stmt = conn->createStatement ("INSERT INTO electronic_media(product_id,ad_id,ad_composite,ad_sourcetext) VALUES (:v1,:v2,:v3,:v4)"); + Blob blob(conn); + blob.setEmpty(); + Clob clob(conn); + clob.setEmpty(); + stmt->setInt(1,6666); + stmt->setInt(2,11001); + stmt->setBlob(3,blob); + stmt->setClob(4,clob); + stmt->executeUpdate(); + stmt->setSQL ("INSERT INTO electronic_media(product_id,ad_id,ad_composite,ad_sourcetext) VALUES (:v1, :v2, :v3, :v4)"); + stmt->setInt(1,7777); + stmt->setInt(2,11001); + stmt->setBlob(3,blob); + stmt->setClob(4,clob); + stmt->executeUpdate(); + stmt->setSQL ("INSERT INTO electronic_media(product_id,ad_id,ad_composite,ad_sourcetext) VALUES (:v1, :v2, :v3, :v4)"); + stmt->setInt(1,8888); + stmt->setInt(2,11001); + stmt->setBlob(3,blob); + stmt->setClob(4,clob); + stmt->executeUpdate(); + conn->commit(); + conn->terminateStatement (stmt); + + } + + void dataRollBack (Connection *conn) + throw (SQLException) + { + Statement *stmt = conn->createStatement ("DELETE FROM electronic_media WHERE product_id=6666 AND ad_id=11001"); + stmt->executeUpdate(); + stmt->setSQL("DELETE FROM electronic_media WHERE product_id=7777 AND ad_id=11001"); + stmt->executeUpdate(); + stmt->setSQL("DELETE FROM electronic_media WHERE product_id=8888 AND ad_id=11001"); + stmt->executeUpdate(); + conn->commit(); + conn->terminateStatement (stmt); + + } + + /** + * populating the clob uses write method; + */ + void populateClob (Clob &clob,unsigned int way) + throw (SQLException) + { + unsigned int bufsize=BUFSIZE; + if (way == USE_NORM) + { + cout << "Populating the Clob using write method" << endl; + unsigned int offset=1; + unsigned char *buffer = new unsigned char[bufsize]; + strcpy((char *)buffer, + "Just for source text content(added using write method)"); + unsigned int size=strlen((char *)buffer); + unsigned int bytesWritten=clob.write (size,buffer, size,offset); + //cout <<"Bytes Written : " << bytesWritten << endl; + delete[] buffer; + } + else if(way==USE_CHUN) + { + cout << "Populating the Clob using writeChunk method" << endl; + unsigned int offset=1; + unsigned int pieceCount = 4; + unsigned char *buffer = new unsigned char[bufsize*pieceCount]; + strcpy((char *)buffer, + "Just for source text content(added using writeChunk method)"); + unsigned int size=strlen((char *)buffer); + // Open the clob for writeChunk + clob.open(OCCI_LOB_READWRITE); + for (int i = 0; i < pieceCount; ++i,offset+=size) + clob.writeChunk(size,buffer,size,offset); + cout << "Clob Size " << clob.length() << endl; + delete[] buffer; + clob.close(); + } + else if(way==USE_BUFF) + { + // Uses stream here + cout << "Populating the Clob using writeBuffer(Stream) method" << endl; + char *file = (char *)"clobdemo.dat"; + char *buffer = new char[bufsize + 1]; + ifstream inFile; + inFile.open(file,ios::in); + if (!inFile) + { + cout << "clobdemo.dat file not found\n"; + delete[] buffer; + return; + } + unsigned int size; + Stream *strm=clob.getStream(); + while(inFile) + { + memset (buffer, NULL, bufsize + 1); + inFile.read(buffer,bufsize); + strm->writeBuffer(buffer,strlen(buffer)); + } + strcpy(buffer,"This piece for writeLastBuffer"); + size=strlen(buffer); + strm->writeLastBuffer(buffer,size); + clob.closeStream(strm); + inFile.close(); + delete[] buffer; + } + cout << "Populating the Clob - Success" << endl; + } + + /** + * printing the clob data as integer stream + */ + void dumpClob (Clob &clob,unsigned int way) + throw (SQLException) + { + unsigned int size=BUFSIZE; + unsigned int offset = 1; + + if (clob.isNull()) + { + cout << "Clob is Null\n"; + return; + } + unsigned int cloblen = clob.length(); + cout << "Length of Clob : "<< cloblen << endl; + if (cloblen == 0) + return; + unsigned char *buffer= new unsigned char[size]; + memset (buffer, NULL, size); + if (way==USE_NORM) + { + cout << "Dumping clob (using read ): "; + int bytesRead=clob.read(size,buffer,size,offset); + for (int i = 0; i < bytesRead; ++i) + cout << buffer[i]; + cout << endl; + } + else if(way==USE_BUFF) + { + Stream *inStream = clob.getStream (1,0); + cout << "Dumping clob(using stream): "; + int bytesRead=(inStream->readBuffer((char *)buffer, size)); + while (bytesRead > 0) + { + for (int i = 0; i < bytesRead; ++i) + { + cout << buffer[i]; + } + bytesRead=(inStream->readBuffer((char *)buffer, size)); + } + cout << endl; + clob.closeStream (inStream); + } + delete []buffer; + } + + occiClob () + { + /** + * default values of username & password + */ + username = "hr"; + password = "hr"; + url = ""; + } + + void setUsername (string u) + { + username = u; + } + + void setPassword (string p) + { + password = p; + } + + void setUrl (string u) + { + url = u; + } + + void runSample () + throw (SQLException) + { + Environment *env = Environment::createEnvironment ( + Environment::DEFAULT); + Connection *conn = env->createConnection (username, password, url); + insertRows (conn); + + // Selecting and modifying the clob column of the table + string sqlQuery = + "SELECT product_id,ad_id,ad_sourcetext FROM electronic_media FOR UPDATE"; + Statement *stmt1 = conn->createStatement (sqlQuery); + ResultSet *rset1 = stmt1->executeQuery (); + cout << "Query :" << sqlQuery << endl; + unsigned int way=USE_NORM; + while (rset1->next ()) + { + cout << "Product_id : " << (int)rset1->getInt(1) << endl; + cout << "Ad_id : " << (int)rset1->getInt(2) << endl; + Clob clob = rset1->getClob (3); + dumpClob (clob, USE_NORM); + if (way==USE_NORM) + { + populateClob(clob,USE_NORM); + way=USE_CHUN; + } + else if(way==USE_CHUN) + { + populateClob(clob,USE_CHUN); + way=USE_BUFF; + } + else if(way==USE_BUFF) + { + populateClob(clob,USE_BUFF); + way=USE_NORM; + } + } + stmt1->executeUpdate(); + stmt1->closeResultSet (rset1); + + // Printing after updating the clob content. + way = USE_BUFF; + sqlQuery = "SELECT product_id, ad_id, ad_sourcetext FROM electronic_media \ +ORDER BY product_id"; + Statement *stmt2 = conn->createStatement (sqlQuery); + ResultSet *rset2 = stmt2->executeQuery (); + cout << "Query :" << sqlQuery << endl; + while (rset2->next ()) + { + cout << "Product_id : " << (int)rset2->getInt(1) << endl; + cout << "Ad_id : " << (int)rset2->getInt(2) << endl; + Clob clob = rset2->getClob (3); + if (way==USE_NORM) + { + dumpClob (clob, USE_NORM); + way=USE_BUFF; + } + else if(way==USE_BUFF) + { + dumpClob (clob, USE_BUFF); + way=USE_NORM; + } + } + stmt2->closeResultSet (rset2); + dataRollBack(conn); + conn->terminateStatement (stmt1); + conn->terminateStatement (stmt2); + env->terminateConnection (conn); + Environment::terminateEnvironment (env); + } + +};//end of class occiClob + +int main (void) +{ + try + { + occiClob *b = new occiClob (); + b->setUsername ("hr"); + b->setPassword ("hr"); + b->runSample (); + } + catch (exception &e) + { + cout << e.what(); + } +} + diff --git a/occicoll.cpp b/occicoll.cpp new file mode 100644 index 0000000..aadb7d7 --- /dev/null +++ b/occicoll.cpp @@ -0,0 +1,230 @@ +/* Copyright (c) 2001, 2006, Oracle. All rights reserved. */ +/* + NAME + occicoll.cpp - OCCI Collections Demo + + DESCRIPTION + To exhibit simple insert, delete & update operations on table + having a Nested Table column + + MODIFIED (MM/DD/YY) + sudsrini 10/22/06 - Username/Password lower case + sudsrini 07/22/04 - Copyright Info + idcqe 03/05/01 - Creation + +*/ + +#include +#include +#include +using namespace oracle::occi; +using namespace std; + +typedef vector journal; + +class occicoll +{ + private: + + Environment *env; + Connection *conn; + Statement *stmt; + string tableName; + string typeName; + + public: + + occicoll (string user, string passwd, string db) + { + env = Environment::createEnvironment (Environment::OBJECT); + conn = env->createConnection (user, passwd, db); + } + + ~occicoll () + { + env->terminateConnection (conn); + Environment::terminateEnvironment (env); + } + + void setTableName (string s) + { + tableName = s; + } + + /** + * Insertion of a row + */ + void insertRow () + { + int c1 = 11; + journal c2; + + c2.push_back ("LIFE"); + c2.push_back ("TODAY"); + c2.push_back ("INVESTOR"); + + cout << "Inserting row with jid = " << 11 << + " and journal_tab (LIFE, TODAY, INVESTOR )" << endl; + try{ + stmt = conn->createStatement ( + "INSERT INTO journal_tab (jid, jname) VALUES (:x, :y)"); + stmt->setInt (1, c1); + setVector (stmt, 2, c2, "JOURNAL"); + stmt->executeUpdate (); + }catch(SQLException ex) + { + cout<<"Exception thrown for insertRow"<terminateStatement (stmt); + + } + + // Displaying all the rows of the table + void displayAllRows () + { + cout << "Displaying all the rows of the table" << endl; + stmt = conn->createStatement ( + "SELECT jid, jname FROM journal_tab order by jid"); + + journal c2; + + ResultSet *rs = stmt->executeQuery(); + try{ + while (rs->next()) + { + cout << "jid: " << rs->getInt(1) << endl; + cout << "jname: "; + getVector (rs, 2, c2); + for (int i = 0; i < c2.size(); ++i) + cout << c2[i] << " "; + cout << endl; + } + }catch(SQLException ex) + { + cout<<"Exception thrown for displayRow"<closeResultSet (rs); + conn->terminateStatement (stmt); + + } // End of displayAllRows() + + // Deleting a row of the nested table of strings + void deleteRow (int c1, string str) + { + cout << "Deleting a row of the nested table of strings" << endl; + stmt = conn->createStatement ( + "SELECT jname FROM journal_tab WHERE jid = :x"); + journal c2; + stmt->setInt (1, c1); + + ResultSet *rs = stmt->executeQuery(); + try{ + if (rs->next()) + { + getVector (rs, 1, c2); + c2.erase (find (c2.begin(), c2.end(), str)); + } + stmt->closeResultSet (rs); + + stmt->setSQL ("UPDATE journal_tab SET jname = :x WHERE jid = :y"); + stmt->setInt (2, c1); + setVector (stmt, 1, c2, "JOURNAL"); + stmt->executeUpdate (); + }catch(SQLException ex) + { + cout<<"Exception thrown for delete row"<commit(); + conn->terminateStatement (stmt); + } // End of deleteRow (int, string) + + // Updating a row of the nested table of strings + void updateRow (int c1, string str) + { + cout << "Updating a row of the nested table of strings" << endl; + stmt = conn->createStatement ( + "SELECT jname FROM journal_tab WHERE jid = :x"); + + journal c2; + + stmt->setInt (1, c1); + ResultSet *rs = stmt->executeQuery(); + try{ + if (rs->next()) + { + getVector (rs, 1, c2); + c2[0] = str; + } + stmt->closeResultSet (rs); + + stmt->setSQL ("UPDATE journal_tab SET jname = :x WHERE jid = :y"); + stmt->setInt (2, c1); + setVector (stmt, 1, c2, "JOURNAL"); + stmt->executeUpdate (); + }catch(SQLException ex) + { + cout<<"Exception thrown for updateRow"<commit(); + conn->terminateStatement (stmt); + } // End of UpdateRow (int, string) + + void cleanup() + { + stmt = conn->createStatement ("DELETE FROM journal_tab"); + stmt->execute(); + stmt->setSQL ("INSERT INTO journal_tab (jid, jname) VALUES (22, journal ('NATION', 'TIMES'))"); + stmt->executeUpdate(); + stmt->setSQL ("INSERT INTO journal_tab (jid, jname) VALUES (33, journal ('CRICKET', 'ALIVE'))"); + stmt->executeUpdate(); + conn->commit(); + conn->terminateStatement (stmt); + } + +};//end of class occicoll + +int main (void) +{ + string user = "hr"; + string passwd = "hr"; + string db = ""; + + try + { + cout << "occicoll - Exhibiting simple insert, delete & update operations" + " on table having a Nested Table column" << endl; + occicoll *demo = new occicoll (user, passwd, db); + + cout << "Displaying all rows before the operations" << endl; + demo->displayAllRows (); + + demo->insertRow (); + + demo->deleteRow (11, "TODAY"); + + demo->updateRow (33, "New_String"); + + cout << "Displaying all rows after all the operations" << endl; + demo->displayAllRows (); + + demo->cleanup(); + delete (demo); + cout << "occicoll - done" << endl; + }catch (SQLException ea) + { + cerr << "Error running the demo: " << ea.getMessage () << endl; + } +} diff --git a/occidemo.sql b/occidemo.sql new file mode 100644 index 0000000..6d1c6a8 --- /dev/null +++ b/occidemo.sql @@ -0,0 +1,344 @@ +/* Copyright (c) 2002, 2004, Oracle. All rights reserved. */ + +/* + NAME + occidemo.sql - Create OCCI demo objects + + DESCRIPTION + SQL Script to create OCCI demo objects + Assumes HR schema is setup + Assumes system's account passwd to be manager + Execute this before any of the OCCI demos are run + To drop the objects created by this SQL use occidemod.sql + + MODIFIED + sudsrini 03/06/03 - sudsrini_occi_10ir1_demos (include occidemod) + idcqe 03/13/01 - Created + +*/ + + +/* Drop objects before creating them */ + +@occidemod.sql + +connect hr/hr + +CREATE TABLE elements ( + element_name VARCHAR2(25), + molar_volume BINARY_FLOAT, + atomic_weight BINARY_DOUBLE +); + +CREATE TABLE author_tab ( + author_id NUMBER, + author_name VARCHAR2(25) +); + +INSERT INTO author_tab (author_id, author_name) VALUES (333, 'JOE'); +INSERT INTO author_tab (author_id, author_name) VALUES (444, 'SMITH'); + +CREATE OR REPLACE TYPE publ_address AS OBJECT ( + street_no NUMBER, + city VARCHAR2(25) +) +/ + +CREATE TABLE publisher_tab ( + publisher_id NUMBER, + publisher_add publ_address +); + +INSERT INTO publisher_tab (publisher_id, publisher_add) VALUES +(11, publ_address (121, 'NEW YORK')); + +CREATE TABLE publ_address_tab OF publ_address; + +INSERT INTO publ_address_tab VALUES (22, 'BOSTON'); +INSERT INTO publ_address_tab VALUES (33, 'BUFFALO'); +INSERT INTO publ_address_tab VALUES (44, 'CALIFORNIA'); + + +CREATE OR REPLACE TYPE journal AS TABLE OF VARCHAR2(50) +/ +CREATE TABLE journal_tab (jid NUMBER, jname journal) +NESTED TABLE jname STORE AS journal_store; + +INSERT INTO journal_tab (jid, jname) VALUES (22, journal ('NATION', 'TIMES')); +INSERT INTO journal_tab (jid, jname) VALUES (33, journal ('CRICKET', 'ALIVE')); + +CREATE OR REPLACE TYPE people_obj AS OBJECT ( + ssn NUMBER, + name VARCHAR2(25) +) NOT FINAL; +/ + +CREATE OR REPLACE TYPE librarian UNDER people_obj( + empno NUMBER, + sal NUMBER(7,2), + dob DATE, + photo BLOB +) +/ + +CREATE TABLE librarian_tab OF librarian; + +INSERT INTO librarian_tab VALUES +(101, 'DAVE', 1001, 10000, '12-Jan-1970', empty_blob()); +INSERT INTO librarian_tab VALUES +(102, 'BOB', 1002, 12000, '17-Jan-1970', empty_blob()); + +CREATE TABLE article_tab ( + artid NUMBER, + artdesc VARCHAR2(4000), + artsummary LONG, + artfeedbk VARCHAR2(2000) +); + +CREATE OR REPLACE PROCEDURE demo_proc (col1 IN NUMBER, col2 IN OUT VARCHAR2, +col3 OUT CHAR) AS +BEGIN + col2 := col1 || ' ' || col2 || ' ' || 'IN-OUT'; + col3 := 'OUT'; +END; +/ + +CREATE OR REPLACE FUNCTION demo_fun (col1 IN NUMBER, +col2 IN OUT VARCHAR2, col3 OUT CHAR) RETURN CHAR AS +BEGIN + col2 := col1 || ' ' || col2 || ' ' || 'IN-OUT'; + col3 := 'OUT'; + RETURN 'abcd'; +END; +/ + +CREATE TABLE book (bookid NUMBER, summary VARCHAR2(4000)); + +CREATE TABLE cover (c1 NUMBER(5), c2 VARCHAR2(20)); + +DECLARE +ch1 VARCHAR2(4000) := 'aa'; +ch2 VARCHAR2(4000):= ''; +nu NUMBER := 0; +BEGIN + FOR nu IN 1..11 LOOP + ch2 := ch1 || ch2; ch1 := ch2; + END LOOP; + INSERT INTO book (bookid, summary) VALUES (11, ch1); +END; +/ + +CREATE TYPE elecdoc_typ AS OBJECT + ( document_typ VARCHAR2(32) + , formatted_doc BLOB + ) ; +/ +CREATE TYPE elecdoc_tab AS TABLE OF elecdoc_typ; +/ + +CREATE TYPE elheader_typ AS OBJECT + ( header_name VARCHAR2(256) + , creation_date DATE + , header_text VARCHAR2(1024) + , logo BLOB + ); +/ + +CREATE TABLE electronic_media + ( product_id NUMBER(6) + , ad_id NUMBER(6) + , ad_composite BLOB + , ad_sourcetext CLOB + , ad_finaltext CLOB + , ad_fltextn NCLOB + , ad_elecdocs_ntab elecdoc_tab + , ad_photo BLOB + , ad_graphic BFILE + , ad_header elheader_typ + , press_release LONG + ) NESTED TABLE ad_elecdocs_ntab STORE AS elecdocs_nestedtab; +CREATE UNIQUE INDEX printmedia_pk + ON electronic_media (product_id, ad_id); + +ALTER TABLE electronic_media +ADD ( CONSTRAINT printmedia__pk + PRIMARY KEY (product_id, ad_id) + ) ; + + + +CREATE TYPE people_typ AS OBJECT +( + name VARCHAR2(30), + ssn NUMBER, + dob DATE +) not final; +/ + +CREATE TABLE people_tab OF people_typ; + +INSERT INTO people_tab VALUES (people_typ('john', 111, '01-Jan-1970')); +INSERT INTO people_tab VALUES (people_typ('jill', 666, '06-Jan-1976')); + +CREATE TYPE student UNDER people_typ +( + stud_id NUMBER, + teammate REF people_typ +) NOT FINAL; +/ + +CREATE TABLE student_tab OF student; +INSERT INTO student_tab VALUES ('jimmy',222,'02-Feb-1976',200, +(SELECT REF(a) FROM people_tab a where name='john')); + +CREATE TYPE parttime_stud UNDER student +( + course_id NUMBER, + partner REF student +)NOT FINAL; +/ +CREATE TABLE parttime_stud_tab OF parttime_stud; + +INSERT INTO parttime_stud_tab VALUES ('james',333,'03-Feb-1976',300, +(SELECT REF(a) FROM people_tab a where name='john'),3000, +(SELECT REF(a) FROM student_tab a)); + + +CREATE TYPE foreign_student UNDER parttime_stud +( + country VARCHAR2(30), + leader REF parttime_stud +); +/ +CREATE TABLE foreign_student_tab OF foreign_student; + +COMMIT; + + +/* OCCI AQ Objects */ + + +connect system/manager + +grant aq_administrator_role, aq_user_role to hr; +grant execute on dbms_aq to hr; +grant execute on dbms_aqadm to hr; + +BEGIN + dbms_aqadm.grant_system_privilege('ENQUEUE_ANY','hr',FALSE); + dbms_aqadm.grant_system_privilege('DEQUEUE_ANY','hr',FALSE); +END; +/ + +connect hr/hr + +CREATE OR REPLACE TYPE hr_obj AS OBJECT +(a1 NUMBER, a2 VARCHAR2(25)); +/ + +BEGIN + dbms_aqadm.create_queue_table ( + queue_table => 'hr.table01', + queue_payload_type => 'RAW', + comment => 'single-consumer', + multiple_consumers => false, + compatible => '8.1.0' +); +END; +/ + +BEGIN + dbms_aqadm.create_queue ( + queue_name => 'queue01', + queue_table=> 'hr.table01' +); +END; +/ +BEGIN + dbms_aqadm.start_queue(queue_name => 'queue01'); +END; +/ + +BEGIN + dbms_aqadm.create_queue_table ( + queue_table => 'hr.table02', + queue_payload_type => 'SYS.ANYDATA', + comment => 'multi-consumer', + multiple_consumers => true, + compatible => '8.1.0' +); +END; +/ + +BEGIN + dbms_aqadm.create_queue ( + queue_name => 'queue02', + queue_table=> 'hr.table02' +); +END; +/ +BEGIN + dbms_aqadm.start_queue(queue_name => 'queue02'); +END; +/ + +BEGIN + dbms_aqadm.create_queue_table ( + queue_table => 'hr.table03', + queue_payload_type => 'hr_obj', + comment => 'multi-consumer', + multiple_consumers => true, + compatible => '8.1.0' +); +END; +/ + +BEGIN + dbms_aqadm.create_queue ( + queue_name => 'queue03', + queue_table=> 'hr.table03' +); +END; +/ +BEGIN + dbms_aqadm.start_queue(queue_name => 'queue03'); +END; +/ + +BEGIN + dbms_aqadm.create_queue_table ( + queue_table => 'hr.table04', + queue_payload_type => 'RAW', + comment => 'multiple-consumer', + multiple_consumers => true, + compatible => '8.1.0' +); +END; +/ + +BEGIN + dbms_aqadm.create_queue ( + queue_name => 'queue04', + queue_table=> 'hr.table04' +); +END; +/ +BEGIN + dbms_aqadm.start_queue(queue_name => 'queue04'); +END; +/ + +Rem Add default local subscribers to the queues + +BEGIN + dbms_aqadm.add_subscriber( queue_name=> 'queue03', + subscriber=> sys.aq$_agent('AGT1','hr.queue03', 0)); +END; +/ + +BEGIN + dbms_aqadm.add_subscriber( queue_name=> 'queue04', + subscriber=> sys.aq$_agent('AGT1','hr.queue04', 0)); +END; +/ + diff --git a/occidemod.sql b/occidemod.sql new file mode 100644 index 0000000..d5d4ce7 --- /dev/null +++ b/occidemod.sql @@ -0,0 +1,121 @@ +/* Copyright (c) 2002, 2003, Oracle Corporation. All rights reserved. */ + +/* + NAME + occidemod - SQL Script to drop OCCI demo objects + + DESCRIPTION + SQL Script to drop OCCI demo objects created by occidemo.sql + To be run in the end to drop OCCI demo objects from HR schema + + MODIFIED + sudsrini 03/06/03 - sudsrini_occi_10ir1_demos + sudsrini 02/21/03 - Created + +*/ + +connect hr/hr + +DROP PROCEDURE demo_proc; +DROP FUNCTION demo_fun; + +DROP TABLE elements; +DROP TABLE author_tab; +DROP TABLE publisher_tab; +DROP TABLE publ_address_tab; +DROP TABLE journal_tab; +DROP TABLE article_tab; +DROP TABLE librarian_tab; +DROP TABLE book; +DROP TABLE cover; + +DROP TYPE journal; +DROP TYPE publ_address; +DROP TYPE librarian; +DROP TYPE people_obj; + + +DROP TABLE electronic_media; +DROP TYPE elheader_typ; +DROP TYPE elecdoc_tab; +DROP TYPE elecdoc_typ; + +DROP TABLE foreign_student_tab; +DROP TABLE parttime_stud_tab; +DROP TABLE student_tab; +DROP TABLE people_tab; +DROP TYPE foreign_student; +DROP TYPE parttime_stud; +DROP TYPE student; +DROP TYPE people_typ; + +/* OCCI AQ Object */ + +connect system/manager + +revoke aq_administrator_role from hr; + +connect hr/hr + +BEGIN + dbms_aqadm.stop_queue(queue_name => 'queue01'); +END; +/ + +BEGIN + dbms_aqadm.drop_queue('queue01'); +END; +/ + +BEGIN + dbms_aqadm.drop_queue_table('hr.table01'); +END; +/ + +BEGIN + dbms_aqadm.stop_queue(queue_name => 'queue02'); +END; +/ + +BEGIN + dbms_aqadm.drop_queue('queue02'); +END; +/ + +BEGIN + dbms_aqadm.drop_queue_table('hr.table02'); +END; +/ + +BEGIN + dbms_aqadm.stop_queue(queue_name => 'queue03'); +END; +/ + +BEGIN + dbms_aqadm.drop_queue('queue03'); +END; +/ + +BEGIN + dbms_aqadm.drop_queue_table('hr.table03'); +END; +/ + +BEGIN + dbms_aqadm.stop_queue(queue_name => 'queue04'); +END; +/ + +BEGIN + dbms_aqadm.drop_queue('queue04'); +END; +/ + +BEGIN + dbms_aqadm.drop_queue_table('hr.table04'); +END; +/ + +DROP TYPE hr_obj; + diff --git a/occidesc.cpp b/occidesc.cpp new file mode 100644 index 0000000..22387e2 --- /dev/null +++ b/occidesc.cpp @@ -0,0 +1,400 @@ +/* Copyright (c) 2001, 2008, Oracle. All rights reserved. */ +/* + NAME + occidesc.cpp - Describing the various objects of the database + + DESCRIPTION + This program describes the database objects like table, object and + procedure to get the metadata + + MODIFIED (MM/DD/YY) + mvasudev 05/22/08 - Add try / catch blocks + sudsrini 10/22/06 - Username/Password lower case + sudsrini 07/22/04 - Copyright Info + idcqe 03/05/01 - Creation + +*/ + +#include +#include +using namespace oracle::occi; +using namespace std; + +class occidesc +{ + private: + + Environment *env; + Connection *conn; + public : + /** + * Constructor for the occidesc demo program. + */ + occidesc (string user, string passwd, string db) throw (SQLException) + { + env = Environment::createEnvironment (Environment::OBJECT); + conn = env->createConnection (user, passwd, db); + }// end of constructor occidesc (string, string, string ) + + /** + * Destructor for the occidesc demo program. + */ + ~occidesc () throw (SQLException) + { + env->terminateConnection (conn); + Environment::terminateEnvironment (env); + } // end of ~occidesc () + + // Describing a subtype + void describe_type() + { + cout << "Describing the object - PEOPLE_OBJ"; + MetaData metaData = conn->getMetaData ((char *)"PEOPLE_OBJ"); + int mdTyp = metaData.getInt(MetaData::ATTR_PTYPE); + if (mdTyp == MetaData::PTYPE_TYPE) + { + cout << "PEOPLE_OBJis a type" << endl; + } + int typcode = metaData.getInt(MetaData::ATTR_TYPECODE); + if (typcode == OCCI_TYPECODE_OBJECT) + cout << "PERSON is an object type" << endl; + else + cout << "PERSON is not an object type" << endl; + int numtypeattrs = metaData.getInt(MetaData::ATTR_NUM_TYPE_ATTRS); + cout << "Object has " << numtypeattrs << " attributes" << endl; + try + { + cout << "Object id: " << metaData.getUInt (MetaData::ATTR_OBJ_ID) + << endl; + } + catch (SQLException ex) + { + cout << ex.getMessage() << endl; + } + cout << "Object Name: " << + metaData.getString (MetaData::ATTR_OBJ_NAME) << endl; + cout << "Schema Name: " << + (metaData.getString(MetaData::ATTR_OBJ_SCHEMA)) << endl; + cout << "Attribute version: " << + (metaData.getString(MetaData::ATTR_VERSION)) << endl; + if (metaData.getBoolean(MetaData::ATTR_IS_INCOMPLETE_TYPE)) + cout << "Incomplete type" << endl; + else + cout << "Not Incomplete type" << endl; + if (metaData.getBoolean(MetaData::ATTR_IS_SYSTEM_TYPE)) + cout << "System type" << endl; + else + cout << "Not System type" << endl; + if (metaData.getBoolean(MetaData::ATTR_IS_PREDEFINED_TYPE)) + cout << "Predefined Type" << endl; + else + cout << "Not Predefined Type" << endl; + if (metaData.getBoolean(MetaData::ATTR_IS_TRANSIENT_TYPE)) + cout << "Transient Type" << endl; + else + cout << "Not Transient Type" << endl; + if (metaData.getBoolean(MetaData::ATTR_IS_SYSTEM_GENERATED_TYPE)) + cout << "System-generated type" << endl; + else + cout << "Not System-generated type" << endl; + if (metaData.getBoolean(MetaData::ATTR_HAS_NESTED_TABLE)) + cout << "Has nested table" << endl; + else + cout << "Does not have nested table" << endl; + if (metaData.getBoolean(MetaData::ATTR_HAS_LOB)) + cout << "Has LOB" << endl; + else + cout << "Does not have LOB" << endl; + if (metaData.getBoolean(MetaData::ATTR_HAS_FILE)) + cout << "Has BFILE" << endl; + else + cout << "Does not have BFILE" << endl; + if (metaData.getBoolean(MetaData::ATTR_IS_INVOKER_RIGHTS)) + cout << "Object is Invoker rights" << endl; + else + cout << "Object is Not Invoker rights" << endl; + RefAny ref = metaData.getRef (MetaData::ATTR_REF_TDO); + MetaData md1 = conn->getMetaData (ref); + vector v1 = + md1.getVector (MetaData::ATTR_LIST_TYPE_ATTRS); + + for (int i = 0; i < v1.size (); ++i) + { + MetaData md2 = (MetaData)v1[i]; + cout << "Column Name :" << + (md2.getString(MetaData::ATTR_NAME)) << endl; + cout << " Data Type :" << + (printType (md2.getInt(MetaData::ATTR_DATA_TYPE))) << endl; + cout << " Size :" << md2.getInt(MetaData::ATTR_DATA_SIZE) << endl; + cout << " Precision :" << md2.getInt(MetaData::ATTR_PRECISION) << endl; + cout << " Scale :" << md2.getInt(MetaData::ATTR_SCALE) << endl << endl; + } + + cout << "describe_type - done" << endl; + } // end of describe_type() + + // Describing a table + void describe_table () + { + cout << "Describing the table - _TAB1" << endl; + vector v1; + MetaData metaData = conn->getMetaData("PUBLISHER_TAB"); + cout << "Object name:" << + (metaData.getString(MetaData::ATTR_OBJ_NAME)) << endl; + cout << "Schema:" << + (metaData.getString(MetaData::ATTR_OBJ_SCHEMA)) << endl; + if (metaData.getInt(MetaData::ATTR_PTYPE) == + MetaData::PTYPE_TABLE) + { + cout << "_TAB1 is a table" << endl; + } + else + cout << "_TAB1 is not a table" << endl; + if (metaData.getBoolean(MetaData::ATTR_PARTITIONED)) + cout << "Table is partitioned" << endl; + else + cout << "Table is not partitioned" << endl; + if (metaData.getBoolean(MetaData::ATTR_IS_TEMPORARY)) + cout << "Table is temporary" << endl; + else + cout << "Table is not temporary" << endl; + if (metaData.getBoolean(MetaData::ATTR_IS_TYPED)) + cout << "Table is typed" << endl; + else + cout << "Table is not typed" << endl; + if (metaData.getBoolean(MetaData::ATTR_CLUSTERED)) + cout << "Table is clustered" << endl; + else + cout << "Table is not clustered" << endl; + if (metaData.getBoolean(MetaData::ATTR_INDEX_ONLY)) + cout << "Table is Index-only" << endl; + else + cout << "Table is not Index-only" << endl; + cout << "Duration:"; + switch (metaData.getInt(MetaData::ATTR_DURATION)) + { + case MetaData::DURATION_SESSION : cout << "Connection" << endl; + break; + case MetaData::DURATION_TRANS : cout << "Transaction" << endl; + break; + case MetaData::DURATION_NULL : cout << "Table not temporary" << endl; + break; + } + try + { + cout << "Data Block Address:" << + metaData.getUInt (MetaData::ATTR_RDBA) << endl; + } + catch (SQLException ex) + { + cout << ex.getMessage() << endl; + } + try + { + cout << "Tablespace:" << + metaData.getInt (MetaData::ATTR_TABLESPACE) << endl; + } + catch (SQLException ex) + { + cout << ex.getMessage() << endl; + } + try + { + cout << "Object Id:" << + metaData.getUInt(MetaData::ATTR_OBJID) << endl; + } + catch (SQLException ex) + { + cout << ex.getMessage() << endl; + } + + int columnCount = metaData.getInt(MetaData::ATTR_NUM_COLS); + cout << "Number of Columns : " << columnCount << endl; + + v1 = metaData.getVector(MetaData::ATTR_LIST_COLUMNS); + for(int i=0; i < v1.size(); i++) + { + MetaData md = v1[i]; + cout << " Column Name :" << + (md.getString(MetaData::ATTR_NAME)) << endl; + cout << " Data Type :" << + (printType (md.getInt(MetaData::ATTR_DATA_TYPE))) << endl; + cout << " Size :" << md.getInt(MetaData::ATTR_DATA_SIZE) << endl; + cout << " Precision :" << md.getInt(MetaData::ATTR_PRECISION) << endl; + cout << " Scale :" << md.getInt(MetaData::ATTR_SCALE) << endl; + bool isnull = md.getBoolean(MetaData::ATTR_IS_NULL); + if (isnull) + cout << " Allows null" << endl; + else + cout << " Does not allow null" << endl; + } + cout << "describe_table - done" << endl; + } // end of describe_table () + + // Describing a procedure + void describe_proc () + { + cout << "Describing the procedure - DEMO_PROC" << endl; + MetaData metaData = conn->getMetaData("DEMO_PROC"); + vector v1 = + metaData.getVector ( MetaData::ATTR_LIST_ARGUMENTS ); + cout << "The number of arguments are:" << v1.size() << endl; + cout << "Object Name :" << + (metaData.getString(MetaData::ATTR_OBJ_NAME)) << endl; + cout << "Schema Name :" << + (metaData.getString(MetaData::ATTR_OBJ_SCHEMA)) << endl; + if (metaData.getInt(MetaData::ATTR_PTYPE) == MetaData:: + PTYPE_PROC) + { + cout << "DEMO_PROC is a procedure" << endl; + } + else + { + if (metaData.getInt(MetaData::ATTR_PTYPE) == MetaData:: + PTYPE_FUNC) + { + cout << "HIKE is a function" << endl; + } + } + try + { + cout << "Object Id:" << + metaData.getUInt(MetaData::ATTR_OBJ_ID) << endl; + } + catch (SQLException ex) + { + cout << ex.getMessage() << endl; + } + try + { + cout << "Name :" << + (metaData.getString(MetaData::ATTR_NAME)) << endl; + } + catch (SQLException ex) + { + cout << ex.getMessage() << endl; + } + + if (metaData.getBoolean(MetaData::ATTR_IS_INVOKER_RIGHTS)) + cout << "It is Invoker-rights" << endl; + else + cout << "It is not Invoker-rights" << endl; + cout << "Overload Id:" << + metaData.getInt(MetaData::ATTR_OVERLOAD_ID) << endl; + + for(int i=0; i < v1.size(); i++) + { + MetaData md = v1[i]; + cout << "Column Name :" << + (md.getString(MetaData::ATTR_NAME)) << endl; + cout << "DataType :" << + (printType (md.getInt(MetaData::ATTR_DATA_TYPE))) + << endl; + cout << "Argument Mode:"; + int mode = md.getInt (MetaData::ATTR_IOMODE); + if (mode == 0) + cout << "IN" << endl; + if (mode == 1) + cout << "OUT" << endl; + if (mode == 2) + cout << "IN/OUT" << endl; + cout << "Size :" << + md.getInt(MetaData::ATTR_DATA_SIZE) << endl; + cout << "Precision :" << + md.getInt(MetaData::ATTR_PRECISION) << endl; + cout << "Scale :" << + md.getInt(MetaData::ATTR_SCALE) << endl; + int isNull = md.getInt ( MetaData::ATTR_IS_NULL); + if (isNull != 0) + cout << "Allows null," << endl; + else + cout << "Does not allow null," << endl; + + int hasDef = md.getInt ( MetaData::ATTR_HAS_DEFAULT); + if (hasDef != 0) + cout << "Has Default" << endl; + else + cout << "Does not have Default" << endl; + } + cout << "test1 - done" << endl; + } + + // Method which prints the data type + string printType (int type) + { + switch (type) + { + case OCCI_SQLT_CHR : return "VARCHAR2"; + break; + case OCCI_SQLT_NUM : return "NUMBER"; + break; + case OCCIINT : return "INTEGER"; + break; + case OCCIFLOAT : return "FLOAT"; + break; + case OCCI_SQLT_STR : return "STRING"; + break; + case OCCI_SQLT_VNU : return "VARNUM"; + break; + case OCCI_SQLT_LNG : return "LONG"; + break; + case OCCI_SQLT_VCS : return "VARCHAR"; + break; + case OCCI_SQLT_RID : return "ROWID"; + break; + case OCCI_SQLT_DAT : return "DATE"; + break; + case OCCI_SQLT_VBI : return "VARRAW"; + break; + case OCCI_SQLT_BIN : return "RAW"; + break; + case OCCI_SQLT_LBI : return "LONG RAW"; + break; + case OCCIUNSIGNED_INT : return "UNSIGNED INT"; + break; + case OCCI_SQLT_LVC : return "LONG VARCHAR"; + break; + case OCCI_SQLT_LVB : return "LONG VARRAW"; + break; + case OCCI_SQLT_AFC : return "CHAR"; + break; + case OCCI_SQLT_AVC : return "CHARZ"; + break; + case OCCI_SQLT_RDD : return "ROWID"; + break; + case OCCI_SQLT_NTY : return "NAMED DATA TYPE"; + break; + case OCCI_SQLT_REF : return "REF"; + break; + case OCCI_SQLT_CLOB: return "CLOB"; + break; + case OCCI_SQLT_BLOB: return "BLOB"; + break; + case OCCI_SQLT_FILE: return "BFILE"; + break; + default: return ""; + } + } // End of printType (int) + + +}; // end of class occidesc + +int main (void) +{ + string user = "hr"; + string passwd = "hr"; + string db = ""; + + cout << "occidesc - Describing the various objects of the database" << endl; + try{ + occidesc *demo = new occidesc (user, passwd, db); + demo->describe_table(); + demo->describe_type(); + demo->describe_proc(); + delete demo; + } + catch (SQLException ex){ + cout << ex.getMessage() << endl; + } + +}// end of main () diff --git a/occidml.cpp b/occidml.cpp new file mode 100644 index 0000000..ec5381c --- /dev/null +++ b/occidml.cpp @@ -0,0 +1,292 @@ +/* Copyright (c) 2001, 2008, Oracle. All rights reserved. */ +/* + NAME + occidml.cpp - Basic DML Operations demo + + DESCRIPTION + To exhibit the insertion, selection, updating and deletion of + a row using OCCI interface + + MODIFIED (MM/DD/YY) + mvasudev 05/22/08 - Add try/catch blocks + sudsrini 10/22/06 - Username/Password lower case + lburgess 04/14/06 - lowercase passwords + sudsrini 07/23/04 - Copyright Info + idcqe 03/05/01 - Creation + +*/ + +#include +#include +using namespace oracle::occi; +using namespace std; + +class occidml +{ + private: + + Environment *env; + Connection *conn; + Statement *stmt; + public: + + occidml (string user, string passwd, string db) + { + env = Environment::createEnvironment (Environment::DEFAULT); + conn = env->createConnection (user, passwd, db); + } + + ~occidml () + { + env->terminateConnection (conn); + Environment::terminateEnvironment (env); + } + + /** + * Insertion of a row with dynamic binding, PreparedStatement functionality. + */ + void insertBind (int c1, string c2) + { + string sqlStmt = "INSERT INTO author_tab VALUES (:x, :y)"; + stmt=conn->createStatement (sqlStmt); + try{ + stmt->setInt (1, c1); + stmt->setString (2, c2); + stmt->executeUpdate (); + cout << "insert - Success" << endl; + }catch(SQLException ex) + { + cout<<"Exception thrown for insertBind"<terminateStatement (stmt); + } + + /** + * Inserting a row into the table. + */ + void insertRow () + { + string sqlStmt = "INSERT INTO author_tab VALUES (111, 'ASHOK')"; + stmt = conn->createStatement (sqlStmt); + try{ + stmt->executeUpdate (); + cout << "insert - Success" << endl; + }catch(SQLException ex) + { + cout<<"Exception thrown for insertRow"<terminateStatement (stmt); + } + + /** + * updating a row + */ + void updateRow (int c1, string c2) + { + string sqlStmt = + "UPDATE author_tab SET author_name = :x WHERE author_id = :y"; + stmt = conn->createStatement (sqlStmt); + try{ + stmt->setString (1, c2); + stmt->setInt (2, c1); + stmt->executeUpdate (); + cout << "update - Success" << endl; + }catch(SQLException ex) + { + cout<<"Exception thrown for updateRow"<terminateStatement (stmt); + } + + + /** + * deletion of a row + */ + void deleteRow (int c1, string c2) + { + string sqlStmt = + "DELETE FROM author_tab WHERE author_id= :x AND author_name = :y"; + stmt = conn->createStatement (sqlStmt); + try{ + stmt->setInt (1, c1); + stmt->setString (2, c2); + stmt->executeUpdate (); + cout << "delete - Success" << endl; + }catch(SQLException ex) + { + cout<<"Exception thrown for deleteRow"<terminateStatement (stmt); + } + + /** + * displaying all the rows in the table + */ + void displayAllRows () + { + string sqlStmt = "SELECT author_id, author_name FROM author_tab \ + order by author_id"; + stmt = conn->createStatement (sqlStmt); + ResultSet *rset = stmt->executeQuery (); + try{ + while (rset->next ()) + { + cout << "author_id: " << rset->getInt (1) << " author_name: " + << rset->getString (2) << endl; + } + }catch(SQLException ex) + { + cout<<"Exception thrown for displayAllRows"<closeResultSet (rset); + conn->terminateStatement (stmt); + } + + /** + * Inserting a row into elements table. + * Demonstrating the usage of BFloat and BDouble datatypes + */ + void insertElement (string elm_name, float mvol=0.0, double awt=0.0) + { + BFloat mol_vol; + BDouble at_wt; + + if (!(mvol)) + mol_vol.isNull = TRUE; + else + mol_vol.value = mvol; + + if (!(awt)) + at_wt.isNull = TRUE; + else + at_wt.value = awt; + + string sqlStmt = "INSERT INTO elements VALUES (:v1, :v2, :v3)"; + stmt = conn->createStatement (sqlStmt); + + try{ + stmt->setString(1, elm_name); + stmt->setBFloat(2, mol_vol); + stmt->setBDouble(3, at_wt); + stmt->executeUpdate (); + cout << "insertElement - Success" << endl; + }catch(SQLException ex) + { + cout<<"Exception thrown for insertElement"<terminateStatement (stmt); + } + + /** + * displaying rows from element table + */ + void displayElements () + { + string sqlStmt = + "SELECT element_name, molar_volume, atomic_weight FROM elements \ + order by element_name"; + stmt = conn->createStatement (sqlStmt); + ResultSet *rset = stmt->executeQuery (); + try{ + cout.precision(7); + while (rset->next ()) + { + string elem_name = rset->getString(1); + BFloat mol_vol = rset->getBFloat(2); + BDouble at_wt = rset->getBDouble(3); + + cout << "Element Name: " << elem_name << endl; + + if ( mol_vol.isNull ) + cout << "Molar Volume is NULL" << endl; + else + cout << "Molar Volume: " << mol_vol.value << " cm3 mol-1" << endl; + + if ( at_wt.isNull ) + cout << "Atomic Weight is NULL" << endl; + else + cout << "Atomic Weight: " << at_wt.value << " g/mole" << endl; + } + }catch(SQLException ex) + { + cout<<"Exception thrown for displayElements"<closeResultSet (rset); + conn->terminateStatement (stmt); + } + +}; // end of class occidml + + +int main (void) +{ + string user = "hr"; + string passwd = "hr"; + string db = ""; + try{ + cout << "occidml - Exhibiting simple insert, delete & update operations" + << endl; + occidml *demo = new occidml (user, passwd, db); + cout << "Displaying all records before any operation" << endl; + demo->displayAllRows (); + + cout << "Inserting a record into the table author_tab " + << endl; + demo->insertRow (); + + cout << "Displaying the records after insert " << endl; + demo->displayAllRows (); + + cout << "Inserting a records into the table author_tab using dynamic bind" + << endl; + demo->insertBind (222, "ANAND"); + + cout << "Displaying the records after insert using dynamic bind" << endl; + demo->displayAllRows (); + + cout << "deleting a row with author_id as 222 from author_tab table" << endl; + demo->deleteRow (222, "ANAND"); + + cout << "updating a row with author_id as 444 from author_tab table" << endl; + demo->updateRow (444, "ADAM"); + + cout << "displaying all rows after all the operations" << endl; + demo->displayAllRows (); + + cout << "inserting radio active element properties" << endl; + demo->insertElement ("Uranium", 12.572, 238.0289 ); + demo->insertElement ("Plutonium", 12.12, 244.0642 ); + demo->insertElement ("Curium", 18.17, 247.0703 ); + demo->insertElement ("Thorium"); + demo->insertElement ("Radium", 41.337, 226.0254); + + cout << "displaying all radio active element properties" << endl; + demo->displayElements (); + + delete (demo); + } + catch (SQLException ex){ + cout << ex.getMessage() << endl; + } + cout << "occidml - done" << endl; +} diff --git a/occiinh.cpp b/occiinh.cpp new file mode 100644 index 0000000..b5379b3 --- /dev/null +++ b/occiinh.cpp @@ -0,0 +1,278 @@ +/* Copyright (c) 2001, 2006, Oracle. All rights reserved. */ +/* + NAME + occiinh.cpp - OCCI Object Inheritance demo + + DESCRIPTION + This demo performs all DML operations using OCCI interface + on the objects + Object Hierarchy + people_typ <---- student <----- parttime_stud <----- foreign_student + + MODIFIED (MM/DD/YY) + sudsrini 10/22/06 - Username/Password lower case + sudsrini 07/23/04 - Copyright Info + idcqe 03/05/01 - Creation + +*/ + +#include +#include +using namespace oracle::occi; +using namespace std; + +#include "occiinhm.h" + +/* Add on your methods in this class*/ +class foreign_student_obj : public foreign_student +{ + /* New methods can be added here */ +}; + +class occiinh +{ + private: + + Environment *env; + Connection *con; + + // This method will return the Ref + RefAny getRefObj(string sqlString) + { + Statement *stmt = con->createStatement (sqlString); + ResultSet *rs; + try + { + rs = stmt->executeQuery (); + if ( rs->next() ) + { + RefAny ref1 = rs->getRef (1); + stmt->closeResultSet (rs); + con->terminateStatement (stmt); + return ref1; + } + } + catch(SQLException ex) + { + cout << "Error in fetching ref" << endl; + } + stmt->closeResultSet (rs); + con->terminateStatement (stmt); + return RefAny(); + } + + + public: + + occiinh (string user, string passwd, string db) + throw (SQLException) + { + env = Environment::createEnvironment (Environment::OBJECT); + occiinhm(env); + con = env->createConnection (user, passwd, db); + }// end of constructor occiinh (string, string, string) + + ~occiinh () + throw (SQLException) + { + env->terminateConnection (con); + Environment::terminateEnvironment (env); + }// end of destructor + + /** + * Insertion of a row + */ + void insertRow () + throw (SQLException) + { + cout << "Inserting a record (joe)" << endl; + string sqlStmt = + "INSERT INTO foreign_student_tab VALUES(:a)"; + Statement *stmt = con->createStatement (sqlStmt); + string fs_name = "joe"; + Number fs_ssn (4); + Date fs_dob(env, 2000, 5, 11, 16, 05, 0); + Number fs_stud_id (400); + Ref< people_typ > fs_teammate = getRefObj( + "SELECT REF(a) FROM people_tab a where name='john'"); + Number fs_course_id(4000); + Ref< student > fs_partner = getRefObj( + "SELECT REF(a) FROM student_tab a"); + string fs_country = "india"; + Ref< parttime_stud > fs_leader = getRefObj( + "SELECT REF(a) FROM parttime_stud_tab a"); + foreign_student_obj *fs_obj = new foreign_student_obj (); + fs_obj->setname(fs_name); + fs_obj->setssn(fs_ssn); + fs_obj->setdob(fs_dob); + fs_obj->setstud_id(fs_stud_id); + fs_obj->setteammate(fs_teammate); + fs_obj->setcourse_id(fs_course_id); + fs_obj->setpartner(fs_partner); + fs_obj->setcountry(fs_country); + fs_obj->setleader(fs_leader); + stmt->setObject(1, fs_obj); + stmt->executeUpdate(); + + con->terminateStatement (stmt); + delete fs_obj; + cout << "Insertion Successful" << endl; + }// end of insertRow (); + + + /** + * updating a row + */ + void updateRow () + throw (SQLException) + { + cout << "Upadating record (Changing name,teammate and course_id)" << endl; + string sqlStmt = + "UPDATE foreign_student_tab SET name=:x, teammate=:y, course_id=:z"; + Statement *stmt = con->createStatement (sqlStmt); + string fs_name = "jeffree"; + Ref< people_typ > fs_teammate = getRefObj( + "SELECT REF(a) FROM people_tab a where name='jill'"); + Number fs_course_id(5000); + stmt->setString(1, fs_name); + stmt->setRef(2,fs_teammate); + stmt->setInt(3, fs_course_id); + stmt->executeUpdate (); + con->commit(); + con->terminateStatement (stmt); + cout << "Updation Successful" << endl; + }// end of updateRow (int, string); + + + /** + * deletion of a row + */ + void deleteRow () + throw (SQLException) + { + cout << "Deletion of jeffree record " << endl; + string sqlStmt = "DELETE FROM foreign_student_tab where name=:x"; + Statement *stmt = con->createStatement (sqlStmt); + string fs_name = "jeffree"; + stmt->setString(1,fs_name); + stmt->executeUpdate(); + con->commit(); + con->terminateStatement (stmt); + cout << "Deletion Successful" << endl; + }// end of deleteRow (int, string); + + /** + * displaying all the rows in the table + */ + void displayAllRows () + throw (SQLException) + { + int count=0; + string sqlStmt = "SELECT REF(a) FROM foreign_student_tab a"; + Statement *stmt = con->createStatement (sqlStmt); + ResultSet *resultSet = stmt->executeQuery (); + + while (resultSet->next ()) + { + count++; + RefAny fs_refany = resultSet->getRef(1); + Ref fs_ref(fs_refany); + fs_ref.setPrefetch(4); + string fmt = "DD-MON-YYYY"; + string nlsParam = "NLS_DATE_LANGUAGE = American"; + Date fs_dob = fs_ref->getdob(); + string date1 = fs_dob.toText (fmt, nlsParam); + cout << "Foreign Student Information" << endl; + cout << "Name : " << fs_ref->getname(); + cout << " SSN : " << (int)fs_ref->getssn(); + cout << " DOB : " << date1 << endl; + cout << "Stud id : " << (int)fs_ref->getstud_id() ; + cout << " Course id : " << (int)fs_ref->getcourse_id(); + cout << " Country : " << fs_ref->getcountry() < fs_teammate = (Ref ) + fs_ref->getteammate(); + cout << "Teammate's Information " << endl; + cout << "Name : " << fs_teammate->getname(); + cout << " SSN : " << (int)fs_teammate->getssn(); + fs_dob = fs_teammate->getdob(); + date1 = fs_dob.toText(fmt, nlsParam); + cout << " DOB : " << date1 << endl << endl; + /* Leader */ + Ref< parttime_stud > fs_leader = (Ref < parttime_stud >) + fs_ref->getleader(); + /* Leader's Partner */ + Ref < student > fs_partner = (Ref ) + fs_leader->getpartner(); + /* Leader's Partenr's teammate */ + fs_teammate = (Ref ) fs_partner->getteammate(); + + cout << "Leader Information " << endl; + cout << "Name : " << fs_leader->getname(); + cout << " SSN : " << (int)fs_leader->getssn(); + fs_dob = fs_leader->getdob(); + date1 = fs_dob.toText(fmt, nlsParam); + cout << " DOB : " << date1 << endl; + cout << "Stud id : " << (int)fs_leader->getstud_id(); + cout << " Course id : " << (int)fs_leader->getcourse_id() << endl; + + cout << "Leader's Partner's Information " << endl; + cout << "Name : " << fs_partner->getname() ; + cout << " SSN : " << (int)fs_partner->getssn(); + fs_dob = fs_partner->getdob(); + date1 = fs_dob.toText(fmt, nlsParam); + cout << " DOB : " << date1 ; + cout << " Stud id : " << (int)fs_partner->getstud_id() << endl; + + + cout << "Leader's Partner's Teammate's Information " << endl; + cout << "Name : " << fs_teammate->getname(); + cout << " SSN : " << (int)fs_teammate->getssn(); + fs_dob = fs_teammate->getdob(); + date1 = fs_dob.toText(fmt, nlsParam); + cout << " DOB : " << date1 << endl << endl; + + }//end of while (resultSet->next ()); + if (count <=0) + cout << "No record found " << endl; + stmt->closeResultSet (resultSet); + con->terminateStatement (stmt); + }// end of updateRow (string); + +}; // end of class occiinh + + +int main (void) +{ + string user = "hr"; + string passwd = "hr"; + string db = ""; + + try + { + cout << "occiinh - Exhibiting simple insert, delete & update operations" + " on Oracle objects" << endl; + occiinh *demo = new occiinh (user, passwd, db); + + cout << "displaying all rows before operations" << endl; + demo->displayAllRows (); + + demo->insertRow (); + cout << "displaying all rows after insertions" << endl; + demo->displayAllRows (); + + demo->updateRow (); + cout << "displaying all rows after updations" << endl; + demo->displayAllRows (); + + demo->deleteRow (); + cout << "displaying all rows after deletions" << endl; + demo->displayAllRows (); + + + delete (demo); + cout << "occiinh - done" << endl; + }catch (SQLException ea) + { + cerr << "Error running the demo: " << ea.getMessage () << endl; + } +}// end of int main (void); diff --git a/occiinh.typ b/occiinh.typ new file mode 100644 index 0000000..774d6af --- /dev/null +++ b/occiinh.typ @@ -0,0 +1,3 @@ +CASE=LOWER +MAPFILE=occiinhm.cpp +TYPE FOREIGN_STUDENT as foreign_student diff --git a/occilbar.cpp b/occilbar.cpp new file mode 100644 index 0000000..3404789 --- /dev/null +++ b/occilbar.cpp @@ -0,0 +1,400 @@ +/* Copyright (c) 2004, 2006, Oracle. All rights reserved. */ +/* + NAME + occilbar.cpp - OCCI Support for reading/writing arrays of LOB's. + + DESCRIPTION + To exhibit OCCI Support for reading/writing arrays of LOB's. + Create a table with BLOB, CLOB column. + Populate the values in the table by using new LOB Array Write method + Retrieve the values from the table by using the LOB Array Read method + + 1. readVectorOfBlobs() + 2. readVectorOfClobs() + 3. writeVectorOfBlobs() + 4. writeVectorOfClobs() + + MODIFIED (MM/DD/YY) + sudsrini 10/22/06 - Username/Password lower case + kukannan 09/21/04 - Include iostream + sudsrini 07/22/04 - Copyright Info + debanerj 06/04/04 - debanerj_13064_lob_array_read + kukannan 05/26/04 - Creation +*/ + +#include +#include +#include +using namespace oracle::occi; +using namespace std; + +#define NO_OF_LOBS 10 + +class lobarray +{ + private: + + Environment *env; + Connection *conn; + + public: + + lobarray (string user, string passwd, string db) + { + env = Environment::createEnvironment (Environment::DEFAULT); + conn = env->createConnection (user, passwd, db); + } + + /** + * Destructor for the lobarray test case. + */ + ~lobarray () + { + env->terminateConnection (conn); + Environment::terminateEnvironment (env); + } // end of ~lobarray () + + /** + * Creating schema objects. + */ + dvoid createTables () + { + string sqlstr1 = "CREATE TABLE lobarray_tab"; + sqlstr1 += " (c1 NUMBER, c2 BLOB, c3 CLOB)"; + Statement *stmt = conn->createStatement(sqlstr1); + stmt->execute(); + } // end of createTables () + + /** + * Removing schema objects created. + */ + dvoid dropTable () + { + Statement *stmt= conn->createStatement("DROP TABLE lobarray_tab"); + stmt->execute(); + } // end of cleanup () + + /** + * The testing logic of the test case. + */ + dvoid test () + { + cout << "lobarray - Testing the OCCI Array LOB Api's" << endl; + createTables (); + + Statement *stmt = conn->createStatement(""); + + char stmt_str[500]; + for (int i=0; iexecute ((const char *)stmt_str); + } + conn->terminateStatement (stmt); + + writeArrayBlob (); + readArrayBlob (); + + cout << "Writing into clob by mentioning character amts " << endl; + writeArrayClob (1); + cout << "Reading from clob by mentioning character amts " << endl; + readArrayClob (1); + + cout << "Writing into clob by mentioning byte amts " << endl; + writeArrayClob (2); + cout << "Reading from clob by mentioning byte amts " << endl; + readArrayClob (2); + + dropTable (); + cout << "lobarray - done" << endl; + } // end of test() + + /************************************************************/ + /* writeArrayBlob() */ + /************************************************************/ + /*Select all the Lob Locators from Blob col from the table. */ + /*Push these Lob Locators in a Vector of Blobs. */ + /*Call populate_buffer function which would populate the */ + /*amount of data to be written, sets the offsets, populates */ + /*the buffer. */ + /*Call writeVectorOfBlobs with the populate buffer,amount */ + /*and offset value. This would write the buffered values */ + /*into respective lobs. Do and connection commit and release*/ + /*the allocated memory. */ + /************************************************************/ + + void writeArrayBlob () + { + cout << "Writing Array Lob using writeVectorofBlobs" << endl; + char stmt_str[500]; + + vector lob_vec; + sprintf(stmt_str,"Select c2 from lobarray_tab for update"); + Statement *stmt = conn->createStatement((const char *)stmt_str); + ResultSet *rs = stmt->executeQuery(); + + while (rs->next()) + lob_vec.push_back(rs->getBlob(1)); + + stmt->closeResultSet(rs); + conn->terminateStatement(stmt); + + oraub8 byte_amts[NO_OF_LOBS]; + oraub8 offsets[NO_OF_LOBS]; + unsigned char *buffers[NO_OF_LOBS]; + oraub8 buffer_lens[NO_OF_LOBS]; + + populate_buffer(byte_amts,offsets, buffers,buffer_lens,1); + writeVectorOfBlobs(conn,lob_vec,byte_amts,offsets,buffers,buffer_lens); + conn->commit(); + release_memory(buffers); + cout << "Writing - Done" << endl; + } + /************************************************************/ + /* writeArrayClob() */ + /************************************************************/ + /*Select all the Lob Locators from Clob col from the table. */ + /*Push these Lob Locators in a Vector of Clobs. */ + /*Call populate_buffer function which would populate the */ + /*amount of data to be written, sets the offsets, populates */ + /*the buffer. */ + /*Call writeVectorOfClobs with the populated buffer,amount */ + /*and offset value. This would write the buffered values */ + /*into respective lobs. Do and connection commit and release*/ + /*the allocated memory. */ + /*The type variable differentiates the attributes based on */ + /*which the value gets inserted into the Clob. */ + /*A value of 1 for the TYPE variable means that the */ + /*of CHARACTER gets inserted into the Lobs. */ + /*A value of 2 for the TYPE variable means that the */ + /*of BYTES gets inserted into the Lobs. */ + /************************************************************/ + + void writeArrayClob (int type) + { + char stmt_str[500]; + + vector lob_vec; + sprintf(stmt_str,"Select c3 from lobarray_tab for update"); + Statement *stmt = conn->createStatement((const char *)stmt_str); + ResultSet *rs = stmt->executeQuery(); + + // Got all the loblocator and pushed in to the vector + while (rs->next()) + lob_vec.push_back(rs->getClob(1)); + + stmt->closeResultSet(rs); + conn->terminateStatement(stmt); + + oraub8 amts[NO_OF_LOBS]; + oraub8 offsets[NO_OF_LOBS]; + unsigned char *buffers[NO_OF_LOBS]; + oraub8 buffer_lens[NO_OF_LOBS]; + populate_buffer(amts,offsets, buffers,buffer_lens,1); + + /**************************************************************/ + /*Populating the Lob by passing Character amounts if type = 1 */ + /*Populating the Lob by passing Byte amounts if type = 2 */ + /**************************************************************/ + + if (type==1) + { + writeVectorOfClobs(conn,lob_vec,NULL,amts,offsets,\ + buffers,buffer_lens); + } + else + { + writeVectorOfClobs(conn,lob_vec,amts,NULL,offsets,\ + buffers,buffer_lens); + } + conn->commit(); + release_memory(buffers); + cout << "Writing - Done" << endl; + } + /************************************************************/ + /* readArrayBlob() */ + /************************************************************/ + /*Select all the Lob Locators from Blob col from the table. */ + /*Push these Lob Locators in a Vector of Blobs. */ + /*Call populate_buffer function which would assign the */ + /*the offsets, allocate memory for the buffer for */ + /*readVectorOfBlobs to read the value into. */ + /*Call readVectorOfBlobs with the populated amount and */ + /*offset value. This would read the LOB data into the */ + /*allocated buffers. Print the buffers by calling */ + /*print_buffers() and release the allocated memory. */ + /************************************************************/ + + + void readArrayBlob () + { + cout << "Reading Array Lob using readVectorofBlob" << endl; + char stmt_str[500]; + + vector lob_vec; + sprintf(stmt_str,"Select c2 from lobarray_tab order by c1"); + Statement *stmt = conn->createStatement((const char *)stmt_str); + ResultSet *rs = stmt->executeQuery(); + + while (rs->next()) + lob_vec.push_back(rs->getBlob(1)); + + stmt->closeResultSet(rs); + conn->terminateStatement(stmt); + + oraub8 read_amts[NO_OF_LOBS]; + oraub8 offsets[NO_OF_LOBS]; + unsigned char *buffers[NO_OF_LOBS]; + oraub8 buffer_lens[NO_OF_LOBS]; + populate_buffer(read_amts,offsets, buffers,buffer_lens,0); + + readVectorOfBlobs(conn,lob_vec,read_amts,offsets,buffers,buffer_lens); + + print_buffer(buffers,read_amts); + release_memory(buffers); + cout << "Reading - Done " << endl; + } + /************************************************************/ + /* readArrayClob() */ + /************************************************************/ + /*Select all the Lob Locators from Clob col from the table. */ + /*Push these Lob Locators in a Vector of Clobs. */ + /*Call populate_buffer function which would assign the */ + /*the offsets, allocate memory for the buffer for */ + /*readVectorOfClobs to read the value into. */ + /*Call readVectorOfClobs with the populated amount and */ + /*offset value. This would read the LOB data into the */ + /*allocated buffers.Print the buffers by calling */ + /*print_buffers() and release the allocated memory. */ + /*A value of 1 for the TYPE variable means that the */ + /*of CHARACTER gets inserted into the Lobs. */ + /*A value of 2 for the TYPE variable means that the */ + /*of BYTES gets inserted into the Lobs. */ + /************************************************************/ + + + void readArrayClob (int type) + { + char stmt_str[500]; + + vector lob_vec; + sprintf(stmt_str,"Select c3 from lobarray_tab order by c1"); + Statement *stmt = conn->createStatement((const char *)stmt_str); + ResultSet *rs = stmt->executeQuery(); + + while (rs->next()) + lob_vec.push_back(rs->getClob(1)); + + stmt->closeResultSet(rs); + conn->terminateStatement(stmt); + + oraub8 read_amts[NO_OF_LOBS]; + oraub8 offsets[NO_OF_LOBS]; + unsigned char *buffers[NO_OF_LOBS]; + oraub8 buffer_lens[NO_OF_LOBS]; + populate_buffer(read_amts,offsets,buffers,buffer_lens,0); + + if (type==1) + readVectorOfClobs(conn,lob_vec,NULL,read_amts,offsets,\ + buffers,buffer_lens); + else if (type==2) + readVectorOfClobs(conn,lob_vec,read_amts,NULL,offsets,\ + buffers,buffer_lens); + + print_buffer(buffers,read_amts); + release_memory(buffers); + cout << "Reading - Done " << endl; + } + + /************************************************************/ + /* populate_buffer() */ + /************************************************************/ + /*This function assign the offsets,buffer_lens,buffer_amts */ + /*for each Lob.Allocates memory for each buffer and populate*/ + /*buffer for each Lob. The significance of Idx is to */ + /*differentiate the calls made while reading or writing the */ + /*Lob Data. Reading/Writing Lobs require offset,amts and */ + /*buffer_lens for each Lob. */ + /*Idx=1 means the function is called prior to writing into */ + /*the LOB and populates the buffer */ + /*Idx=1 means the function is called prior to reading from */ + /*the LOB and donot populate the buffer */ + /************************************************************/ + + void populate_buffer(oraub8 *amts,oraub8 *offsets,unsigned char **buffers,\ + oraub8 *buffer_lens,int idx) + { + for (int i=0; i < NO_OF_LOBS ; i++) + { + offsets[i]=1; + buffer_lens[i]=i+1; //Writing upto multiples of 5 + amts[i]=buffer_lens[i]; + buffers[i]=new unsigned char[buffer_lens[i]]; + + if (idx!=0) + { + for (int j=0; jtest (); + } + catch (SQLException ea) + { + cout<<"Exception thrown by test Function" < occimb1.html + + MODIFIED (MM/DD/YY) + sudsrini 03/07/08 - order by for deterministic output + sudsrini 10/22/06 - Username/Password lower case + kukannan 03/12/06 - Fix bug 5074203 + sudsrini 07/23/04 - Copyright Info + shiyer 03/05/03 - Creation + +*/ + +#include +#include + +using namespace std; +using namespace oracle::occi; + + +int main() +{ + //part1 - use ZHT16BIG5 characterset + try + { + cout << "Creating environment with ZHT16BIG5(Chinese) characterset
" << endl; + Environment *big5env = Environment::createEnvironment("ZHT16BIG5","ZHT16BIG5"); + + Connection *conn = big5env->createConnection("hr", "hr"); + + cout << "Inserting some information in Chinese - Periodic table elements
" << endl; + + Statement *stmt = + conn->createStatement("INSERT INTO GLOBALINFO_TAB VALUES (:1, :2 ,:3)"); + + stmt->setString(1,"Chinese"); + stmt->setString(2,"Periodic Table Elements"); + + //the code-points in ZHT16BIG5 for the symbols + const char siliconsym[] = {0xD6,0xBA,0x00}; + const char goldsym[] = {0xAA,0xF7,0x00}; + const char calciumsym[] = {0xE0,0xB3,0x00}; + + string info; + info += "Silicon = "; + info += siliconsym; + info += " Gold = "; + info += goldsym; + info += " Calcium = "; + info += calciumsym; + stmt->setString(3,info); + + stmt->executeUpdate(); + conn->commit(); + + conn->terminateStatement(stmt); + big5env->terminateConnection(conn); + Environment::terminateEnvironment(big5env); + } + catch (SQLException &e) + { + cout << "Error : "; + cout << e.getMessage() << endl; + } + + //part2 - use EL8ISO8859P7(Greek) characterset + try + { + cout << "Now creating environment with EL8ISO8859P7(Greek) characterset
" << endl; + Environment *greekenv= Environment::createEnvironment("EL8ISO8859P7","EL8ISO8859P7"); + + Connection *conn = greekenv->createConnection("hr", "hr"); + + cout << "Inserting some information in Greek - Mathematical symbols
" << endl; + + Statement *stmt = + conn->createStatement("INSERT INTO GLOBALINFO_TAB VALUES (:1, :2 ,:3)"); + + stmt->setString(1,"Greek"); + stmt->setString(2,"Mathematical symbols"); + + string info; + info += "alpha = "; + info += "á";//codepoint - 0xE1 in EL8ISO8859P7 + info += " beta = "; + info += "â";//codepoint - 0xE2 + info += " gamma = "; + info += "ã";//codepoint - 0xE3 + info += " delta = "; + info += "ä";//codepoint - 0xE4 + info += " epsilon = "; + info += "å";//codepoint - 0xE5 + stmt->setString(3,info); + stmt->executeUpdate(); + conn->commit(); + } + catch (SQLException &e) + { + cout << "Error : "; + cout << e.getMessage() << endl; + } + + //part3 - use UTF8 characterset and retrieve the data we have inserted + try + { + cout << "Now creating environment with UTF8 characterset
" << endl; + Environment *utf8env= Environment::createEnvironment("UTF8","UTF8"); + + Connection *conn = utf8env->createConnection("hr","hr"); + + cout << "Retrieveing the Chinese & Greek information inserted
" << endl; + + Statement *stmt = + conn->createStatement("SELECT G_LANG, G_INFODESC, G_INFO FROM GLOBALINFO_TAB ORDER BY G_LANG"); + ResultSet *rs = stmt->executeQuery(); + + cout << +"The Unicode data will not display correctly in terminal. \ +To properly view, pipe the output of this program to a text file. \ +Open this text file from a Web browser and set \ +Encoding/Characterset to UTF8
" << endl; + + cout << "=========================================
" << endl; + + while (rs->next()) + { + cout << rs->getString(1) << "," << rs->getString(2) << ","; + cout << rs->getString(3); //Chinese/Greek Info + + cout << "
" << endl; //HTML formatting tag + } + + cout << "=========================================
" << endl; + + stmt->closeResultSet(rs); + conn->terminateStatement(stmt); + + utf8env->terminateConnection(conn); + Environment::terminateEnvironment(utf8env); + + } + catch (SQLException &e) + { + cout << "Error : "; + cout << e.getMessage() << endl; + } + + return 0; +} diff --git a/occimb1.sql b/occimb1.sql new file mode 100644 index 0000000..06a3b13 --- /dev/null +++ b/occimb1.sql @@ -0,0 +1,31 @@ +/* Copyright (c) 2003, 2004, Oracle Corporation. All rights reserved. */ +/* + + NAME + occimb1.sql - Create Objects for OCCI Globalization demo + + DESCRIPTION + + This sql script creates objects for occi multibyte demo + This program assumes sample HR schema is setup. + + NOTES + The database characterset must be UTF8. + + MODIFIED (MM/DD/YY) + sudsrini 08/02/04 - Copyright Info + shiyer 03/05/03 - Creation + +*/ + +connect hr/hr; + +drop table globalinfo_tab; + +create table globalinfo_tab +( + g_lang varchar2(10), + g_infodesc varchar2(50), + g_info varchar2(100) +); + diff --git a/occiobj.cpp b/occiobj.cpp new file mode 100644 index 0000000..499595a --- /dev/null +++ b/occiobj.cpp @@ -0,0 +1,196 @@ +/* Copyright (c) 2001, 2006, Oracle. All rights reserved. */ +/* + NAME + occiobj.cpp - OCCI Embedded Object demo + + DESCRIPTION + This demo performs all DML operations using OCCI interface + on embedded object column of table + + + MODIFIED (MM/DD/YY) + sudsrini 10/22/06 - Username/Password lower case + lburgess 04/14/06 - lowercase passwords + sudsrini 07/23/04 - Copyright Info + idcqe 03/05/01 - Creation + +*/ + +#include +#include "occiobjm.h" + +using namespace oracle::occi; +using namespace std; + +class occiobj +{ + private: + + Environment *env; + Connection *con; + Statement *stmt; + public: + + occiobj (string user, string passwd, string db) + { + env = Environment::createEnvironment (Environment::OBJECT); + occiobjm (env); + con = env->createConnection (user, passwd, db); + } + + ~occiobj () + { + env->terminateConnection (con); + Environment::terminateEnvironment (env); + } + + /** + * Insertion of a row + */ + void insertRow (int c1, int a1, string a2) + { + cout << "Inserting record - Publisher id :" << c1 << + ", Publisher address :" << a1 << ", " << a2 <createStatement (sqlStmt); + stmt->setInt (1, c1); + address *o = new address (); + o->setStreet_no (Number (a1)); + o->setCity (a2); + stmt->setObject (2, o); + stmt->executeUpdate (); + cout << "Insert - Success" << endl; + delete (o); + }catch(SQLException ex) + { + cout<<"Exception thrown for insertRow"<terminateStatement (stmt); + } + + + /** + * updating a row + */ + void updateRow (int c1, int a1, string a2) + { + cout << "Upadating record with publisher id :"<< c1 << endl; + string sqlStmt = + "UPDATE publisher_tab SET publisher_add= :x WHERE publisher_id = :y"; + try{ + stmt = con->createStatement (sqlStmt); + address *o = new address (); + o->setStreet_no (Number (a1)); + o->setCity (a2); + stmt->setObject (1, o); + stmt->setInt (2, c1); + stmt->executeUpdate (); + cout << "Update - Success" << endl; + delete (o); + }catch(SQLException ex) + { + cout<<"Exception thrown for updateRow"<terminateStatement (stmt); + } + + + /** + * deletion of a row + */ + void deleteRow (int c1, int a1, string a2) + { + cout << "Deletion of record where publisher id :" << c1 <createStatement (sqlStmt); + stmt->setInt (1, c1); + + address *o = new address (); + o->setStreet_no (Number (a1)); + o->setCity (a2); + stmt->setObject (2, o); + stmt->executeUpdate (); + cout << "Delete - Success" << endl; + delete (o); + }catch(SQLException ex) + { + cout<<"Exception thrown for deleteRow"<terminateStatement (stmt); + } + + /** + * displaying all the rows in the table + */ + void displayAllRows () + { + string sqlStmt = "SELECT publisher_id, publisher_add FROM publisher_tab \ + order by publisher_id"; + try{ + stmt = con->createStatement (sqlStmt); + ResultSet *rset = stmt->executeQuery (); + + while (rset->next ()) + { + cout << "publisher id: " << rset->getInt (1) + << " publisher address: address (" ; + address *o = (address *)rset->getObject (2); + cout << (int)o->getStreet_no () << ", " << o->getCity () << ")" << endl; + } + + stmt->closeResultSet (rset); + }catch(SQLException ex) + { + cout<<"Exception thrown for displayAllRows"<terminateStatement (stmt); + } + +};//end of class occiobj; + + +int main (void) +{ + string user = "hr"; + string passwd = "hr"; + string db = ""; + + try + { + cout << "occiobj - Exhibiting simple insert, delete & update operations" + " on Oracle objects" << endl; + occiobj *demo = new occiobj (user, passwd, db); + + cout << "displaying all rows before operations" << endl; + demo->displayAllRows (); + + demo->insertRow (12, 122, "MIKE"); + + demo->deleteRow (11, 121, "ANNA"); + + demo->updateRow (23, 123, "KNUTH"); + + cout << "displaying all rows after all operations" << endl; + demo->displayAllRows (); + + delete (demo); + cout << "occiobj - done" << endl; + }catch (SQLException ea) + { + cerr << "Error running the demo: " << ea.getMessage () << endl; + } +} diff --git a/occiobj.typ b/occiobj.typ new file mode 100644 index 0000000..dd788cd --- /dev/null +++ b/occiobj.typ @@ -0,0 +1,3 @@ +CASE=SAME +MAPFILE=occiobjm.cpp +TYPE publ_address as address diff --git a/occipobj.cpp b/occipobj.cpp new file mode 100644 index 0000000..3961049 --- /dev/null +++ b/occipobj.cpp @@ -0,0 +1,199 @@ +/* Copyright (c) 2001, 2006, Oracle. All rights reserved. */ +/* + NAME + occipobj.cpp - OCCI Objects demo using Navigational Access + + DESCRIPTION + This demo uses OCCI navigational access for manipulating persistent + objects demonstrating pinning, unpinning, marking for flush and delete + + + MODIFIED (MM/DD/YY) + sudsrini 10/22/06 - Username/Password lower case + sudsrini 07/23/04 - Copyright Info + idcqe 03/05/01 - Creation + +*/ + +#include +#include "occipobjm.h" + +using namespace oracle::occi; +using namespace std; + +class occipobj +{ + private: + + Environment *env; + Connection *conn; + Statement *stmt; + string tableName; + string typeName; + + public: + + occipobj (string user, string passwd, string db) + { + env = Environment::createEnvironment (Environment::OBJECT); + occipobjm (env); + conn = env->createConnection (user, passwd, db); + } + + ~occipobj () + { + env->terminateConnection (conn); + Environment::terminateEnvironment (env); + } + + void setTableName (string s) + { + tableName = s; + } + + /** + * Insertion of a row + */ + void insertRow (int a1, string a2) + { + cout << "Inserting row ADDRESS (" << a1 << ", " << a2 << ")" << endl; + Number n1(a1); + address *o = new (conn, tableName) address(); + o->setStreet_no(n1); + o->setCity(a2); + conn->commit (); + cout << "Insertion - Successful" << endl; + } + + /** + * updating a row + */ + void updateRow (int b1, int a1, string a2) + { + cout << "Updating a row with attribute a1 = " << b1 << endl; + stmt = conn->createStatement + ("SELECT REF(a) FROM publ_address_tab a WHERE street_no = :x FOR UPDATE"); + stmt->setInt (1, b1); + ResultSet *rs = stmt->executeQuery (); + try{ + if ( rs->next() ) + { + RefAny rany = rs->getRef (1); + Ref
r1(rany); + address *o = r1.ptr(); + o->markModified (); + o->setStreet_no (Number (a1)); + o->setCity (a2); + o->flush (); + } + }catch(SQLException ex) + { + cout<<"Exception thrown updateRow"<commit (); + stmt->closeResultSet(rs); + conn->terminateStatement (stmt); + cout << "Updation - Successful" << endl; + } + + + /** + * deletion of a row + */ + void deleteRow (int a1, string a2) + { + cout << "Deleting a row with object ADDRESS (" << a1 << ", " << a2 + << ")" << endl; + stmt = conn->createStatement + ("SELECT REF(a) FROM publ_address_tab a WHERE street_no = :x AND city = :y FOR UPDATE"); + stmt->setInt (1, a1); + stmt->setString (2, a2); + ResultSet *rs = stmt->executeQuery (); + try{ + if ( rs->next() ) + { + RefAny rany = rs->getRef (1); + Ref
r1(rany); + address *o = r1.ptr(); + o->markDelete (); + } + }catch(SQLException ex) + { + cout<<"Exception thrown for deleteRow"<commit (); + stmt->closeResultSet(rs); + conn->terminateStatement (stmt); + cout << "Deletion - Successful" << endl; + } + + /** + * displaying all the rows in the table + */ + void displayAllRows () + { + string sqlStmt = "SELECT REF (a) FROM publ_address_tab a \ + ORDER BY street_no"; + stmt = conn->createStatement (sqlStmt); + ResultSet *rset = stmt->executeQuery (); + try{ + while (rset->next ()) + { + RefAny rany = rset->getRef (1); + Ref
r1(rany); + address *o = r1.ptr(); + cout << "ADDRESS(" << (int)o->getStreet_no () << ", " << o->getCity () << ")" << endl; + } + }catch(SQLException ex) + { + cout<<"Exception thrown for displayAllRows"<closeResultSet (rset); + conn->terminateStatement (stmt); + } + +}; // end of class occipobj + + +int main (void) +{ + string user = "hr"; + string passwd = "hr"; + string db = ""; + + try + { + cout << "occipobj - Exhibiting simple insert, delete & update operations" + " on persistent objects" << endl; + occipobj *demo = new occipobj (user, passwd, db); + + cout << "Displaying all rows before the opeations" << endl; + demo->displayAllRows (); + + demo->setTableName ("PUBL_ADDRESS_TAB"); + + demo->insertRow (21, "KRISHNA"); + + demo->deleteRow (22, "BOSTON"); + + demo->updateRow (33, 123, "BHUMI"); + + cout << "Displaying all rows after all the operations" << endl; + demo->displayAllRows (); + + delete (demo); + cout << "occipobj - done" << endl; + }catch (SQLException ea) + { + cerr << "Error running the demo: " << ea.getMessage () << endl; + } +} diff --git a/occipobj.typ b/occipobj.typ new file mode 100644 index 0000000..8d53132 --- /dev/null +++ b/occipobj.typ @@ -0,0 +1,3 @@ +CASE=SAME +MAPFILE=occipobjm.cpp +TYPE publ_address as address diff --git a/occipool.cpp b/occipool.cpp new file mode 100644 index 0000000..bde834b --- /dev/null +++ b/occipool.cpp @@ -0,0 +1,129 @@ +/* Copyright (c) 2001, 2008, Oracle. All rights reserved. */ +/* + NAME + occipool.cpp - OCCI Connection Pool Interface demo + + DESCRIPTION : + This program demonstates creating and using of connection pool + + Make sure setup file, occidemo.sql is run prior to running this program. + + MODIFIED (MM/DD/YY) + mvasudev 05/23/08 - Add try/catch blocks + sudsrini 10/22/06 - Username/Password lower case + sudsrini 07/23/04 - Copyright Info + idcqe 03/05/01 - Creation + +*/ + +#include +#include +using namespace oracle::occi; +using namespace std; + +class occipool +{ + private: + + Environment *env; + Connection *con; + Statement *stmt; + public : + /** + * Constructor for the occipool test case. + */ + occipool () + { + env = Environment::createEnvironment (Environment::DEFAULT); + }// end of constructor occipool () + + /** + * Destructor for the occipool test case. + */ + ~occipool () + { + Environment::terminateEnvironment (env); + } // end of ~occipool () + + /** + * The testing logic of the test case. + */ + dvoid select () + { + cout << "occipool - Selecting records using ConnectionPool interface" << + endl; + const string poolUserName = "hr"; + const string poolPassword = "hr"; + const string connectString = ""; + const string username = "hr"; + const string passWord = "hr"; + unsigned int maxConn = 5; + unsigned int minConn = 3; + unsigned int incrConn = 2; + ConnectionPool *connPool; + try{ + connPool = env->createConnectionPool + (poolUserName, poolPassword, connectString, minConn, maxConn, incrConn); + if (connPool) + cout << "SUCCESS - createConnectionPool" << endl; + else + cout << "FAILURE - createConnectionPool" << endl; + con = connPool->createConnection (username, passWord); + if (con) + cout << "SUCCESS - createConnection" << endl; + else + cout << "FAILURE - createConnection" << endl; + }catch(SQLException ex) + { + cout<<"Exception thrown for createConnectionPool"<createStatement + ("SELECT author_id, author_name FROM author_tab"); + ResultSet *rset = stmt->executeQuery(); + while (rset->next()) + { + cout << "author_id:" << rset->getInt (1) << endl; + cout << "author_name:" << rset->getString (2) << endl; + } + stmt->closeResultSet (rset); + con->terminateStatement (stmt); + connPool->terminateConnection (con); + env->terminateConnectionPool (connPool); + }catch(SQLException ex) + { + cout<<"Exception thrown for retrieving data"<select(); + delete demo; + } + catch(SQLException ex) + { + cout< +#include +using namespace oracle::occi; +using namespace std; + +class occiproc +{ + private: + + Environment *env; + Connection *con; + + public : + /** + * Constructor for the occiproc demo program. + */ + occiproc (string user, string passwd, string db) throw (SQLException) + { + env = Environment::createEnvironment (Environment::DEFAULT); + con = env->createConnection (user, passwd, db); + }// end of constructor occiproc (string, string, string ) + + /** + * Destructor for the occiproc demo program. + */ + ~occiproc () throw (SQLException) + { + env->terminateConnection (con); + Environment::terminateEnvironment (env); + } // end of ~occiproc () + + // Function to call a PL/SQL procedure + void callproc () + { + cout << "callproc - invoking a PL/SQL procedure having IN, OUT and IN/OUT "; + cout << "parameters" << endl; + Statement *stmt = con->createStatement + ("BEGIN demo_proc(:v1, :v2, :v3); END;"); + try{ + cout << "Executing the block :" << stmt->getSQL() << endl; + stmt->setInt (1, 10); + stmt->setMaxParamSize (2, 30); + stmt->setString (2, "IN"); + stmt->registerOutParam (3, OCCISTRING, 30, ""); + int updateCount = stmt->executeUpdate (); + cout << "Update Count:" << updateCount << endl; + string c1 = stmt->getString (2); + string c2 = stmt->getString (3); + cout << "Printing the INOUT & OUT parameters:" << endl; + cout << "Col2: " << c1 << endl; + cout << "Col3: " << c2 << endl; + con->terminateStatement (stmt); + cout << "occiproc - done" << endl; + } + catch (SQLException ex){ + cout << ex.getMessage() << endl; + } + } // end of callproc () + + // Function to call a PL/SQL function + void callfun () + { cout << "callfun - invoking a PL/SQL function having IN, OUT and IN/OUT "; + cout << "parameters" << endl; + Statement *stmt = con->createStatement + ("BEGIN :a := demo_fun(:v1, :v2, :v3); END;"); + try{ + cout << "Executing the block :" << stmt->getSQL() << endl; + stmt->setInt (2, 10); + stmt->setMaxParamSize (3, 30); + stmt->setString (3, "IN"); + stmt->registerOutParam (1, OCCISTRING, 30, ""); + stmt->registerOutParam (4, OCCISTRING, 30, ""); + int updateCount = stmt->executeUpdate (); + cout << "Update Count : " << updateCount << endl; + + string c1 = stmt->getString (1); + string c2 = stmt->getString (3); + string c3 = stmt->getString (4); + + cout << "Printing the INOUT & OUT parameters :" << endl; + cout << "Col2: " << c2 << endl; + cout << "Col3: " << c3 << endl; + cout << "Printing the return value of the function: "; + cout << c1 << endl; + + con->terminateStatement (stmt); + cout << "occifun - done" << endl; + } + catch (SQLException ex){ + cout << ex.getMessage() << endl; + } + } // end of callfun () +}; // end of class occiproc + +int main (void) +{ + string user = "hr"; + string passwd = "hr"; + string db = ""; + + cout << "occiproc - invoking a PL/SQL function and procedure having "; + cout << "parameters" << endl; + try{ + occiproc *demo = new occiproc (user, passwd, db); + demo->callproc(); + demo->callfun(); + delete demo; + } + catch (SQLException ex){ + cout << ex.getMessage() << endl; + } + +}// end of main () diff --git a/occiscp.cpp b/occiscp.cpp new file mode 100644 index 0000000..130b44c --- /dev/null +++ b/occiscp.cpp @@ -0,0 +1,193 @@ +/* Copyright (c) 2003, 2006, Oracle. All rights reserved. */ +/* + NAME + occiscp.cpp - OCCI StatelessConnectionPool with Statement Cache + + DESCRIPTION : + This program demonstates the creating and using of + StatelessConnectionPool in the database with statement caching enabled. + + * Create a StatelessConnectionPool. + * Caching can be enabled for all the connections in the pool + by calling setStmtCacheSize(size) on the pool object with + a non-zero value of size. + * Get a connection from the pool. + * If necessary, override the cache size for the connection + with setStmtCacheSize(size) on the connection. + * Create a statement with a call to createStatement(sql, tag) + or createStatement(sql). If the statement is in the cache, + it is returned; if not, a new statement with NULL tag is created + for the user and returned. + * Use the statement to execute SQL commands and obtain results. + * Return the statement back to the cache by calling + terminateStatement(stmt, tag) or terminateStatement(stmt). + Alternately, if the user does not want the statement to be cached, + he can call setDisableStmtCaching(TRUE) on the statement and + then terminateStatement(stmt). This will delete the statement + instead of caching it. + * Release the connection back to the pool. + + NOTE : + Stateless Connection Pool & Statement Cache are two different + features of OCCI and can be used exclusively. + This program makes use of both the features for demonstration purpose only + + MODIFIED (MM/DD/YY) + sudsrini 10/22/06 - Username/Password lower case + sudsrini 07/23/04 - Copyright Info + idcqe 03/05/03 - Creation + +*/ + +#include +#include +using namespace oracle::occi; +using namespace std; + +Environment *env; +int main (void) +{ + env = Environment::createEnvironment (Environment::DEFAULT); + const string poolUserName = "hr"; + const string poolPassword = "hr"; + const string connectString = ""; + unsigned int maxConn = 5; + unsigned int minConn = 3; + unsigned int incrConn = 2; + + cout<<"Demo for StatelessConnectionPool with statement cache"<createStatelessConnectionPool + (poolUserName, poolPassword, connectString, maxConn, + minConn, incrConn, StatelessConnectionPool::HOMOGENEOUS); + + if (scPool) + cout<<"SUCCESS - createStatelessConnectionPool"<getConnection(); + if (con1) + cout<<"SUCCESS - getConnection"<setStmtCacheSize(2); + unsigned size1 = con1->getStmtCacheSize(); + cout<<"The size of cache for the connection is "<releaseConnection (con1, tag); + + // Get the connection with tag = "tagA" from the pool. + con1 = scPool->getConnection (tag); + if (con1) + cout<<"SUCCESS - getConnection"<createStatement(sqlquery1); + ResultSet *rset1 = stmt1->executeQuery (); + cout<<"Retrieving the data"<next()) + { + cout<<"Emp id: "<getInt(1)<closeResultSet ( rset1 ); + //Put the statement into the cache + con1->terminateStatement ( stmt1); + //Check if the statement is in the cache. + bool cached = con1->isCached(sqlquery1); + if (cached) + cout<<"The statement is in the cache"<createStatement(sqlquery2); + ResultSet *rset2 = stmt2->executeQuery (); + cout<<"Retrieving the data"<next()) + { + cout<<"Emp id: "<getInt(1)<closeResultSet ( rset2 ); + + //Put the statement into the cache by tagging it + con1->terminateStatement(stmt2, tag); + + stmt3=con1->createStatement(sqlquery2,tag); + //Remove the statement from the cache + cout<<"Now disable caching on the statement"<disableCaching(); + con1->terminateStatement (stmt3 ); + + //Check if the statement is in the cache. + cached = con1->isCached(sqlquery2, tag); + if (cached) + cout<<"The statement is in the cache"<releaseConnection(con1); + + //Get one tagged connection from the pool + con2 = scPool->getAnyTaggedConnection(tag); + if (con2) + cout<<"SUCCESS - getAnyTaggedConnection"<terminateConnection (con2); + + //Get one more connection from the pool + con3 = scPool->getConnection(); + if (con3) + cout<<"SUCCESS - getConnection"< +#include +using namespace oracle::occi; +using namespace std; + +class occistrm +{ + private: + + Environment *env; + Connection *conn; + + public: + + occistrm (string user, string passwd, string db) + throw (SQLException) + { + env = Environment::createEnvironment (Environment::DEFAULT); + conn = env->createConnection (user, passwd, db); + }// end of constructor occistrm (string, string, string) + + ~occistrm () + throw (SQLException) + { + env->terminateConnection (conn); + Environment::terminateEnvironment (env); + }// end of destructor + + /** + * displaying all the rows in the table + */ + void displayAllRows () + { + Statement *stmt = conn->createStatement ( + "SELECT summary FROM book WHERE bookid = 11"); + stmt->execute (); + ResultSet *rs = stmt->getResultSet (); + rs->setCharacterStreamMode(1, 4000); + char buffer[500]; + int length = 0; + unsigned int size = 500; + try{ + while (rs->next ()) + { + Stream *stream = rs->getStream (1); + while( (length=stream->readBuffer(buffer, size))!=-1) + { + cout << "Read " << length << " bytes from stream" << endl; + } + rs->closeStream(stream); + } + } + catch (SQLException ex){ + cout << ex.getMessage() << endl; + } + stmt->closeResultSet (rs); + conn->terminateStatement (stmt); + }// end of updateRow (string); + +}; // end of class occistrm + + +int main (void) +{ + string user = "hr"; + string passwd = "hr"; + string db = ""; + try{ + cout << "occistrm - Exhibiting usage of streams for VARCHAR2 data" + << endl; + occistrm *demo = new occistrm (user, passwd, db); + + demo->displayAllRows (); + + delete (demo); + } + catch (SQLException ex){ + cout << ex.getMessage() << endl; + } + cout << "occistrm - done" << endl; +}// end of int main (void); diff --git a/occiuni1.cpp b/occiuni1.cpp new file mode 100644 index 0000000..73a9d38 --- /dev/null +++ b/occiuni1.cpp @@ -0,0 +1,186 @@ +/* Copyright (c) 2003, 2006, Oracle. All rights reserved. */ +/* + NAME + occiuni1.cpp - OCCI Globalization Support demo (Unicode) + + DESCRIPTION + Demonstrates OCCI globalization support capabilities :- + + 1.createEnvironment : specifying client characterset & + national characterset of the application + + 2.setUString : binding Unicode data for a NVARCHAR2 + column using OCCI's UString datatype + + 3.setCharSet : specifying charactersets different from the + Environment's for Statement bind and ResultSet fetch + + 4.getString : fetching Unicode data from a NVARCHAR2 + column in UTF8 charset + + Demo schema : - + table Countries_Tab + ( + CID Number(10), Country Id + CENGLISHNAME Varchar2(100), Country name in English + CNATIONALNAME NVarchar2(100), Country name in national language + ) + + Oracle's NVARCHAR2 datatype is capable of storing Unicode data. + + This demo inserts some country names in their national languages( + e.g Japan in japanese) in Unicode(UTF16) and then fetches them in + UTF8 characterset. + + INSTRUCTIONS + ------------ + + 1.Run SQL script - occiuni1.sql before running this program. The + database characterset can be any characterset, the database + national characterset will be one of the Unicode + charactersets : AL16UTF16 or UTF8. + + 2.Run this program and direct output to a file and view the output + file from a browser :- + $ ./occiuni1 > occiuni1.html + + MODIFIED (MM/DD/YY) + sudsrini 10/22/06 - Username/Password lower case + kukannan 03/12/06 - Fix bug 5074203 + sudsrini 07/23/04 - Copyright Info + shiyer 03/05/03 - Creation + +*/ + +#include +#include + +using namespace std; +using namespace oracle::occi; + +//ascii2utf16 - simpile utility function to convert an +//ASCII string to Unicode string +UString ascii2utf16(string asciistr) +{ + UString ustr; + ustr.resize (asciistr.length()); + for (int i = 0; i < asciistr.length(); i++) + ustr[i] = (unsigned short)asciistr[i]; + + return ustr; +} + +int main() +{ + + try + { + +//initialize environment with client characterset = US7ASCII, +//national characterset = UTF16 + Environment *env = Environment::createEnvironment("US7ASCII","OCCIUTF16"); + + Connection *conn = env->createConnection("hr","hr"); + + cout << "Inserting Unicode data in UTF16 characterset
" << endl; + + Statement *stmt = conn->createStatement("insert into Countries_Tab values (:1,:2,:3)"); + +//If the database column type is NCHAR/NVARCHAR2 then need to call +//setDatabaseNCHARParam with true to indicate this. + stmt->setDatabaseNCHARParam(3, true); + +//-------------------1, U.S.A---------------------------------------- + stmt->setInt(1, 1); + stmt->setString(2, "U.S.A"); //data in ASCII + UString uUSA = ascii2utf16("U.S.A");//U.S.A in Unicode + stmt->setUString(3, uUSA);//setUString for binding Unicode + stmt->executeUpdate(); + +//-------------------2, Russia---------------------------------------- + stmt->setInt(1, 2); + stmt->setString(2, "Russia"); +//the 6 Cyrillic Unicode characters for 'Russia'. + unsigned short russiaunicodechars[] = {0x0420,0x043E,0x0441, + 0x0441,0x0438,0x044F}; + UString uRussia(russiaunicodechars,6); + stmt->setUString(3,uRussia); + + stmt->executeUpdate(); + +//-------------------3, Japan---------------------------------------- + stmt->setInt(1, 3); + stmt->setString(2, "Japan"); + +//the 2 Katakana Unicode characters for 'Japan' in japanese + unsigned short japanunicodechars[] = {0x65E5,0x672C}; + UString uJapan(japanunicodechars, 2); + stmt->setUString(3,uJapan); + + stmt->executeUpdate(); + +//-------------------4, Austria---------------------------------------- + stmt->setInt(1, 4); + stmt->setString(2, "Austria"); + +// the client charset & client national charset environment settings +// can be over-ridden for specific columns by calling the setCharSet +// method on Statement/ResultSet + stmt->setCharSet(3, "WE8DEC");//override UTF16 for this column + +//the character Ö (WE8DEC codepoint D6) is for Latin capital letter O with +//Diaresis. Use setString instead of setUString, since not in UTF16 + string aAustria("Österreich");//data in WE8DEC + stmt->setString(3, aAustria); + + stmt->executeUpdate(); + +//commit the inserts. Users can view the inserted data from SQL*Plus or +//ISQL*Plus + conn->commit(); + + conn->terminateStatement(stmt); + +//Now fetch the data. We will fetch the Unicode data (i.e country +//names in national language) in UTF8 charset +//added some HTML
output for formatting in browser + + cout << "Retrieving data in UTF8 characterset
" << endl; + cout << +"The Unicode data will not display correctly in terminal. \ +To properly view, pipe the output of this program to a text file. \ +Open this text file from a Web browser and set \ +Encoding/Characterset to UTF8
" << endl; + cout << "=========================================
" << endl; + + stmt = conn->createStatement("select Cid, CEnglishName, CNationalName from Countries_Tab"); + ResultSet *rs = stmt->executeQuery(); + + rs->setDatabaseNCHARParam(3, true);//NVARCHAR2 column + rs->setCharSet(3, "UTF8"); //explicitly specify characterset + + while (rs->next()) + { + cout << rs->getInt(1) << "," << rs->getString(2) << ","; + cout << rs->getString(3); //country name in UTF8 + + cout << "
" << endl; //HTML formatting tag + } + + cout << "=========================================
" << endl; + + stmt->closeResultSet(rs); + conn->terminateStatement(stmt); + + //terminate connection & environment + env->terminateConnection(conn); + Environment::terminateEnvironment(env); + } + catch (SQLException e) + { + cout << "Error : "; + cout << e.getMessage() << endl; + } + + return 0; +} diff --git a/occiuni1.sql b/occiuni1.sql new file mode 100644 index 0000000..975f591 --- /dev/null +++ b/occiuni1.sql @@ -0,0 +1,30 @@ +/* Copyright (c) 2003, 2005, Oracle. All rights reserved. */ +/* + + NAME + occiuni1.sql - Create Objects for OCCI Globalization demo + + DESCRIPTION + + This sql script creates objects for occi unicode demo + This program assumes sample HR schema is setup. + + + MODIFIED (MM/DD/YY) + sudsrini 08/02/04 - Copyright Info + shiyer 03/05/03 - Creation + +*/ + +connect hr/hr; + +drop table countries_tab; + +create table countries_tab +( + CID Number(10), + CENGLISHNAME Varchar2(100), + CNATIONALNAME NVarchar2(100) +) +/ + diff --git a/occiuni2.cpp b/occiuni2.cpp new file mode 100644 index 0000000..0aa566d --- /dev/null +++ b/occiuni2.cpp @@ -0,0 +1,250 @@ +/* Copyright (c) 2003, 2006, Oracle. All rights reserved. */ +/* + NAME + occiuni2.cpp - OCCI Globalization Support demo (Unicode, Windows specific) + + DESCRIPTION + This is a Microsoft Windows specific demo. + Except for the use of Windows API's and wstring datatypes, other concepts + demonstrated apply to all platforms. + The data file used is also Windows specific. + + Demonstrates the following capabilities :- + 1. Equivalance of OCCI's UString & Windows wstring datatype. + A wstring can be passed to OCCI Unicode interfaces expecting a + UString datatype. A wchar literal (L prefix) can also be passed + for a UString + + 2. Initialize OCCI Environment in Unicode(UTF16) + + 3. Logon & executing statements using the UString interfaces + + 4. Creating & updating persistent objects containing NCLOB + attributes + + 5. Reading & writing Unicode data from/into NCLOBs. Shows use of + Clob::writeChunk & Clob::read methods for wchar data. The Unicode + data is stored in text files. + + 6. OTT generated class definition with UString attribute. + + Schema :- + create type DocObjType as object + ( + DocName varchar2(100), + DocText nclob + ) + + create table DocumentsTab of DocObjType; + + OTT generated C++ class : DocObjType + + INSTRUCTIONS + ------------ + 1.Run SQL script - occiuni2.sql before running this program. + 2.This demo is Microsoft Windows only. + + MODIFIED (MM/DD/YY) + sudsrini 10/22/06 - Username/Password lower case + kukannan 03/12/06 - Fix bug 5074203 + sudsrini 07/23/04 - Copyright Info + shiyer 03/05/03 - Creation + +*/ + +#include +#include +#include + +#include + +//mapping function include +#include "occiuni2m.h" + +using namespace std; +using namespace oracle::occi; + +int main() +{ + cout << "***OCCI Globalization Support demo program.***" << endl; + cout << "***This program loads Unicode data files into a NClob attribute***" << endl; + + char *unicodefiles[4] = {"occiuni2_hindi.txt", "occiuni2_russian.txt", "occiuni2_korean.txt", + "occiuni2_japanese.txt"}; + try + { + + cout << "Initializing OCCI environment in Unicode mode" << endl; + //initialize in Unicode(UTF16) mode + Environment *utf16env = Environment::createEnvironment( "OCCIUTF16", + "OCCIUTF16", Environment::OBJECT ); + occiuni2m(utf16env); + + //"L" prefix will create a widechar i.e Unicode literal which is equivalent to + // OCCI's UString datatype + Connection *conn = utf16env->createConnection( L"hr",L"hr",L"" ); + + //load the 4 sample Unicode files + for (int i = 0; i < 4;i++) + { + //convert the filename argument to Unicode. We will be saving the filename + //as one of the attributes of the object. + const char *asciifilename = unicodefiles[i]; + wchar_t wcfilename[100]; + MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, (LPCSTR)asciifilename, + strlen(asciifilename)+1, (LPWSTR)wcfilename, 100 ); + wstring docname(wcfilename); + + cout << "Loading " << asciifilename << endl; + + + //Create a persistent object, set the NClob to empty and save + //the object. Use the overloaded new operator that takes UString + //arugments + DocObjType *newdoc = new (conn, L"DOCUMENTSTAB",L"DOCOBJTYPE", + L"HR",L"HR") DocObjType(); + + newdoc->setDocname(docname); + + //first insert a empty clob + Clob doccontents(conn); + doccontents.setEmpty(); + newdoc->setDoctext(doccontents);//empty + + conn->commit(); + + //Now, we will select the object again and add the document text + //to the NClob attribute. + Statement *stmt = conn->createStatement( + L"select ref(a) from documentstab a where docname = :1 for update"); + + stmt->setUString(1, docname);//bind wstring + ResultSet *rs = stmt->executeQuery(); + + rs->next();//this will actually fetch the Ref + + Ref docobjref = rs->getRef(1); + DocObjType *docobj = docobjref.ptr();//pin the object + + doccontents = docobj->getDoctext();//get the Clob + doccontents.open(); + + doccontents.setCharSetId("OCCIUTF16"); + doccontents.setCharSetForm(OCCI_SQLCS_NCHAR); + + ifstream in( asciifilename, ios::binary ); + int bytesread=0, totalbytesread=0, wcharsread=0; + wchar_t wbuffer1[50];//50 chars = 100 bytes at a time + + //we have stored the data in a Unicode text file. The first + //character (2 bytes) is a Unicode Byte-Order-Mark and + //indicates whether the data in the file is little-endian or + //big-endian + in.read((char *)wbuffer1,2);//read & skip BOM + int offset = 1; + + while (in.read( (char *)wbuffer1,sizeof(wbuffer1) )) + { + bytesread = in.gcount(); + wcharsread = bytesread/2; + + //write to the NClob + doccontents.writeChunk( wcharsread, (utext *)wbuffer1, sizeof(wbuffer1), offset ); + + offset += wcharsread;//offset is in terms of characters + totalbytesread += bytesread; + } + //last chunk + bytesread = in.gcount(); + wcharsread = bytesread/2; + totalbytesread += bytesread; + + doccontents.writeChunk( wcharsread, (utext *)wbuffer1, bytesread, offset ); + doccontents.close(); + + //update the object and flush to database + docobj->setDoctext(doccontents); + docobj->markModified(); + docobj->flush(); + conn->commit(); + + + cout << totalbytesread/2 << " characters saved" << endl; + + //Statement & ResultSet objects will be created again + stmt->closeResultSet(rs); + conn->terminateStatement(stmt); + }//for (i = 0; i < 4) + + + cout << "Now reading the NClob data back and saving to new files" << endl; + + Statement *selectstmt = conn->createStatement( + L"select ref(a) from DocumentsTab a" ); + ResultSet *queryrs = selectstmt->executeQuery(); + wstring wfilehdrtxt = L"If you cannot see the text properly, try setting your font to a Unicode font like : - Arial Unicode MS, Lucinda Sans Unicode etc..."; + while (queryrs->next()) + { + Ref docobjref = queryrs->getRef(1); + + wstring docname = docobjref->getDocname(); + + //create the output file, prepend "fetch_" to the original filename + docname = L"fetch_" + docname; + char asciifilenamebuf[100]; + + int ret = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)docname.c_str(), + docname.length()+1, (LPSTR)asciifilenamebuf, 100, NULL, NULL); + + cout << "Creating Unicode textfile " << asciifilenamebuf << endl; + ofstream outdoc(asciifilenamebuf, ios_base::binary | ios_base::trunc); + + //first write the BOM + wchar_t bom = 0xFEFF;//Windows is little-endian + outdoc.write((char *)&bom, 2); + + outdoc.write((char *)wfilehdrtxt.c_str(), wfilehdrtxt.length()*2); + + Clob doccontents = docobjref->getDoctext(); + doccontents.setCharSetId("OCCIUTF16"); + doccontents.setCharSetForm(OCCI_SQLCS_NCHAR); + int offset = 1; + int clobcharsread=0; + //now read the NClob and write to file + wchar_t wbuffer2[100];//100 chars at a time + while ( (clobcharsread = + doccontents.read(100, wbuffer2, sizeof(wbuffer2), offset)) !=0 ) + { + offset = offset+clobcharsread; + outdoc.write((char *)wbuffer2,clobcharsread*2);//write takes number of bytes + } + outdoc.close(); + + }//while (queryrs->next()) + + //done + cout << "You can view the created files in Notepad(or any other editor that displays Unicode)" << endl; + selectstmt->closeResultSet(queryrs); + conn->terminateStatement(selectstmt); + + //delete the rows from the table + //if you want to retain the rows, comment out + cout << "Cleaning up table" << endl; + Statement *deletestmt = conn->createStatement( + L"delete from DocumentsTab"); + deletestmt->executeUpdate(); + + conn->commit(); + + utf16env->terminateConnection(conn); + Environment::terminateEnvironment(utf16env); + + cout << "Done" << endl; + + } + catch (SQLException &e) + { + std::cout << e.getErrorCode() << std::endl; + } + return 0; +} diff --git a/occiuni2.sql b/occiuni2.sql new file mode 100644 index 0000000..6b7f0d2 --- /dev/null +++ b/occiuni2.sql @@ -0,0 +1,36 @@ +/* Copyright (c) 2003, 2005, Oracle. All rights reserved. */ +/* + + NAME + occiuni2.sql - Create Objects for OCCI Globalization demo + + DESCRIPTION + + This sql script creates objects for OCCI Windows Specific unicode demo + This program assumes sample HR schema is setup. + + NOTES + The demo to be run only on windows + + MODIFIED (MM/DD/YY) + sudsrini 08/02/04 - Copyright Info + shiyer 03/05/03 - Creation + +*/ + +connect hr/hr + +drop table DocumentsTab; + +drop type DocObjType; + +create type DocObjType as object +( + DocName varchar2(100), + --nclob to store Unicode data + DocText nclob +) +/ + +create table DocumentsTab of DocObjType; + diff --git a/occiuni2.typ b/occiuni2.typ new file mode 100644 index 0000000..075fbd0 --- /dev/null +++ b/occiuni2.typ @@ -0,0 +1,4 @@ +MAPFILE=occiuni2m.cpp +TYPE docobjtype as DocObjType +TRANSLATE docname as DocName + doctext as DocText diff --git a/occiuni2_hindi.txt b/occiuni2_hindi.txt new file mode 100644 index 0000000..7d2f3d6 Binary files /dev/null and b/occiuni2_hindi.txt differ diff --git a/occiuni2_japanese.txt b/occiuni2_japanese.txt new file mode 100644 index 0000000..7ab4eb4 Binary files /dev/null and b/occiuni2_japanese.txt differ diff --git a/occiuni2_korean.txt b/occiuni2_korean.txt new file mode 100644 index 0000000..c8ceadb Binary files /dev/null and b/occiuni2_korean.txt differ diff --git a/occiuni2_russian.txt b/occiuni2_russian.txt new file mode 100644 index 0000000..646481d Binary files /dev/null and b/occiuni2_russian.txt differ diff --git a/occixa.cpp b/occixa.cpp new file mode 100644 index 0000000..8f9604a --- /dev/null +++ b/occixa.cpp @@ -0,0 +1,321 @@ +/* Copyright (c) 2003, 2009, Oracle and/or its affiliates. +All rights reserved. */ +/* + NAME + occixa.cpp: OCCI XA interface demo + + DESCRIPTION + This program creates an XA Environment, gets an XA Connection from the + created environment, uses the XA connection to do DMLs on a table. + + The key APIs that are used are: + - getXAEnviroment + - getXAConnection + - getXAErrorCode + - releaseXAConnection + - releaseXAEnvironment + + For more more information, please refer Oracle documentaion. + + MODIFIED (MM/DD/YY) + sudsrini 07/08/09 - Include string.h, iostream not including it on sles11 + sudsrini 10/22/06 - Username/Password lower case + sudsrini 07/23/04 - Copyright Info + shiyer 03/05/03 - Creation + +*/ + +#include +#include +#include +#include // Should be included for all OCCI XA interface + +using namespace oracle::occi; +using namespace std; + +#ifdef WIN32COMMON + extern "C" __declspec(dllimport) struct xa_switch_t xaosw; + extern "C" __declspec(dllimport) struct xa_switch_t xaoswd; +#else + extern struct xa_switch_t xaosw; + extern struct xa_switch_t xaoswd; +#endif + +static XID xidx = { 0x1e0a0a1e, 12, 8, "KeesGTID01Branch0001" }; +static XID *xid = &xidx; + +class occixa +{ + +private : + struct xa_switch_t *xafunc ; + Environment *xaenvrnmnt; + Connection *xaConnection; + +public : + +occixa () +{ +} + +~occixa () +{ +} + +void test (Connection *conn) +{ + Statement *stmt; + + showln("Invoking createStatement using XA Connection"); + stmt = conn->createStatement + ("INSERT INTO EMPLOYEES (employee_id, last_name, email,hire_date,job_id) \ + values (998, 'Mike', 'x1@y.com','12-Mar-1970','AC_ACCOUNT')"); + + showln("Inserting Records into Local Database"); + stmt->executeUpdate(); + + showln("Selecting Records From Local Database using XA Connection"); + displayQueryResult ( conn, + "SELECT Employee_id,last_name FROM EMPLOYEES where employee_id \ + between 998 and 999 ORDER BY 1,2" ); + + showln("Deleting the inserted Records from Database"); + stmt = conn->createStatement + ("DELETE EMPLOYEES where employee_id between 998 and 999"); + + stmt->executeUpdate(); + + showln("Terminating the Statements using XA Connection "); + conn->terminateStatement (stmt); + +} + +// This function establishes an XA connection to the resource manager +void startXATest (string uname, string pwd, string db , XID *xid ) +{ + + int xarslt = 0; // xa result code + int rmid = 1; + char *xaoinfo; + this->xafunc = &xaoswd; + + //Forming the xaoinfo1 string which has to be sent as a parameter for + //xa_open_entry function call. + + string xaoinfo1 = "oracle_xa+ACC=P/"; + xaoinfo1 += uname; + xaoinfo1 +="/"; + xaoinfo1 += pwd; + + //For an Object Test this parameter OBJECTS=T should also be given to the + //xaoinfo string ( a parameter of the xa_open_entry function call) + + #ifdef OBJECTS + xaoinfo1 +="+OBJECTS=T"; + #endif + + //To open an entry for XA with a remote database, DB="database_name" + //should also be given to the xaoinfo string ( a parameter of the + //xa_open_entry function call) + + if (!db.empty()) + xaoinfo1 += "+SESTM=50+logdir=.+DB="+db; + else + xaoinfo1 += "+SESTM=50+logdir=."; + xaoinfo=(char *)xaoinfo1.c_str(); + + // Connects to the resource manager + xarslt = xafunc->xa_open_entry(xaoinfo, rmid, TMNOFLAGS); + + if ( xarslt ) + cout << "xaoopen = " << xarslt << endl; + + XID *t = xid; + int i; + for (i=0;i<64;i++) + t->data[i] = '\0'; + t->formatID = 1; + t->gtrid_length = 8; + for (i=0;igtrid_length;i++) + t->data[i] = 1; + t->bqual_length = 4; + for (i=0;ibqual_length;i++) + t->data[i+t->gtrid_length] = 1; + xid=t; + + // Starts a new transaction and associates it with the given transaction ID (XID) + xarslt = xafunc->xa_start_entry(xid, rmid, TMNOFLAGS); + + if ( xarslt ) + cout << "xaostart = " << xarslt << endl; + + try + { + // This method returns a pointer to OCCI Environment Object that corresponds + // to the one opened by the XA Library + // db represents the database name in which the XA Environment is created + + xaenvrnmnt = Environment::getXAEnvironment(db); + } + catch(SQLException &ex) + { + cout << ex.what() << endl; + + //This method returns an XA error code when a XA exception is encountered. + //It returns a XA_OK if the error is not due to XA.It takes db as paramter. + + int error = ex.getXAErrorCode(db); + if(error==XA_OK) + cout << "Error in SQL processing" << endl; + else + cout << "XA Error Code:" << error << endl; + } + + try + { + // This method returns a pointer to an OCCI Connection object that corresponds + // to the one opened by the XA Library. + //db represents the database name to which the XA Connection is got + + xaConnection = xaenvrnmnt->getXAConnection(db); + } + catch(SQLException &ex) + { + cout << ex.what() << endl; + int error = ex.getXAErrorCode(db); + if(error==XA_OK) + cout << "Error in SQL processing" << endl; + else + cout << "XA Error Code:" << error << endl; + } + + try + { + test ( xaConnection ); + } + catch (SQLException ea) + { + showError (ea); + } + + try + { + //This method releases/de-allocates the neccessary handles allocated by the + //getXAConnection call. It takes XA Connection as the parameter + + xaenvrnmnt->releaseXAConnection (xaConnection); + } + catch(SQLException &ex) + { + cout << ex.what() << endl; + int error = ex.getXAErrorCode(db); + if(error==XA_OK) + cout << "Error in SQL processing" << endl; + else + cout << "XA Error Code:" << error << endl; + } + + // Disassociates the process from the given XID + xarslt = xafunc->xa_end_entry(xid, rmid, TMSUCCESS); + if ( xarslt ) + cout << "xaoend = " << xarslt << endl; + + // Prepares the transaction associated with the given XID. First phase of + // two-phase commit protocol. + xarslt = xafunc->xa_prepare_entry(xid, rmid, TMNOFLAGS); + if ( xarslt ) + cout << "xaoprepare = " << xarslt << endl; + + // Commits the transaction associated with the given XID. Second phase of + // two-phase commit protocol. + xarslt = xafunc->xa_commit_entry(xid, rmid, TMNOFLAGS); + if ( xarslt ) + cout << "xaocommit = " << xarslt << endl; + + try + { + //This call releases the neccessary handles allocated by the + //getXAEnvironment call. It takes XA Environment as the parameter + + Environment::releaseXAEnvironment (xaenvrnmnt); + } + catch(SQLException &ex) + { + cout << ex.what() << endl; + int error = ex.getXAErrorCode(db); + if(error==XA_OK) + cout << "Error in SQL processing" << endl; + else + cout << "XA Error Code:" << error << endl; + } + + // Disconnects from the resource manager. + xarslt = xafunc->xa_close_entry(xaoinfo, rmid, TMNOFLAGS); + if ( xarslt ) + { + cout << "xaoclose = " << xarslt << endl; + } + +} + +dvoid displayQueryResult (Connection* conn, string sqlQuery) +{ + Statement *stmt = conn->createStatement (sqlQuery); + int i=0; + try + { + ResultSet *rs = stmt->executeQuery (); + while (rs->next ()) + { + int a = rs->getInt (1); + cout << "Col 1" << ": " << a << endl; + string ch = rs->getString (2); + cout << "Col 2" << ": " << ch << endl; + + } + stmt->closeResultSet (rs); + } + catch ( SQLException e ) + { + showError ( e ); + conn->terminateStatement (stmt); + throw; + } + + conn->terminateStatement (stmt); +} + +dvoid showError (SQLException ex) +{ + showln ("Error number: ") << ex.getErrorCode() << endl; + showln (ex.getMessage()) << endl; +} + + +ostream& showln (string str) +{ + return cout << str << endl; +} +}; + +int main ( int argc, char* argv[]) +{ + string userName = "hr"; + string password = "hr"; + string database =""; + + occixa* h = new occixa(); + + // Gets an XA Connection to the default database, uses the XA Connection + // to Insert/Select from a table with/without database link + + try + { + h->startXATest (userName, password, database,xid); + } + catch (SQLException ea) + { + h->showError (ea); + } + +} diff --git a/oci02.c b/oci02.c new file mode 100644 index 0000000..0fbdd40 --- /dev/null +++ b/oci02.c @@ -0,0 +1,353 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci02.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests single row fetch of a query with a bind by position + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + aliu 01/05/06 - add order by in the select to fix intermittent + diffs + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/22/97 - Fix VMS porting exceptions + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci02.c + * + * Description: This program retrieves the column information for a set of + * tables called TESTxx where xx is a number. + * + * It illustrates getting data back using SINGLE ROW FETCH + * via a SELECT statement. + * It also illustrates re-executing the same query again without + * having to rebind + * + * Based on: oci01.c + * Changes: added obndrn call + * added where clause to query with :1 + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires ONE argument - the number of tables + * + * oci02 4 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndrn + * Describe - none Hard-coded query + * Define - odefin + * Execute - oexec + * Fetch - ofetch + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/(sizeof(size_t))]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +text tabname [MAX_NAME_LENGTH+1]; /* table name - generated on the fly */ +uword tabnum = 0; /* table number */ +uword row_count = 0; /* number of rows returned so far */ + + +/* Function prototypes */ +void gentable(); +void logon (); +void logoff (); +void setup(); +void err_report(); +void get_data(); +void dump_data(); +void do_exit(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"SELECT cname, clength, colid \ + FROM ocicolu \ + WHERE tname = :1 order by colid"; + +/* return values from query - kept as globals for simplicity */ +uword colid; +uword collen; +text cname [MAX_NAME_LENGTH+1]; + +main(argc, argv) +eword argc; +text **argv; +{ + + uword numtabs; /* number of tables requested */ + uword tabindex; /* for loop index */ + + if (argc != 2) + { + printf("\n\n Usage: where numtabs is the number of \ +tables with name TESTxx \n\n\n"); + do_exit(OCI_EXIT_FAILURE); + } + + numtabs = atoi((char *)argv[1]); + printf("\n Number of tables is %d\n", numtabs); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + for (tabindex = 0; tabindex < numtabs; tabindex++) + { + gentable(); + get_data(); /* retrieve data */ + } + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndrn(&cda, 1, (ub1 *)tabname, (sword)sizeof(tabname), /* bind */ + SQLT_STR, -1, (sb2 *) 0, (text *) 0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (odefin(&cda, 1, (ub1 *) cname, (sword) sizeof(cname), /* define */ + (sword) SQLT_STR, + (sword) -1, (sb2 *) 0, (text *) 0, -1, -1, + (ub2 *) 0, (ub2 *) 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (odefin(&cda, 2, (ub1 *) &collen, (sword) sizeof(uword), + (sword) SQLT_INT, + (sword) -1, (sb2 *) 0, (text *) 0, -1, -1, + (ub2 *) 0, (ub2 *) 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (odefin(&cda, 3, (ub1 *) &colid, (sword) sizeof(uword), + (sword) SQLT_INT, + (sword) -1, (sb2 *) 0, (text *) 0, -1, -1, + (ub2 *) 0, (ub2 *) 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: get_data + * + * Description: This routine actually executes the cursor and fetches the + * data. It calls dump_data to print the data + * + */ +void get_data() +{ + + if (oexec(&cda)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + printf("\n printing column information for table %s :\n\n", tabname); + + while (ofetch(&cda) == 0) + { + row_count++; /* bump this for printing purposes */ + dump_data(); + } + + if (cda.rc != NO_DATA_FOUND) + err_report(&cda); + + row_count = 0; /* reset for next table */ + +} + +/* + * Function: dump_data + * + * Description: This routine prints out the row/s from each fetch + * + */ +void dump_data() +{ + printf(" column %d name is %s\n", row_count, cname); + printf(" column %d length is %d \n", row_count, collen); + printf(" column %d id is %d \n", row_count, colid); + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: gentable + * + * Description: This routine generates the next table name of the form TESTxx + * + */ +void gentable() +{ + + tabnum++; /* generate the next table name */ + sprintf((char *)tabname, "TEST%d", tabnum); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci02.sql b/oci02.sql new file mode 100644 index 0000000..e2924c9 --- /dev/null +++ b/oci02.sql @@ -0,0 +1,54 @@ +rem +rem $Header: oci02.sql 11-oct-2006.15:55:31 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci02.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci02.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +rem +rem create a view to get the name, length and colid of all the columns in +rem a table +create or replace view ocicol + (tobjid, townerid, tname, cname, clength, colid) AS + SELECT o$.obj#, o$.owner#, o$.name, c$.name, c$.length, c$.col# + FROM sys.col$ c$, sys.obj$ o$ + WHERE o$.obj# = c$.obj# +/ + +CREATE OR REPLACE view ocicolu AS /* user version for ocitest */ + SELECT * from ocicol WHERE townerid = uid +/ +grant select on ocicolu to public; +drop public synonym ocicolu; +create public synonym ocicolu for sys.ocicolu; + +rem +rem Create a new user - call it ocitest +rem +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect, resource to ocitest; + +rem +rem Created needed tables +rem +connect ocitest/OCITEST; + +create table test1 (col1 number); +create table test2 (col1 number, col2 number); +create table test3 (col1 number, col2 number, col3 number); +create table test4 (this_col_name_is_30_chars_long number, + two long, three date, four char(10)); + diff --git a/oci03.c b/oci03.c new file mode 100644 index 0000000..2b332cf --- /dev/null +++ b/oci03.c @@ -0,0 +1,353 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci03.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests single row fetch using bind by value + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + aliu 01/05/06 - add order by in the select statements to fix + intermittent diffs + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/22/97 - Fix VMS porting exceptions + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci03.c + * + * Description: This program retrieves the column information for a set of + * tables called TESTxx where xx is a number. + * + * It illustrates getting data back using SINGLE ROW FETCH + * via a SELECT statement. + * It also illustrates re-executing the same query again without + * having to rebind + * + * Based on: oci02.c + * Changes: changed obndrn call to obndrv + * changed query where clause to :tabname + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires ONE argument - the number of tables + * + * oci03 4 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndrv + * Describe - none Hard-coded query + * Define - odefin + * Execute - oexec + * Fetch - ofetch + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/(sizeof(size_t))]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +text tabname [MAX_NAME_LENGTH+1]; /* table name - generated on the fly */ +uword tabnum = 0; /* table number */ +uword row_count = 0; /* number of rows returned so far */ + + +/* Function prototypes */ +void gentable(); +void logon (); +void logoff (); +void setup(); +void err_report(); +void get_data(); +void dump_data(); +void do_exit(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"SELECT cname, clength, colid \ + FROM ocicolu\ + WHERE tname = :tabname order by colid"; + +/* return values from query - kept as globals for simplicity */ +uword colid; +uword collen; +text cname [MAX_NAME_LENGTH+1]; + +main(argc, argv) +eword argc; +text **argv; +{ + + uword numtabs; /* number of tables requested */ + uword tabindex; /* for loop index */ + + if (argc != 2) + { + printf("\n\n Usage: where numtabs is the number of \ +tables with name TESTxx \n\n\n"); + do_exit(OCI_EXIT_FAILURE); + } + + numtabs = atoi((char *)argv[1]); + printf("\n Number of tables is %d\n", numtabs); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + for (tabindex = 0; tabindex < numtabs; tabindex++) + { + gentable(); + get_data(); /* retrieve data */ + } + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndrv(&cda, (text *)":tabname", -1, + (ub1 *)tabname, (sword)sizeof(tabname), + SQLT_STR, -1, (sb2 *) 0, (text *) 0, -1, -1)) /* bind */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (odefin(&cda, 1, (ub1 *) cname, (sword) sizeof(cname), /* define */ + (sword) SQLT_STR, + (sword) -1, (sb2 *) 0, (text *) 0, -1, -1, + (ub2 *) 0, (ub2 *) 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (odefin(&cda, 2, (ub1 *) &collen, (sword) sizeof(uword), + (sword) SQLT_INT, + (sword) -1, (sb2 *) 0, (text *) 0, -1, -1, + (ub2 *) 0, (ub2 *) 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (odefin(&cda, 3, (ub1 *) &colid, (sword) sizeof(uword), + (sword) SQLT_INT, + (sword) -1, (sb2 *) 0, (text *) 0, -1, -1, + (ub2 *) 0, (ub2 *) 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: get_data + * + * Description: This routine actually executes the cursor and fetches the + * data. It calls dump_data to print the data + * + */ +void get_data() +{ + + if (oexec(&cda)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + printf("\n printing column information for table %s :\n\n", tabname); + + while (ofetch(&cda) == 0) + { + row_count++; /* bump this for printing purposes */ + dump_data(); + } + + if (cda.rc != NO_DATA_FOUND) + err_report(&cda); + + row_count = 0; /* reset for next table */ +} + +/* + * Function: dump_data + * + * Description: This routine prints out the row/s from each fetch + * + */ +void dump_data() +{ + printf(" column %d name is %s\n", row_count, cname); + printf(" column %d length is %d \n", row_count, collen); + printf(" column %d id is %d \n", row_count, colid); + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: gentable + * + * Description: This routine generates the next table name of the form TESTxx + * + */ +void gentable() +{ + + tabnum++; /* generate the next table name */ + sprintf((char *)tabname, "TEST%d", tabnum); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci03.sql b/oci03.sql new file mode 100644 index 0000000..48760f9 --- /dev/null +++ b/oci03.sql @@ -0,0 +1,54 @@ +rem +rem $Header: oci03.sql 11-oct-2006.15:55:31 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci03.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci03.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +rem +rem create a view to get the name, length and colid of all the columns in +rem a table +create or replace view ocicol + (tobjid, townerid, tname, cname, clength, colid) AS + SELECT o$.obj#, o$.owner#, o$.name, c$.name, c$.length, c$.col# + FROM sys.col$ c$, sys.obj$ o$ + WHERE o$.obj# = c$.obj# +/ + +CREATE OR REPLACE view ocicolu AS /* user version for ocitest */ + SELECT * from ocicol WHERE townerid = uid +/ +grant select on ocicolu to public; +drop public synonym ocicolu; +create public synonym ocicolu for sys.ocicolu; + +rem +rem Create a new user - call it ocitest +rem +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect, resource to ocitest; + +rem +rem Created needed tables +rem +connect ocitest/OCITEST; + +create table test1 (col1 number); +create table test2 (col1 number, col2 number); +create table test3 (col1 number, col2 number, col3 number); +create table test4 (this_col_name_is_30_chars_long number, + two long, three date, four char(10)); + diff --git a/oci04.c b/oci04.c new file mode 100644 index 0000000..f13558e --- /dev/null +++ b/oci04.c @@ -0,0 +1,354 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci04.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests single row fetch of a query with an array bind of a scalar + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + aliu 01/05/06 - add order by in the select statements to fix + intermittent diffs + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/22/97 - Fix VMS porting exceptions + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci04.c + * + * Description: This program retrieves the column information for a set of + * tables called TESTxx where xx is a number. + * + * It illustrates getting data back using SINGLE ROW FETCH + * via a SELECT statement. + * It also illustrates re-executing the same query again without + * having to rebind + * + * Based on: oci02.c + * Changes: changed obndrn call to obndra call + * modified where clause to include :tabname + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires ONE argument - the number of tables + * + * oci04 4 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - odefin + * Execute - oexec + * Fetch - ofetch + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/(sizeof(size_t))]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +text tabname [MAX_NAME_LENGTH+1]; /* table name - generated on the fly */ +uword tabnum = 0; /* table number */ +uword row_count = 0; /* number of rows returned so far */ + + +/* Function prototypes */ +void gentable(); +void logon (); +void logoff (); +void setup(); +void err_report(); +void get_data(); +void dump_data(); +void do_exit(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"SELECT cname, clength, colid \ + FROM ocicolu\ + WHERE tname = :tabname order by colid"; + +/* return values from query - kept as globals for simplicity */ +uword colid; +uword collen; +text cname [MAX_NAME_LENGTH+1]; + +main(argc, argv) +eword argc; +text **argv; +{ + + uword numtabs; /* number of tables requested */ + uword tabindex; /* for loop index */ + + if (argc != 2) + { + printf("\n\n Usage: where numtabs is the number of \ +tables with name TESTxx \n\n\n"); + do_exit(OCI_EXIT_FAILURE); + } + + numtabs = atoi((char *)argv[1]); + printf("\n Number of tables is %d\n", numtabs); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + for (tabindex = 0; tabindex < numtabs; tabindex++) + { + gentable(); + get_data(); /* retrieve data */ + } + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndra(&cda, (text *)":tabname", -1, + (ub1 *)tabname, (sword)sizeof(tabname), + SQLT_STR, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) /* bind */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (odefin(&cda, 1, (ub1 *) cname, (sword) sizeof(cname), /* define */ + (sword) SQLT_STR, + (sword) -1, (sb2 *) 0, (text *) 0, -1, -1, + (ub2 *) 0, (ub2 *) 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (odefin(&cda, 2, (ub1 *) &collen, (sword) sizeof(uword), + (sword) SQLT_INT, + (sword) -1, (sb2 *) 0, (text *) 0, -1, -1, + (ub2 *) 0, (ub2 *) 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (odefin(&cda, 3, (ub1 *) &colid, (sword) sizeof(uword), + (sword) SQLT_INT, + (sword) -1, (sb2 *) 0, (text *) 0, -1, -1, + (ub2 *) 0, (ub2 *) 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: get_data + * + * Description: This routine actually executes the cursor and fetches the + * data. It calls dump_data to print the data + * + */ +void get_data() +{ + + if (oexec(&cda)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + printf("\n printing column information for table %s :\n\n", tabname); + + while (ofetch(&cda) == 0) + { + row_count++; /* bump this for printing purposes */ + dump_data(); + } + + if (cda.rc != NO_DATA_FOUND) + err_report(&cda); + + row_count = 0; /* reset for next table */ +} + +/* + * Function: dump_data + * + * Description: This routine prints out the row/s from each fetch + * + */ +void dump_data() +{ + printf(" column %d name is %s\n", row_count, cname); + printf(" column %d length is %d \n", row_count, collen); + printf(" column %d id is %d \n", row_count, colid); + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: gentable + * + * Description: This routine generates the next table name of the form TESTxx + * + */ +void gentable() +{ + + tabnum++; /* generate the next table name */ + sprintf((char *)tabname, "TEST%d", tabnum); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci04.sql b/oci04.sql new file mode 100644 index 0000000..05aab1e --- /dev/null +++ b/oci04.sql @@ -0,0 +1,54 @@ +rem +rem $Header: oci04.sql 11-oct-2006.15:55:31 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci04.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci01.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +rem +rem create a view to get the name, length and colid of all the columns in +rem a table +create or replace view ocicol + (tobjid, townerid, tname, cname, clength, colid) AS + SELECT o$.obj#, o$.owner#, o$.name, c$.name, c$.length, c$.col# + FROM sys.col$ c$, sys.obj$ o$ + WHERE o$.obj# = c$.obj# +/ + +CREATE OR REPLACE view ocicolu AS /* user version for ocitest */ + SELECT * from ocicol WHERE townerid = uid +/ +grant select on ocicolu to public; +drop public synonym ocicolu; +create public synonym ocicolu for sys.ocicolu; + +rem +rem Create a new user - call it ocitest +rem +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect, resource to ocitest; + +rem +rem Created needed tables +rem +connect ocitest/OCITEST; + +create table test1 (col1 number); +create table test2 (col1 number, col2 number); +create table test3 (col1 number, col2 number, col3 number); +create table test4 (this_col_name_is_30_chars_long number, + two long, three date, four char(10)); + diff --git a/oci05.c b/oci05.c new file mode 100644 index 0000000..2f221e4 --- /dev/null +++ b/oci05.c @@ -0,0 +1,368 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci05.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests single row fetch with cancellation + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + aliu 01/05/06 - add order by in the select statements to fix + intermittent diffs + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/22/97 - Fix VMS porting exceptions + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci05.c + * + * Description: This program retrieves the column information for a set of + * tables called TESTxx where xx is a number. + * + * It illustrates getting data back using SINGLE ROW FETCH + * via a SELECT statement. + * It also illustrates re-executing the same query again without + * having to rebind + * + * Based on: oci02.c + * Changes: call ocan after 4 (arbitrary number) rows have been fetched + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires ONE argument - the number of tables + * + * oci05 4 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndrn + * Describe - none Hard-coded query + * Define - odefin + * Execute - oexec + * Fetch - ofetch + * Close - oclose + * Logoff - olof + * Cancel - ocan Cancel cursor after 4 rows + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +#define CANCEL_ROWS 4 /* cancel after 4 rows - arbitrary number */ + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/(sizeof(size_t))]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +text tabname [MAX_NAME_LENGTH+1]; /* table name - generated on the fly */ +uword tabnum = 0; /* table number */ +uword row_count = 0; /* number of rows returned so far */ + + +/* Function prototypes */ +void gentable(); +void logon (); +void logoff (); +void setup(); +void err_report(); +void get_data(); +void dump_data(); +void do_exit(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"SELECT cname, clength, colid \ + FROM ocicolu\ + WHERE tname = :1 order by colid"; + +/* return values from query - kept as globals for simplicity */ +uword colid; +uword collen; +text cname [MAX_NAME_LENGTH+1]; + +main(argc, argv) +eword argc; +text **argv; +{ + + uword numtabs; /* number of tables requested */ + uword tabindex; /* for loop index */ + + if (argc != 2) + { + printf("\n\n Usage: where numtabs is the number of \ +tables with name TESTxx \n\n\n"); + do_exit(OCI_EXIT_FAILURE); + } + + numtabs = atoi((char *)argv[1]); + printf("\n Number of tables is %d\n", numtabs); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + for (tabindex = 0; tabindex < numtabs; tabindex++) + { + gentable(); + get_data(); /* retrieve data */ + } + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndrn(&cda, 1, (ub1 *)tabname, (sword)sizeof(tabname), /* bind */ + SQLT_STR, -1, (sb2 *) 0, (text *) 0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (odefin(&cda, 1, (ub1 *) cname, (sword) sizeof(cname), /* define */ + (sword) SQLT_STR, + (sword) -1, (sb2 *) 0, (text *) 0, -1, -1, + (ub2 *) 0, (ub2 *) 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (odefin(&cda, 2, (ub1 *) &collen, (sword) sizeof(uword), + (sword) SQLT_INT, + (sword) -1, (sb2 *) 0, (text *) 0, -1, -1, + (ub2 *) 0, (ub2 *) 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (odefin(&cda, 3, (ub1 *) &colid, (sword) sizeof(uword), + (sword) SQLT_INT, + (sword) -1, (sb2 *) 0, (text *) 0, -1, -1, + (ub2 *) 0, (ub2 *) 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: get_data + * + * Description: This routine actually executes the cursor and fetches the + * data. It calls dump_data to print the data + * + */ +void get_data() +{ + + if (oexec(&cda)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + printf("\n printing column information for table %s :\n\n", tabname); + + while (ofetch(&cda) == 0) + { + row_count++; /* bump this for printing purposes */ + dump_data(); + + if ((row_count == CANCEL_ROWS) && (cda.rc == 0)) + { + printf(" Cancelling query after %d rows retrieved \n", row_count); + if (ocan(&cda)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + row_count = 0; /* reset since we are returning prematurely */ + return; + } + + } + + if (cda.rc != NO_DATA_FOUND) + err_report(&cda); + + row_count = 0; /* reset for next table */ + +} + +/* + * Function: dump_data + * + * Description: This routine prints out the row/s from each fetch + * + */ +void dump_data() +{ + printf(" column %d name is %s\n", row_count, cname); + printf(" column %d length is %d \n", row_count, collen); + printf(" column %d id is %d \n", row_count, colid); + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: gentable + * + * Description: This routine generates the next table name of the form TESTxx + * + */ +void gentable() +{ + + tabnum++; /* generate the next table name */ + sprintf((char *)tabname, "TEST%d", tabnum); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci05.sql b/oci05.sql new file mode 100644 index 0000000..4044697 --- /dev/null +++ b/oci05.sql @@ -0,0 +1,65 @@ +rem +rem $Header: oci05.sql 11-oct-2006.15:55:31 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci05.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci05.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +connect sys/knl_test7 as sysdba; +rem +rem create a view to get the name, length and colid of all the columns in +rem a table +create or replace view ocicol + (tobjid, townerid, tname, cname, clength, colid) AS + SELECT o$.obj#, o$.owner#, o$.name, c$.name, c$.length, c$.col# + FROM sys.col$ c$, sys.obj$ o$ + WHERE o$.obj# = c$.obj# +/ + +CREATE OR REPLACE view ocicolu AS /* user version for ocitest */ + SELECT * from ocicol WHERE townerid = uid +/ +grant select on ocicolu to public; +drop public synonym ocicolu; +create public synonym ocicolu for sys.ocicolu; + +rem +rem Create a new user - call it ocitest +rem +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect, resource to ocitest; + +rem +rem Created needed tables +rem +connect ocitest/OCITEST; + +create table test1 (col1 number); +create table test2 (col1 number, col2 number); +create table test3 (col1 number, col2 number, col3 number); +create table test4 (this_col_name_is_30_chars_long number, two long, + three date, four char(10)); +create table test5( + col1 number, col2 char, col3 number, col4 char, + col5 number, col6 char, col7 number, col8 char, + col9 number, col10 char); +create table test6( + col1 number, col2 char, col3 number, col4 char, + col5 number, col6 char, col7 number, col8 char, + col9 number, col10 char, col11 number, col12 char, + col13 number, col14 char, col15 number, col16 char, + col17 number, col18 char, col19 number); +create table test7 (one number, two long, three date, four char(10), + five number, six number, seven number, eight number, + nine char(1), ten varchar(2000)); diff --git a/oci06.c b/oci06.c new file mode 100644 index 0000000..bbee745 --- /dev/null +++ b/oci06.c @@ -0,0 +1,383 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci06.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests array fetch of just one table + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + aliu 01/05/06 - add order by in the select statements to fix + intermittent diffs + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/29/97 - Fix olint errors + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci06.c + * + * Description: This program retrieves the column information for a single + * table called TEST1 + * + * It illustrates getting data back using ARRAY FETCH + * via a SELECT statement. + * The number of columns being returned is hard coded + * at 4 columns. The table has 4 columns for simplicity + * + * Based on: oci04.c + * Changes: added array features + * where clause has :tabname + * changed ofetch to ofen for multiple rows + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires NO arguments + * + * oci06 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra array bind by name + * Describe - none Hard-coded query + * Define - odefin + * Execute - oexec + * Fetch - ofen fetching multiple rows + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/(sizeof(size_t))]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +text tabname [MAX_NAME_LENGTH+1]; /* table name - generated on the fly */ +uword tabnum = 0; /* table number */ +uword row_count = 0; /* number of rows returned so far */ +uword numrows = 4; /* HARDCODED */ + +/* Function prototypes */ +void gentable(); +void logon (); +void logoff (); +void setup(); +void err_report(); +void get_data(); +void dump_data(); +void do_exit(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"SELECT cname, clength, colid \ + FROM ocicolu\ + WHERE tname = :tabname order by colid"; + +#define NUMCOLS 3 /* number of columns returned by above query */ + +/* array fetch definitions */ +struct col_struct{ + sword size; /* length of the column */ + sword type; /* type of the column */ + } ; + +struct col_struct coltable [] = /* query returns one char and two numbers */ + { {MAX_NAME_LENGTH+1, SQLT_STR}, + {sizeof(eword), SQLT_INT}, + {sizeof(eword), SQLT_INT} + }; + +struct colp { /* Buffer descriptor */ + sword c_type; /* What type is this column fetched as */ + ub1 *c_buf; /* The area to store the column */ + ub2 c_size; /* Size of the storage area */ + sb2 *c_indp; /* Indicator variable for this column */ + ub2 *c_rlen; /* Fetched length of the column */ + ub2 *c_rcode; /* array of return codes */ + };/* COLUMN STRUCTURE */ +typedef struct colp colp; +#define malloc_col(n) (colp *)malloc((size_t)(n * sizeof(colp))); + +colp *cols; /* column structure */ + +main(argc, argv) +eword argc; +text **argv; +{ + + uword numtabs; /* number of tables requested */ + uword tabindex; /* for loop index */ + + numtabs = 1; /* hardcoded */ + printf("\n Number of tables is %d\n", numtabs); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + for (tabindex = 0; tabindex < numtabs; tabindex++) + { + gentable(); + get_data(); /* retrieve data */ + } + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + colp *colsptr; /* temporary pointer */ + sword colindex; + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndra(&cda, (text *)":tabname", -1, + (ub1 *)tabname, (sword)sizeof(tabname), + SQLT_STR, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) /* bind */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + + cols = malloc_col(NUMCOLS); + colsptr = cols; + for (colindex = 0; colindex < NUMCOLS; colindex++, colsptr++) + { + + colsptr->c_size = coltable[colindex].size; + colsptr->c_type = coltable[colindex].type; + colsptr->c_indp = (sb2*)malloc((ub4)(numrows*sizeof(sb2))); + colsptr->c_rlen = (ub2*)malloc((ub4)(numrows*sizeof(ub2))); + colsptr->c_rcode = (ub2*)malloc((ub4)(numrows*sizeof(ub2))); + colsptr->c_buf = (ub1 *)malloc((ub4)(numrows*colsptr->c_size)); + + if (odefin(&cda, colindex + 1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, (text *)0, -1, -1, + colsptr->c_rlen, colsptr->c_rcode)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + } + +} + +/* + * Function: get_data + * + * Description: This routine actually executes the cursor and fetches the + * data. It calls dump_data to print the data + * + */ +void get_data() +{ + + if (oexec(&cda)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + printf("\n printing column information for table %s :\n\n", tabname); + + while (ofen(&cda, numrows) == 0) + { + dump_data(); + } + + if (cda.rc != NO_DATA_FOUND) + err_report(&cda); + +} + +/* + * Function: dump_data + * + * Description: This routine prints out the row/s from each fetch + * + */ +void dump_data() +{ + + uword index; + ub4 value; + for (index = 0; index < numrows; index++) + { + + printf(" column %d name is %s\n", index + 1 , + cols[0].c_buf + index * cols[0].c_size); + + memcpy((dvoid *)&value, (dvoid *)(cols[1].c_buf + index * cols[1].c_size), + *(cols[1].c_rlen + index)); + printf(" column %d length is %d \n", index + 1 , value); + + memcpy((dvoid *)&value, (dvoid *)(cols[2].c_buf + index * cols[2].c_size), + *(cols[2].c_rlen + index)); + printf(" column %d id is %d \n", index + 1 , value); + + } +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: gentable + * + * Description: This routine generates the next table name of the form TESTxx + * + */ +void gentable() +{ + + tabnum++; /* generate the next table name */ + sprintf((char *)tabname, "TEST%d", tabnum); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci06.sql b/oci06.sql new file mode 100644 index 0000000..5c4ac66 --- /dev/null +++ b/oci06.sql @@ -0,0 +1,51 @@ +rem +rem $Header: oci06.sql 11-oct-2006.15:55:32 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci06.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci06.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +rem +rem create a view to get the name, length and colid of all the columns in +rem a table +create or replace view ocicol + (tobjid, townerid, tname, cname, clength, colid) AS + SELECT o$.obj#, o$.owner#, o$.name, c$.name, c$.length, c$.col# + FROM sys.col$ c$, sys.obj$ o$ + WHERE o$.obj# = c$.obj# +/ + +CREATE OR REPLACE view ocicolu AS /* user version for ocitest */ + SELECT * from ocicol WHERE townerid = uid +/ +grant select on ocicolu to public; +drop public synonym ocicolu; +create public synonym ocicolu for sys.ocicolu; + +rem +rem Create a new user - call it ocitest +rem +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect, resource to ocitest; + +rem +rem Created needed tables +rem +connect ocitest/OCITEST; + +create table test1 (this_col_name_is_30_chars_long number, + two long, three date, four char(10)); + diff --git a/oci07.c b/oci07.c new file mode 100644 index 0000000..fce1482 --- /dev/null +++ b/oci07.c @@ -0,0 +1,382 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci07.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests array fetch with piggyback of first fetch and execute + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + aliu 01/05/06 - add order by in the select statements to fix + intermittent diffs + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/29/97 - Fix olint errors + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci07.c + * + * Description: This program retrieves the column information for a single + * table called TEST1 + * + * It illustrates getting data back using ARRAY FETCH + * via a SELECT statement. + * The number of columns being returned is hard coded + * at 4 columns. The table has 4 columns for simplicity + * This program piggy backs the first fetch on the execute + * call + * + * Based on: oci06.c + * Changes: changed oexec to oexfet + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires NO arguments + * + * oci07 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra array bind by name + * Describe - none Hard-coded query + * Define - odefin + * Execute - oexfet Includes first fetch + * Fetch - none Included in execute + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/(sizeof(size_t))]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +text tabname [MAX_NAME_LENGTH+1]; /* table name - generated on the fly */ +uword tabnum = 0; /* table number */ +uword row_count = 0; /* number of rows returned so far */ +uword numrows = 4; /* HARDCODED */ + +/* Function prototypes */ +void gentable(); +void logon (); +void logoff (); +void setup(); +void err_report(); +void get_data(); +void dump_data(); +void do_exit(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"SELECT cname, clength, colid \ + FROM ocicolu\ + WHERE tname = :tabname order by colid"; + +#define NUMCOLS 3 /* number of columns returned by above query */ + +/* array fetch definitions */ +struct col_struct{ + sword size; /* length of the column */ + sword type; /* type of the column */ + } ; + +struct col_struct coltable [] = /* query returns one char and two numbers */ + { {MAX_NAME_LENGTH+1, SQLT_STR}, + {sizeof(eword), SQLT_INT}, + {sizeof(eword), SQLT_INT} + }; + +struct colp { /* Buffer descriptor */ + sword c_type; /* What type is this column fetched as */ + ub1 *c_buf; /* The area to store the column */ + ub2 c_size; /* Size of the storage area */ + sb2 *c_indp; /* Indicator variable for this column */ + ub2 *c_rlen; /* Fetched length of the column */ + ub2 *c_rcode; /* array of return codes */ + };/* COLUMN STRUCTURE */ +typedef struct colp colp; +#define malloc_col(n) (colp *)malloc((size_t)(n * sizeof(colp))); + +colp *cols; /* column structure */ + +main(argc, argv) +eword argc; +text **argv; +{ + + uword numtabs; /* number of tables requested */ + uword tabindex; /* for loop index */ + + numtabs = 1; /* hardcoded */ + printf("\n Number of tables is %d\n", numtabs); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + for (tabindex = 0; tabindex < numtabs; tabindex++) + { + gentable(); + get_data(); /* retrieve data */ + } + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + colp *colsptr; /* temporary pointer */ + sword colindex; + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndra(&cda, (text *)":tabname", -1, + (ub1 *)tabname, (sword)sizeof(tabname), + SQLT_STR, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) /* bind */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + + cols = malloc_col(NUMCOLS); + colsptr = cols; + for (colindex = 0; colindex < NUMCOLS; colindex++, colsptr++) + { + + colsptr->c_size = coltable[colindex].size; + colsptr->c_type = coltable[colindex].type; + colsptr->c_indp = (sb2*)malloc((ub4)(numrows*sizeof(sb2))); + colsptr->c_rlen = (ub2*)malloc((ub4)(numrows*sizeof(ub2))); + colsptr->c_rcode = (ub2*)malloc((ub4)(numrows*sizeof(ub2))); + colsptr->c_buf = (ub1 *)malloc((ub4)(numrows*colsptr->c_size)); + + if (odefin(&cda, colindex + 1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, (text *)0, -1, -1, + colsptr->c_rlen, colsptr->c_rcode)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + } + +} + +/* + * Function: get_data + * + * Description: This routine actually executes the cursor and fetches the + * data. It calls dump_data to print the data + * + */ +void get_data() +{ + + printf("\n printing column information for table %s :\n\n", tabname); + + /* expecting an EXACT match */ + /* cancel cursor after oexfet */ + if (oexfet(&cda, (ub4)numrows, -1, -1) == 0) + { + dump_data(); + } + else + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + +} + +/* + * Function: dump_data + * + * Description: This routine prints out the row/s from each fetch + * + */ +void dump_data() +{ + + uword index; + ub4 value; + for (index = 0; index < numrows; index++) + { + + printf(" column %d name is %s\n", index + 1 , + cols[0].c_buf + index * cols[0].c_size); + + memcpy((dvoid *)&value, (dvoid *)(cols[1].c_buf + index * cols[1].c_size), + *(cols[1].c_rlen + index)); + printf(" column %d length is %d \n", index + 1 , value); + + memcpy((dvoid *)&value, (dvoid *)(cols[2].c_buf + index * cols[2].c_size), + *(cols[2].c_rlen + index)); + printf(" column %d id is %d \n", index + 1 , value); + + } +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: gentable + * + * Description: This routine generates the next table name of the form TESTxx + * + */ +void gentable() +{ + + tabnum++; /* generate the next table name */ + sprintf((char *)tabname, "TEST%d", tabnum); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci07.sql b/oci07.sql new file mode 100644 index 0000000..ff82ad1 --- /dev/null +++ b/oci07.sql @@ -0,0 +1,51 @@ +rem +rem $Header: oci07.sql 11-oct-2006.15:55:32 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci07.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci07.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +rem +rem create a view to get the name, length and colid of all the columns in +rem a table +create or replace view ocicol + (tobjid, townerid, tname, cname, clength, colid) AS + SELECT o$.obj#, o$.owner#, o$.name, c$.name, c$.length, c$.col# + FROM sys.col$ c$, sys.obj$ o$ + WHERE o$.obj# = c$.obj# +/ + +CREATE OR REPLACE view ocicolu AS /* user version for ocitest */ + SELECT * from ocicol WHERE townerid = uid +/ +grant select on ocicolu to public; +drop public synonym ocicolu; +create public synonym ocicolu for sys.ocicolu; + +rem +rem Create a new user - call it ocitest +rem +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect, resource to ocitest; + +rem +rem Created needed tables +rem +connect ocitest/OCITEST; + +create table test1 (this_col_name_is_30_chars_long number, two long, + three date, four char(10)); + diff --git a/oci08.c b/oci08.c new file mode 100644 index 0000000..450be58 --- /dev/null +++ b/oci08.c @@ -0,0 +1,427 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci08.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests array fetch with multiple fetches with piggyback of first fetch + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + aliu 01/05/06 - add order by in the select statements to fix + intermittent diffs + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/22/97 - Fix VMS porting exceptions + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci08.c + * + * Description: This program retrieves the column information for a set of + * tables called TESTxx where xx is a number + * + * It illustrates getting data back using ARRAY FETCH + * via a SELECT statement. + * It also illustrates re-executing the same query again without + * having to re-bind. + * The user can create multiple TESTxx tables + * The user can enter the number of rows to be fetched on each + * cycle + * + * Based on: oci07.c + * Changes: added support for multiple tables + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires TWO arguments: + * - the number of tables + * - the number of rows to fetch per cycle + * + * oci08 4 3 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra array bind by name + * Describe - none Hard-coded query + * Define - odefin + * Execute - oexfet Includes first fetch + * Fetch - ofen For subsequent fetches + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/(sizeof(size_t))]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +text tabname [MAX_NAME_LENGTH+1]; /* table name - generated on the fly */ +uword tabnum = 0; /* table number */ +uword row_count = 0; /* number of rows returned so far */ +uword numrows; /* get it as input */ + +/* Function prototypes */ +void gentable(); +void logon (); +void logoff (); +void setup(); +void err_report(); +void get_data(); +void dump_data(); +void do_exit(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"SELECT cname, clength, colid \ + FROM ocicolu\ + WHERE tname = :tabname order by colid"; + +#define NUMCOLS 3 /* number of columns returned by above query */ + +/* array fetch definitions */ +struct col_struct{ + sword size; /* length of the column */ + sword type; /* type of the column */ + } ; + +struct col_struct coltable [] = /* query returns one char and two numbers */ + { {MAX_NAME_LENGTH+1, SQLT_STR}, + {sizeof(eword), SQLT_INT}, + {sizeof(eword), SQLT_INT} + }; + +struct colp { /* Buffer descriptor */ + sword c_type; /* What type is this column fetched as */ + ub1 *c_buf; /* The area to store the column */ + ub2 c_size; /* Size of the storage area */ + sb2 *c_indp; /* Indicator variable for this column */ + ub2 *c_rlen; /* Fetched length of the column */ + ub2 *c_rcode; /* array of return codes */ + };/* COLUMN STRUCTURE */ +typedef struct colp colp; +#define malloc_col(n) (colp *)malloc((size_t)(n * sizeof(colp))); + +colp *cols; /* column structure */ + +main(argc, argv) +eword argc; +text **argv; +{ + + uword numtabs; /* number of tables requested */ + uword tabindex; /* for loop index */ + + if (argc != 3) + { + printf("\n\n Usage: \n"); + printf(" where numtabs is the number of tables with name TESTxx\n" ); + printf(" and numrows is number of rows per fetch cycle\n\n\n"); + do_exit(OCI_EXIT_FAILURE); + } + + numtabs = atoi((char *)argv[1]); + printf("\n Number of tables is %d\n", numtabs); + + numrows = atoi((char *)argv[2]); + printf("\n Number of rows to be fetched per cycle is %d\n", numrows); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + for (tabindex = 0; tabindex < numtabs; tabindex++) + { + gentable(); + get_data(); /* retrieve data */ + } + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + colp *colsptr; /* temporary pointer */ + sword colindex; + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndra(&cda, (text *)":tabname", -1, + (ub1 *)tabname, (sword)sizeof(tabname), + SQLT_STR, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) /* bind */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + + cols = malloc_col(NUMCOLS); + colsptr = cols; + for (colindex = 0; colindex < NUMCOLS; colindex++, colsptr++) + { + + colsptr->c_size = coltable[colindex].size; + colsptr->c_type = coltable[colindex].type; + colsptr->c_indp = (sb2*)malloc((ub4)(numrows*sizeof(sb2))); + colsptr->c_rlen = (ub2*)malloc((ub4)(numrows*sizeof(ub2))); + colsptr->c_rcode = (ub2*)malloc((ub4)(numrows*sizeof(ub2))); + colsptr->c_buf = (ub1 *)malloc((ub4)(numrows*colsptr->c_size)); + + if (odefin(&cda, colindex + 1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, (text *)0, -1, -1, + colsptr->c_rlen, colsptr->c_rcode)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + } + +} + +/* + * Function: get_data + * + * Description: This routine actually executes the cursor and fetches the + * data. It calls dump_data to print the data + * + */ +void get_data() +{ + + printf("\n printing column information for table %s :\n\n", tabname); + + /* don't cancel the cursor after the first execute/fetch */ + /* also don't want an exact match */ + if (oexfet(&cda, (ub4)numrows, 0, 0) != 0 && cda.rc != NO_DATA_FOUND) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + dump_data(); + + if (cda.rc == NO_DATA_FOUND) + { + row_count = 0; + return; /* no more rows to fetch */ + } + + while(1) /* we definitely have more rows to fetch */ + { + ofen(&cda, numrows); /* next fetch cycle */ + + if ((cda.rc == NO_DATA_FOUND) && ((cda.rpc - row_count) == 0)) + break; + + if ((cda.rc == 0) || + (cda.rc == NO_DATA_FOUND) && (cda.rpc - row_count)> 0) + { + dump_data(); + if ((cda.rc == NO_DATA_FOUND) && (cda.rpc == row_count)) + break; + } + + else + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + } + + row_count = 0; /* reset running counter for next table */ +} + +/* + * Function: dump_data + * + * Description: This routine prints out the row/s from each fetch + * + */ +void dump_data() +{ + + uword index; + ub4 value; + for (index = 0; index < cda.rpc - row_count; index++) + { + + printf(" column %d name is %s\n", row_count + index + 1 , + cols[0].c_buf + index * cols[0].c_size); + + memcpy((dvoid *)&value, (dvoid *)(cols[1].c_buf + index * cols[1].c_size), + *(cols[1].c_rlen + index)); + printf(" column %d length is %d \n", row_count + index + 1 , value); + + memcpy((dvoid *)&value, (dvoid *)(cols[2].c_buf + index * cols[2].c_size), + *(cols[2].c_rlen + index)); + printf(" column %d id is %d \n", row_count + index + 1 , value); + + } + + row_count += cda.rpc - row_count; /* we only need the increment */ + + printf(" ==> Total rows so far is %d\n", row_count); +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: gentable + * + * Description: This routine generates the next table name of the form TESTxx + * + */ +void gentable() +{ + + tabnum++; /* generate the next table name */ + sprintf((char *)tabname, "TEST%d", tabnum); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci08.sql b/oci08.sql new file mode 100644 index 0000000..953deff --- /dev/null +++ b/oci08.sql @@ -0,0 +1,64 @@ +rem +rem $Header: oci08.sql 11-oct-2006.15:55:32 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci08.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci08.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +rem +rem create a view to get the name, length and colid of all the columns in +rem a table +create or replace view ocicol + (tobjid, townerid, tname, cname, clength, colid) AS + SELECT o$.obj#, o$.owner#, o$.name, c$.name, c$.length, c$.col# + FROM sys.col$ c$, sys.obj$ o$ + WHERE o$.obj# = c$.obj# +/ + +CREATE OR REPLACE view ocicolu AS /* user version for ocitest */ + SELECT * from ocicol WHERE townerid = uid +/ +grant select on ocicolu to public; +drop public synonym ocicolu; +create public synonym ocicolu for sys.ocicolu; + +rem +rem Create a new user - call it ocitest +rem +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect, resource to ocitest; + +rem +rem Created needed tables +rem +connect ocitest/OCITEST; +create table test1 (col1 number); +create table test2 (col1 number, col2 number); +create table test3 (col1 number, col2 number, col3 number); +create table test4 (one number, two long, three date, four char(10)); +create table test5( + col1 number, col2 char, col3 number, col4 char, + col5 number, col6 char, col7 number, col8 char, + col9 number, col10 char); +create table test6( + col1 number, col2 char, col3 number, col4 char, + col5 number, col6 char, col7 number, col8 char, + col9 number, col10 char, col11 number, col12 char, + col13 number, col14 char, col15 number, col16 char, + col17 number, col18 char, col19 number); +create table test7 (one number, two long, three date, four char(10), + five number, six number, seven number, eight number, + nine char(1), ten varchar(2000)); diff --git a/oci09.c b/oci09.c new file mode 100644 index 0000000..1f6d1f7 --- /dev/null +++ b/oci09.c @@ -0,0 +1,347 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci09.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests single row fetch via PL/SQL procedures + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/22/97 - Fix VMS porting exceptions + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci09.c + * + * Description: This program retrieves the column information for a set of + * tables called TESTxx where xx is a number. + * + * It illustrates getting data back using SINGLE ROW FETCH + * through a PLSQL PROCEDURE + * It also illustrates re-executing the same query again without + * having to rebind + * + * Based on: oci04.c + * Changes: changed odefin to obndra calls + * no fetch cycle, execute does the fetch now + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires ONE argument - the number of tables + * + * oci09 4 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - none Use obndra for plsql parameters + * Execute - oexec + * Fetch - none Execute gets data back + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/(sizeof(size_t))]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +text tabname [MAX_NAME_LENGTH+1]; /* table name - generated on the fly */ +uword tabnum = 0; /* table number */ +uword row_count = 0; /* number of rows returned so far */ + + +/* Function prototypes */ +void gentable(); +void logon (); +void logoff (); +void setup(); +void err_report(); +void get_data(); +void dump_data(); +void do_exit(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"\ + begin \ + oci09pkg.oci09proc(:tabname, :cname, :collen, :colid);\ + end;"; + +/* return values from query - kept as globals for simplicity */ +uword colid; +uword collen; +text cname [MAX_NAME_LENGTH+1]; + +main(argc, argv) +eword argc; +text **argv; +{ + + uword numtabs; /* number of tables requested */ + uword tabindex; /* for loop index */ + + if (argc != 2) + { + printf("\n\n Usage: where numtabs is the number of \ +tables with name TESTxx \n\n\n"); + do_exit(OCI_EXIT_FAILURE); + } + + numtabs = atoi((char *)argv[1]); + printf("\n Number of tables is %d\n", numtabs); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + for (tabindex = 0; tabindex < numtabs; tabindex++) + { + gentable(); + get_data(); /* retrieve data */ + } + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndra(&cda, (text *)":tabname", -1, /* bind */ + (ub1 *)tabname, (sword)sizeof(tabname), + SQLT_STR, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndra(&cda, (text *)":cname", -1, /* bind */ + (ub1 *)cname, (sword)sizeof(cname), + SQLT_STR, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndra(&cda, (text *)":collen", -1, /* bind */ + (ub1 *)&collen, (sword)sizeof(collen), + SQLT_INT, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndra(&cda, (text *)":colid", -1, /* bind */ + (ub1 *)&colid, (sword)sizeof(colid), + SQLT_INT, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: get_data + * + * Description: This routine actually executes the cursor and fetches the + * data. It calls dump_data to print the data + * + */ +void get_data() +{ + + printf("\n printing column information for table %s :\n\n", tabname); + + while (oexec(&cda) == 0) + { + row_count++; /* bump this for printing purposes */ + dump_data(); + } + + if (cda.rc != NULL_VALUE_RETURNED) + err_report(&cda); + + row_count = 0; /* reset for next table */ +} + +/* + * Function: dump_data + * + * Description: This routine prints out the row/s from each fetch + * + */ +void dump_data() +{ + printf(" column %d name is %s\n", row_count, cname); + printf(" column %d length is %d \n", row_count, collen); + printf(" column %d id is %d \n", row_count, colid); + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: gentable + * + * Description: This routine generates the next table name of the form TESTxx + * + */ +void gentable() +{ + + tabnum++; /* generate the next table name */ + sprintf((char *)tabname, "TEST%d", tabnum); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci09.sql b/oci09.sql new file mode 100644 index 0000000..7e1daf2 --- /dev/null +++ b/oci09.sql @@ -0,0 +1,108 @@ +rem +rem $Header: oci09.sql 11-oct-2006.15:55:32 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci09.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci09.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem aliu 01/05/06 - add order by in the select statements from +rem ocicolu to fix intermittent diffs +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +rem +rem create a view to get the name, length and colid of all the columns in +rem a table +create or replace view ocicol + (tobjid, townerid, tname, cname, clength, colid) AS + select o$.obj#, o$.owner#, o$.name, c$.name, c$.length, c$.col# + from sys.col$ c$, sys.obj$ o$ + where o$.obj# = c$.obj# +/ + +CREATE OR REPLACE view ocicolu AS /* current user's columns */ + SELECT * from ocicol WHERE townerid = uid +/ +grant select on ocicolu to public; +drop public synonym ocicolu; +create public synonym ocicolu for sys.ocicolu; + +rem +rem Create a new user - call it ocitest +rem +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect,resource to ocitest; +connect ocitest/OCITEST; + +create table test1 (col1 number); +create table test2 (col1 number, col2 number); +create table test3 (col1 number, col2 number, col3 number); +create table test4 (one number, two long, three date, four char(10)); +create table test5( + col1 number, col2 char, col3 number, col4 char, + col5 number, col6 char, col7 number, col8 char, + col9 number, col10 char); +create table test6( + col1 number, col2 char, col3 number, col4 char, + col5 number, col6 char, col7 number, col8 char, + col9 number, col10 char, col11 number, col12 char, + col13 number, col14 char, col15 number, col16 char, + col17 number, col18 char, col19 number); + +create table debug_cursor (col1 char); +create table debug_result (col1 varchar2(20)); +create or replace package oci09pkg as + + procedure oci09proc( + tabname in varchar2, + colname out varchar2, + collen out varchar2, + colid out varchar2); +end; +/ + +create or replace package body oci09pkg as + + cursor get_col( + table_name in varchar2) is + select cname, clength, colid from ocicolu + where tname = table_name order by colid; + + procedure oci09proc( + tabname in varchar2, + colname out varchar2, + collen out varchar2, + colid out varchar2) is + + begin + + if NOT get_col%ISOPEN then + open get_col(tabname); + insert into debug_cursor values('y'); + else + insert into debug_cursor values('n'); + end if; + + fetch get_col into colname, collen, colid; + + if get_col%NOTFOUND then + close get_col; + end if; -- close the cursor for the next table + + insert into debug_result values (colname); + commit; + end; + +end; +/ + diff --git a/oci10.c b/oci10.c new file mode 100644 index 0000000..17b5a20 --- /dev/null +++ b/oci10.c @@ -0,0 +1,487 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci10.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests array fetch using PL/SQL procedures via PL/SQL arrays + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/22/97 - Fix VMS porting exceptions + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci10.c + * + * Description: This program retrieves the column information for a set of + * tables called TESTxx where xx is a number. + * + * It illustrates getting data back using ARRAY FETCH + * through a PLSQL PROCEDURE + * It also illustrates re-executing the same query again without + * having to rebind + * The user can create multiple TESTxx tables + * The user can enter the number of rows to be fetched on each + * cycle + * + * Based on: oci07.c + * Changes: changed odefin to obndra calls + * no fetch cycle, execute does the fetch now + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires TWO arguments: + * - the number of tables + * - the number of rows to fetch per cycle + * + * oci10 4 3 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - none Use obndra for plsql parameters + * Execute - oexec For the plsql procedure + * Fetch - none Execute gets data back + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/(sizeof(size_t))]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +text tabname [MAX_NAME_LENGTH+1]; /* table name - generated on the fly */ +uword tabnum = 0; /* table number */ +uword row_count = 0; /* number of rows returned so far */ +uword numrows; /* get it as input */ + +/* Function prototypes */ +void gentable(); +void logon (); +void logoff (); +void setup(); +void err_report(); +void get_data(); +void dump_data(); +void do_exit(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"\ + begin \ + oci10pkg.oci10proc(:cname, :collen, :colid, :tabname,\ + :batch_size, :num_ret, :done_fetch);\ + end;"; + +#define NUMCOLS 3 /* number of columns returned by above query */ +sword num_ret; /* number of rows ACTUALLY returned from procedure */ +sword done_fetch; /* any more rows to fetch for this table? */ + +/* array fetch definitions */ +struct col_struct{ + sword size; /* length of the column */ + sword type; /* type of the column */ + } ; + +struct col_struct coltable [] = /* query returns one char and two numbers */ + { {MAX_NAME_LENGTH+1, SQLT_STR}, + {sizeof(eword), SQLT_INT}, + {sizeof(eword), SQLT_INT} + }; + +struct colp { /* Buffer descriptor */ + sword c_type; /* What type is this column fetched as */ + ub1 *c_buf; /* The area to store the column */ + ub2 c_size; /* Size of the storage area */ + sb2 *c_indp; /* Indicator variable for this column */ + ub2 *c_rlen; /* Fetched length of the column */ + ub2 *c_rcode; /* array of return codes */ + ub4 c_curlen; /* current length */ + };/* COLUMN STRUCTURE */ +typedef struct colp colp; +#define malloc_col(n) (colp *)malloc((size_t)(n * sizeof(colp))); + +colp *cols; /* column structure */ + +#define BUG207799 + +main(argc, argv) +eword argc; +text **argv; +{ + + uword numtabs; /* number of tables requested */ + uword tabindex; /* for loop index */ + + if (argc != 3) + { + printf("\n\n Usage: \n"); + printf(" where numtabs is the number of tables with name TESTxx\n" ); + printf(" and numrows is number of rows per fetch cycle\n\n\n"); + do_exit(OCI_EXIT_FAILURE); + } + + numtabs = atoi((char *)argv[1]); + printf("\n Number of tables is %d\n", numtabs); + + numrows = atoi((char *)argv[2]); + printf("\n Number of rows to be fetched per cycle is %d\n", numrows); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + for (tabindex = 0; tabindex < numtabs; tabindex++) + { + gentable(); + get_data(); /* retrieve data */ + } + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + colp *colsptr; /* temporary pointer */ + sword colindex; + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + /* bind all the scalar values */ + if (obndra(&cda, (text *)":tabname", -1, + (ub1 *)tabname, (sword)sizeof(tabname), + SQLT_STR, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) /* bind */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndra(&cda, (text *)":batch_size", -1, + (ub1 *)&numrows, (sword)sizeof(numrows), + SQLT_INT, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) /* bind */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndra(&cda, (text *)":num_ret", -1, + (ub1 *)&num_ret, (sword)sizeof(num_ret), + SQLT_INT, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) /* bind */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndra(&cda, (text *)":done_fetch", -1, + (ub1 *)&done_fetch, (sword)sizeof(done_fetch), + SQLT_INT, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) /* bind */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + + cols = malloc_col(NUMCOLS); + colsptr = cols; + for (colindex = 0; colindex < NUMCOLS; colindex++, colsptr++) + { + + colsptr->c_size = coltable[colindex].size; + colsptr->c_type = coltable[colindex].type; + colsptr->c_indp = (sb2*)malloc((ub4)(numrows*sizeof(sb2))); + colsptr->c_rlen = (ub2*)malloc((ub4)(numrows*sizeof(ub2))); + colsptr->c_rcode = (ub2*)malloc((ub4)(numrows*sizeof(ub2))); + colsptr->c_buf = (ub1 *)malloc((ub4)(numrows*colsptr->c_size)); + colsptr->c_curlen = 0; + + switch (colindex) { + case(0) : + + if (obndra(&cda, (text *)":cname", -1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, colsptr->c_rlen, colsptr->c_rcode, + (ub4)numrows, &(colsptr->c_curlen), + (text *)0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + break; + + case(1) : + + if (obndra(&cda, (text *)":collen", -1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, colsptr->c_rlen, colsptr->c_rcode, + (ub4)numrows, &(colsptr->c_curlen), + (text *)0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + break; + + case(2) : + + if (obndra(&cda, (text *)":colid", -1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, colsptr->c_rlen, colsptr->c_rcode, + (ub4)numrows, &(colsptr->c_curlen), + (text *)0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + break; + } + + } + +} + +/* + * Function: get_data + * + * Description: This routine actually executes the cursor and fetches the + * data. It calls dump_data to print the data + * + */ +void get_data() +{ + + colp *colsptr; + uword colindex; + + printf("\n printing column information for table %s :\n\n", tabname); + + row_count = 0; + done_fetch = FALSE; + while(!done_fetch) + { + +#ifdef BUG207799 + /* bug 207799 - need to reset the curlen to zero */ + colsptr = cols; + for (colindex = 0; colindex < NUMCOLS; colindex++,colsptr++) + colsptr->c_curlen = 0; +#endif /* BUG 207799 */ + + oexec(&cda); + + if (cda.rc == 0) + { + if (num_ret > 0) + dump_data(); + } + else + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + } + + row_count = 0; /* reset running counter for next table */ +} + +/* + * Function: dump_data + * + * Description: This routine prints out the row/s from each fetch + * + */ +void dump_data() +{ + + uword index; + ub4 value; + for (index = 0; index < num_ret; index++) + { + + printf(" column %d name is %s\n", row_count + index + 1 , + cols[0].c_buf + index * cols[0].c_size); + + memcpy((dvoid *)&value, (dvoid *)(cols[1].c_buf + index * cols[1].c_size), + *(cols[1].c_rlen + index)); + printf(" column %d length is %d \n", row_count + index + 1 , value); + + memcpy((dvoid *)&value, (dvoid *)(cols[2].c_buf + index * cols[2].c_size), + *(cols[2].c_rlen + index)); + printf(" column %d id is %d \n", row_count + index + 1 , value); + + } + + row_count += num_ret; /* we only need the increment */ + + printf(" ==> Total rows so far is %d\n", row_count); +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: gentable + * + * Description: This routine generates the next table name of the form TESTxx + * + */ +void gentable() +{ + + tabnum++; /* generate the next table name */ + sprintf((char *)tabname, "TEST%d", tabnum); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci10.sql b/oci10.sql new file mode 100644 index 0000000..deccf6c --- /dev/null +++ b/oci10.sql @@ -0,0 +1,120 @@ +rem +rem $Header: oci10.sql 11-oct-2006.15:55:32 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci10.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci10.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem aliu 01/10/06 - add order by in the select from ocicolu to fix +rem intermittent diffs +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +rem +rem create a view to get the name, length and colid of all the columns in +rem a table +create or replace view ocicol + (tobjid, townerid, tname, cname, clength, colid) AS + select o$.obj#, o$.owner#, o$.name, c$.name, c$.length, c$.col# + from sys.col$ c$, sys.obj$ o$ + where o$.obj# = c$.obj# +/ + +CREATE OR REPLACE view ocicolu AS /* current user's columns */ + SELECT * from ocicol WHERE townerid = uid +/ +grant select on ocicolu to public; +drop public synonym ocicolu; +create public synonym ocicolu for sys.ocicolu; + +rem Create a new user - call it ocitest +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect,resource to ocitest; +connect ocitest/OCITEST; + +create table test1 (col1 number); +create table test2 (col1 number, col2 number); +create table test3 (col1 number, col2 number, col3 number); +create table test4 (one number, two long, three date, four char(10)); +create table test5( + col1 number, col2 char, col3 number, col4 char, + col5 number, col6 char, col7 number, col8 char, + col9 number, col10 char); +create table test6( + col1 number, col2 char, col3 number, col4 char, + col5 number, col6 char, col7 number, col8 char, + col9 number, col10 char, col11 number, col12 char, + col13 number, col14 char, col15 number, col16 char, + col17 number, col18 char, col19 number); + +create or replace package oci10pkg as + + type char_array is table of varchar2(20) index by binary_integer; + type num_array is table of integer index by binary_integer; + + procedure oci10proc( + cname out char_array, -- array to put cname in + collen out num_array, -- array to put column lengths in + colid out num_array, -- array to put column ids in + tabname in varchar2, -- table name to get col definitions + batchsize in integer, -- number of rows per trip + numret in out integer, -- number of rows ACTUALLY RETURNED + donefetch in out integer); -- are we done fetching for this + -- table +end; +/ + +create or replace package body oci10pkg as + + cursor get_col( + table_name in varchar2) is + select cname, clength, colid from ocicolu + where tname = table_name order by colid; + + + procedure oci10proc( + cname out char_array, + collen out num_array, + colid out num_array, + tabname in varchar2, + batchsize in integer, + numret in out integer, + donefetch in out integer + ) is + + begin + + donefetch := 0; + numret := 0; + + if NOT get_col%ISOPEN then + open get_col(tabname); + end if; + + for i in 1..batchsize loop + fetch get_col + into cname(i), collen(i), colid(i); + + if get_col%NOTFOUND then + close get_col; + donefetch := 1; + exit; + else + numret := numret + 1; + end if; + end loop; + + end; + +end; +/ diff --git a/oci11.c b/oci11.c new file mode 100644 index 0000000..52cf897 --- /dev/null +++ b/oci11.c @@ -0,0 +1,435 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci11.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests array fetch using PL/SQL procedures via cursor variables + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/22/97 - Fix VMS porting exceptions + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ +/* + * Name: oci11.c + * + * Description: This program retrieves the column information for a set of + * tables called TESTxx where xx is a number. + * + * It illustrates getting data back using ARRAY FETCH + * through a PLSQL PROCEDURE using a RESULT SET + * It also illustrates re-executing the same query again without + * having to rebind + * The user can create multiple TESTxx tables + * The user can enter the number of rows to be fetched on each + * cycle + * + * Based on: oci08.c + * Changes: second cursor now returned from within plsql procedure + * define calls needed based on second cursor + * fetch cyle on second cursor, exec on first cursor + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires TWO arguments: + * - the number of tables + * - the number of rows to fetch per cycle + * + * oci11 4 3 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - odefin This is for the returned cursor + * Execute - oexec For the plsql procedure + * Fetch - ofen Fetch for second cursor. + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/(sizeof(size_t))]; /* host area */ +Cda_Def cda; /* cursor area */ +Cda_Def cursor2; + +/* Globals needed */ +text tabname [MAX_NAME_LENGTH+1]; /* table name - generated on the fly */ +uword tabnum = 0; /* table number */ +uword row_count = 0; /* number of rows returned so far */ +uword numrows; /* get it as input */ + +/* Function prototypes */ +void gentable(); +void logon (); +void logoff (); +void setup(); +void err_report(); +void get_data(); +void dump_data(); +void do_exit(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"\ + begin \ + oci11pkg.oci11proc(:curs,:tabname);\ + end;"; + +#define NUMCOLS 3 /* number of columns returned by above query */ +sword num_ret; /* number of rows ACTUALLY returned from procedure */ +sword done_fetch; /* any more rows to fetch for this table? */ + +/* array fetch definitions */ +struct col_struct{ + sword size; /* length of the column */ + sword type; /* type of the column */ + } ; + +struct col_struct coltable [] = /* query returns one char and two numbers */ + { {MAX_NAME_LENGTH+1, SQLT_STR}, + {sizeof(eword), SQLT_INT}, + {sizeof(eword), SQLT_INT} + }; + +struct colp { /* Buffer descriptor */ + sword c_type; /* What type is this column fetched as */ + ub1 *c_buf; /* The area to store the column */ + ub2 c_size; /* Size of the storage area */ + sb2 *c_indp; /* Indicator variable for this column */ + ub2 *c_rlen; /* Fetched length of the column */ + ub2 *c_rcode; /* array of return codes */ + ub4 c_curlen; /* current length */ + };/* COLUMN STRUCTURE */ +typedef struct colp colp; +#define malloc_col(n) (colp *)malloc((size_t)(n * sizeof(colp))); + +colp *cols; /* column structure */ + +main(argc, argv) +eword argc; +text **argv; +{ + + uword numtabs; /* number of tables requested */ + uword tabindex; /* for loop index */ + + if (argc != 3) + { + printf("\n\n Usage: \n"); + printf(" where numtabs is the number of tables with name TESTxx\n" ); + printf(" and numrows is number of rows per fetch cycle\n\n\n"); + do_exit(OCI_EXIT_FAILURE); + } + + numtabs = atoi((char *)argv[1]); + printf("\n Number of tables is %d\n", numtabs); + + numrows = atoi((char *)argv[2]); + printf("\n Number of rows to be fetched per cycle is %d\n", numrows); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + for (tabindex = 0; tabindex < numtabs; tabindex++) + { + gentable(); + + if (oexec(&cda)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + get_data(); + } + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + memset((dvoid *)&cursor2, 0, sizeof(Cda_Def)); + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + /* bind all the scalar values */ + if (obndra(&cda, (text *)":curs", -1, + (ub1 *)&cursor2, -1, + SQLT_CUR, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) /* bind */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndra(&cda, (text *)":tabname", -1, + (ub1 *)tabname, 31, + SQLT_STR, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) /* bind */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: get_data + * + * Description: This routine actually executes the cursor and fetches the + * data. It calls dump_data to print the data + * + */ +void get_data() +{ + + colp *colsptr; + uword colindex; + printf("\n printing column information for table %s :\n\n", tabname); + + cols = malloc_col(NUMCOLS); + colsptr = cols; + for (colindex = 0; colindex < NUMCOLS; colindex++, colsptr++) + { + + colsptr->c_size = coltable[colindex].size; + colsptr->c_type = coltable[colindex].type; + colsptr->c_indp = (sb2*)malloc((ub4)(numrows*sizeof(sb2))); + colsptr->c_rlen = (ub2*)malloc((ub4)(numrows*sizeof(ub2))); + colsptr->c_rcode = (ub2*)malloc((ub4)(numrows*sizeof(ub2))); + colsptr->c_buf = (ub1 *)malloc((ub4)(numrows*colsptr->c_size)); + colsptr->c_curlen = 0; + + if (odefin(&cursor2, colindex + 1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, (text *)0, -1, -1, + colsptr->c_rlen, colsptr->c_rcode)) + { + err_report(&cursor2); + do_exit(OCI_EXIT_FAILURE); + } + } + + + while(1) /* we definitely have more rows to fetch */ + { + + ofen(&cursor2, numrows); /* next fetch cycle */ + + if ((cursor2.rc == NO_DATA_FOUND) && ((cursor2.rpc - row_count) == 0)) + break; + + if ((cursor2.rc == 0) || + (cursor2.rc == NO_DATA_FOUND) && (cursor2.rpc - row_count)> 0) + { + dump_data(); + if ((cursor2.rc == NO_DATA_FOUND) && (cursor2.rpc == row_count)) + break; + } + + else + { + err_report(&cursor2); + do_exit(OCI_EXIT_FAILURE); + } + + } + row_count = 0; /* reset running counter for next table */ +} + + +/* + * Function: dump_data + * + * Description: This routine prints out the row/s from each fetch + * + */ +void dump_data() +{ + + uword index; + ub4 value; + for (index = 0; index < cursor2.rpc - row_count; index++) + { + + printf(" column %d name is %s\n", row_count + index + 1 , + cols[0].c_buf + index * cols[0].c_size); + + memcpy((dvoid *)&value, (dvoid *)(cols[1].c_buf + index * cols[1].c_size), + *(cols[1].c_rlen + index)); + printf(" column %d length is %d \n", row_count + index + 1 , value); + + memcpy((dvoid *)&value, (dvoid *)(cols[2].c_buf + index * cols[2].c_size), + *(cols[2].c_rlen + index)); + printf(" column %d id is %d \n", row_count + index + 1 , value); + + } + + row_count += cursor2.rpc - row_count; /* we only need the increment */ + + printf(" ==> Total rows so far is %d\n", row_count); +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: gentable + * + * Description: This routine generates the next table name of the form TESTxx + * + */ +void gentable() +{ + + tabnum++; /* generate the next table name */ + sprintf((char *)tabname, "TEST%d", tabnum); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} + diff --git a/oci11.sql b/oci11.sql new file mode 100644 index 0000000..0cb850c --- /dev/null +++ b/oci11.sql @@ -0,0 +1,93 @@ +rem +rem $Header: oci11.sql 11-oct-2006.15:55:33 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci11.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci11.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem aliu 01/05/06 - add order by in the select from ocicolu to fix +rem intermittent diffs +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +rem +rem create a view to get the name, length and colid of all the columns in +rem a table +create or replace view ocicol + (tobjid, townerid, tname, cname, clength, colid) AS + select o$.obj#, o$.owner#, o$.name, c$.name, c$.length, c$.col# + from sys.col$ c$, sys.obj$ o$ + where o$.obj# = c$.obj# +/ + +CREATE OR REPLACE view ocicolu AS /* current user's columns */ + SELECT * from ocicol WHERE townerid = uid +/ +grant select on ocicolu to public; +drop public synonym ocicolu; +create public synonym ocicolu for sys.ocicolu; + +rem Create a new user - call it ocitest +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect,resource to ocitest; +connect ocitest/OCITEST; + +create table test1 (col1 number); +create table test2 (col1 number, col2 number); +create table test3 (col1 number, col2 number, col3 number); +create table test4 (one number, two long, three date, four char(10)); +create table test5( + col1 number, col2 char, col3 number, col4 char, + col5 number, col6 char, col7 number, col8 char, + col9 number, col10 char); +create table test6( + col1 number, col2 char, col3 number, col4 char, + col5 number, col6 char, col7 number, col8 char, + col9 number, col10 char, col11 number, col12 char, + col13 number, col14 char, col15 number, col16 char, + col17 number, col18 char, col19 number); + +create or replace package oci11pkg as + + type rectype is record (cname ocicolu.cname%type, + clength ocicolu.clength%type, + colid ocicolu.colid%type); + type ctype is ref cursor return rectype; + + procedure oci11proc( + curs in out ctype, + tabname in varchar2); + +end; +/ + +create or replace package body oci11pkg as + + procedure oci11proc( + curs in out ctype, + tabname in varchar2 + + ) is + + begin + + open curs for + select cname, clength, colid + from ocicolu + where tname = tabname order by colid; + + + end; + +end; +/ diff --git a/oci12.c b/oci12.c new file mode 100644 index 0000000..e203f81 --- /dev/null +++ b/oci12.c @@ -0,0 +1,352 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci12.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests single row fetch of LONG data with piecewise fetch + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/29/97 - Fix olint errors + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ +/* + * Name: oci12.c + * + * Description: This program retrieves the rows contained in oci11tab which + * contains a long. Some rows have to be fetched piecewise. + * + * It illustrates getting data back using SINGLE ROW FETCH + * via a SELECT statement. + * It illustrates how to do a piecewise fetch of a long. + * Fetching 5 characters per long fetch + * + * Based on: oci04.c + * Changes: added long support + * hardcoded oci12tab in query + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires NO arguments + * + * oci12 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - odefin + * Execute - oexec + * Fetch - ofetch, oflng Long fetch + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +/* Globals needed */ +text tabname [MAX_NAME_LENGTH+1]; /* table name - generated on the fly */ +uword tabnum = 0; /* table number */ +uword row_count = 0; /* number of rows returned so far */ + + +/* Function prototypes */ +void logon (); +void logoff (); +void setup(); +void err_report(); +void get_data(); +void dump_data(); +void do_exit(); +void fetch_long(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"SELECT col1, col2 FROM oci12tab ORDER BY col1"; + +/* return values from query - kept as globals for simplicity */ + +#define LONG_SIZE 5 /* getting back 5 chars per long fetch */ +sword col1; +text col2 [LONG_SIZE + 1]; +sb2 col2_ind; /* indicator variable for col2 */ +ub2 col2_rlen; /* return length for col2 */ + +main(argc, argv) +eword argc; +text **argv; +{ + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + get_data(); /* retrieve data */ + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (odefin(&cda, 1, (ub1 *) &col1, (sword) sizeof(col1), /* define */ + (sword) SQLT_INT, + (sword) -1, (sb2 *) 0, (text *) 0, -1, -1, + (ub2 *) 0, (ub2 *) 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + /* save one character for null termination */ + if (odefin(&cda, 2, (ub1 *) col2, (sword) (sizeof(col2) - 1), + (sword) SQLT_LNG, + (sword) -1, (sb2 *)&col2_ind, (text *) 0, -1, -1, + (ub2 *)&col2_rlen, (ub2 *) 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: get_data + * + * Description: This routine actually executes the cursor and fetches the + * data. It calls dump_data to print the data + * + */ +void get_data() +{ + + if (oexec(&cda)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + printf("\n Printing the data for table oci12tab \n"); + + while (ofetch(&cda) == 0) + { + row_count++; /* bump this for printing purposes */ + + col2[col2_rlen] = '\0'; /* have to null terminate */ + + dump_data(); + + if ((col2_ind == -2) || (col2_rlen < col2_ind)) + fetch_long(); + + printf("\n"); + } + + if (cda.rc != NO_DATA_FOUND) + err_report(&cda); + +} + +/* + * Function: fetch_long + * + * Description: This routine retrieves the rest of a long row in pieces + * + */ +void fetch_long() +{ + + ub4 offset = col2_rlen; + /* we have already fetched col2_rlen characters so this is where the offset + starts for the next fetch cycle */ + ub4 piece = 0; + + printf(" \n", row_count); + + do + { + + if (oflng(&cda, 2, (ub1 *)col2, (sb4)(sizeof(col2) - 1), SQLT_LNG, + &piece, offset)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (piece) /* did we get anything? */ + { + printf(" received %d characters ", piece); + col2[piece] ='\0'; + printf(" data piece is %s\n", col2); + } + + offset += piece; /* bump the offset and keep going */ + + } while (piece == LONG_SIZE); + +} + + +/* + * Function: dump_data + * + * Description: This routine prints out the row/s from each fetch + * + */ +void dump_data() +{ + + printf(" row %d col1 is %d\n", row_count, col1); + printf(" row %d col2 is %s \n", row_count, col2); + +} + + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} + diff --git a/oci12.sql b/oci12.sql new file mode 100644 index 0000000..b3eb216 --- /dev/null +++ b/oci12.sql @@ -0,0 +1,43 @@ +rem +rem $Header: oci12.sql 11-oct-2006.15:55:33 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci12.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci12.c +rem RETURNS +rem +rem NOTES +rem +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect,resource to ocitest; +connect ocitest/OCITEST; + +create table oci12tab (col1 number, col2 long); + +insert into oci12tab values(1, 'A'); +insert into oci12tab values(2, 'AB'); +insert into oci12tab values(3, 'ABC'); +insert into oci12tab values(4, 'ABCDEFGHIJKLM'); +insert into oci12tab values(5, 'ABCD'); +insert into oci12tab values(6, 'ABCDE'); +insert into oci12tab values(7, 'ABCDEFGHIJ'); +insert into oci12tab values(8, '1'); +insert into oci12tab values(9, '12'); +insert into oci12tab values(10, '123'); +insert into oci12tab values(11, '123456789'); +insert into oci12tab values(12, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'); +commit; diff --git a/oci13.c b/oci13.c new file mode 100644 index 0000000..d4c3e58 --- /dev/null +++ b/oci13.c @@ -0,0 +1,504 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci13.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests array fetch of LONG data with piecewise fetching + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/29/97 - Fix olint errors + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci13.c + * + * Description: This program retrieves the rows contained in oci13tab which + * contains a long. Some rows have to be fetched piecewise. + * + * It illustrates getting data back using ARRAY FETCH + * via a SELECT statement. + * It illustrates how to do a piecewise fetch of a long. + * Fetching 5 characters per long fetch + * With an array fetch, piecewise longs will have to be + * fetched with a different cursor + * + * Based on: oci07.c + * Changes: added long support + * hardcoded oci13tab in query + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires ONE argument - number of rows per + * fetch cycle + * + * oci13 4 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - odefin + * Execute - oexec + * Fetch - ofetch, oflng Long fetch + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +/* Globals needed */ +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +uword row_count = 0; /* number of rows returned so far */ +uword numrows; /* get it as input */ + +/* Function prototypes */ +void logon (); +void logoff (); +void setup(); +void err_report(); +void get_data(); +void dump_data(); +void do_exit(); +void fetch_long(); +void setup_long(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"SELECT col1, col2 FROM oci13tab ORDER BY col1"; + +#define NUMCOLS 2 /* number of columns returned by above query */ +#define LONG_SIZE 5 /* getting back 5 characters with each long piece */ +text col2[LONG_SIZE +1]; /* buffer to hold the long pieces */ + +/* array fetch definitions */ +struct col_struct{ + sword size; /* length of the column */ + sword type; /* type of the column */ + } ; + +struct col_struct coltable [] = + { {sizeof(eword), SQLT_INT}, + {LONG_SIZE, SQLT_LNG} + }; + +struct colp { /* Buffer descriptor */ + sword c_type; /* What type is this column fetched as */ + ub1 *c_buf; /* The area to store the column */ + ub2 c_size; /* Size of the storage area */ + sb2 *c_indp; /* Indicator variable for this column */ + ub2 *c_rlen; /* Fetched length of the column */ + ub2 *c_rcode; /* array of return codes */ + };/* COLUMN STRUCTURE */ +typedef struct colp colp; +#define malloc_col(n) (colp *)malloc((size_t)(n * sizeof(colp))); + +colp *cols; /* column structure */ + +Cda_Def cda_long; /* cursor area to get remaining long pieces */ + +text *long_sqlstmt = (text *)"SELECT col2 FROM oci13tab\ + where col1 = :row_number"; + +sword long_row_number; /* row number to fetch pieces for */ + + +main(argc, argv) +eword argc; +text **argv; +{ + + if (argc != 2) + { + printf("\n\n Usage: \ +where numrows is number of rows per fetch cycle\n\n\n"); + do_exit(OCI_EXIT_FAILURE); + } + + numrows = atoi((char *)argv[1]); + printf("\n Number of rows to be fetched per cycle is %d\n", numrows); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + setup_long(); /* prepare long query */ + + get_data(); /* retrieve data */ + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + colp *colsptr; /* temporary pointer */ + sword colindex; + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + cols = malloc_col(NUMCOLS); + colsptr = cols; + for (colindex = 0; colindex < NUMCOLS; colindex++, colsptr++) + { + + colsptr->c_size = coltable[colindex].size; + colsptr->c_type = coltable[colindex].type; + colsptr->c_indp = (sb2*)malloc((ub4)(numrows*sizeof(sb2))); + colsptr->c_rlen = (ub2*)malloc((ub4)(numrows*sizeof(ub2))); + colsptr->c_rcode = (ub2*)malloc((ub4)(numrows*sizeof(ub2))); + colsptr->c_buf = (ub1 *)malloc((ub4)(numrows*colsptr->c_size)); + + if (odefin(&cda, colindex + 1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, (text *)0, -1, -1, + colsptr->c_rlen, colsptr->c_rcode)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + } + +} + +/* + * Function: setup_long + * + * Description: This routine allocates the second cursor needed to fetch + * the remaining piece of a long. + * + */ +void setup_long() +{ + + if (oopen(&cda_long, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda_long); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda_long, long_sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda_long); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndrv(&cda_long, (text *)":row_number", -1, + (ub1 *)&long_row_number, (sword)sizeof(long_row_number), + SQLT_INT, -1, (sb2 *) 0, (text *) 0, -1, -1)) /* bind */ + { + err_report(&cda_long); + do_exit(OCI_EXIT_FAILURE); + } + + if (odefin(&cda_long, 1, (ub1 *) col2, (sword) (sizeof(col2) - 1), + (sword) SQLT_LNG, + (sword) -1, (sb2 *)0, (text *) 0, -1, -1, + (ub2 *)0, (ub2 *) 0)) + { + err_report(&cda_long); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: get_data + * + * Description: This routine actually executes the cursor and fetches the + * data. It calls dump_data to print the data + * + */ +void get_data() +{ + + printf("\n printing the information for oci13tab: \n"); + + /* don't cancel the cursor after the first execute/fetch */ + /* also don't want an exact match */ + if (oexfet(&cda, (ub4)numrows, 0, 0) != 0 && cda.rc != NO_DATA_FOUND) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + dump_data(); + + if (cda.rc == NO_DATA_FOUND) + { + row_count = 0; + return; /* no more rows to fetch */ + } + + while(1) + { + ofen(&cda, (sword)numrows); + + if ((cda.rc == NO_DATA_FOUND) && ((cda.rpc - row_count) == 0)) + break; + + if ((cda.rc == 0) || + (cda.rc == NO_DATA_FOUND) && (cda.rpc - row_count)> 0) + { + dump_data(); + if ((cda.rc == NO_DATA_FOUND) && (cda.rpc == row_count)) + break; + } + + else + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + } + + row_count = 0; /* reset running counter for next table */ +} + +/* + * Function: dump_data + * + * Description: This routine prints out the row/s from each fetch + * + */ +void dump_data() +{ + + uword index; + ub4 value; + text longbuf[LONG_SIZE + 1]; + + for (index = 0; index < cda.rpc - row_count; index++) + { + + + memcpy((dvoid *)&value, (dvoid *)(cols[0].c_buf + index * cols[0].c_size), + *(cols[0].c_rlen + index)); + printf(" row %d col1 is %d \n", row_count + index + 1 , value); + + memcpy((dvoid *)longbuf, (dvoid *)(cols[1].c_buf + index * cols[1].c_size), + cols[1].c_rlen[index]); + longbuf[cols[1].c_rlen[index]] = '\0'; /* need to null terminate */ + + printf(" row %d col2 is %s\n", row_count + index + 1 , longbuf); + + if ((cols[1].c_rlen[index] < cols[1].c_indp[index]) || + (cols[1].c_indp[index] == -2)) + { + long_row_number = row_count + index + 1; + fetch_long(cols[1].c_rlen[index]); + } + + printf("\n"); + + } + + row_count += cda.rpc - row_count; /* we only need the increment */ + + printf(" Total rows so far is %d\n", row_count); +} + +/* + * Function: fetch_long + * + * Description: This routine retrieves the rest of a long row in pieces + * + */ +void fetch_long(offset) +uword offset; +{ + + ub4 piece = 0; + + printf(" \n", long_row_number); + + /* we need exactly one row */ + if (oexfet(&cda_long, (ub4)1, 0, 0)) + { + err_report(&cda_long); + do_exit(OCI_EXIT_FAILURE); + } + + /* the above call returns the first piece of the long - we have already + printed it - so just ignore it */ + + do + { + + if (oflng(&cda_long, 1, (ub1 *)col2, (sb4)(sizeof(col2) - 1), SQLT_LNG, + &piece, (ub4)offset)) + { + err_report(&cda_long); + do_exit(OCI_EXIT_FAILURE); + } + + if (piece) /* did we get anything? */ + { + printf(" received %d characters ", piece); + col2[piece] ='\0'; + printf(" data piece is %s\n", col2); + } + + offset += piece; /* bump the offset and keep going */ + + } while (piece == LONG_SIZE); + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (oclose(&cda_long)) /* close LONG cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci13.sql b/oci13.sql new file mode 100644 index 0000000..80ba3ad --- /dev/null +++ b/oci13.sql @@ -0,0 +1,39 @@ +rem +rem $Header: oci13.sql 11-oct-2006.15:55:33 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci13.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci13.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect,resource to ocitest; +connect ocitest/OCITEST; + +create table oci13tab (col1 number, col2 long); + +insert into oci13tab values(1, 'A'); +insert into oci13tab values(2, 'AB'); +insert into oci13tab values(3, 'ABC'); +insert into oci13tab values(4, 'ABCDEFGHIJKLM'); +insert into oci13tab values(5, 'ABCD'); +insert into oci13tab values(6, 'ABCDE'); +insert into oci13tab values(7, 'ABCDEFGHIJ'); +insert into oci13tab values(8, '1'); +insert into oci13tab values(9, '12'); +insert into oci13tab values(10, '123'); +insert into oci13tab values(11, '123456789'); +insert into oci13tab values(12, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'); +commit; diff --git a/oci14.c b/oci14.c new file mode 100644 index 0000000..5db5a37 --- /dev/null +++ b/oci14.c @@ -0,0 +1,387 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci14.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests array insert + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + whe 10/20/99 - #1039217: add int for static variable pass + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/22/97 - Fix VMS porting exceptions + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci14.c + * + * Description: This program performs an array insert one column using + * an INSERT statement. + * Always inserting 5 rows at a time. + * + * Based on: none + * Changes: none + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires ONE argument - number of rows to insert + * + * oci14 4 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - none insert statement + * Execute - oexec + * Fetch - none insert + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +uword row_count = 0; /* number of rows inserted so far */ +uword numrows; /* get it as input */ + +/* Function prototypes */ +void logon (); +void logoff (); +void setup(); +void err_report(); +void insert_data(); +void do_exit(); +void initialize_data(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"INSERT INTO oci14tab (col1) values (:col1)"; + +#define NUMCOLS 1 /* number of columns returned by above query */ +#define MAX_ROWS_PER_INSERT 5 /* 5 rows max per insert */ + +/* array fetch definitions */ +struct col_struct{ + sword size; /* length of the column */ + sword type; /* type of the column */ + } ; + +struct col_struct coltable [] = + { {MAX_NAME_LENGTH+1, SQLT_STR} + }; + + +struct colp { /* Buffer descriptor */ + sword c_type; /* What type is this column fetched as */ + ub1 *c_buf; /* The area to store the column */ + ub2 c_size; /* Size of the storage area */ + sb2 *c_indp; /* Indicator variable for this column */ + ub2 *c_rlen; /* Fetched length of the column */ + ub2 *c_rcode; /* array of return codes */ + sb4 c_curlen; /* current length */ + };/* COLUMN STRUCTURE */ +typedef struct colp colp; +#define malloc_col(n) (colp *)malloc((size_t)(n * sizeof(colp))); + +colp *cols; /* column structure */ + +main(argc, argv) +eword argc; +text **argv; +{ + + if (argc != 2) + { + printf("\n\n Usage: where numrows is the number of \ +rows the user wants to insert \n"); + do_exit(OCI_EXIT_FAILURE); + } + + numrows = atoi((char *)argv[1]); + if (numrows > 26) + { + printf("Please input a number under 26\n"); + do_exit(OCI_EXIT_FAILURE); + } + printf("\n Total number of rows to be inserted is %d\n", numrows); + + logon(); + + setup(); + + insert_data(); + + logoff(); + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + colp *colsptr; /* temporary pointer */ + sword colindex; + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + cols = malloc_col(NUMCOLS); + colsptr = cols; + for (colindex = 0; colindex < NUMCOLS; colindex++, colsptr++) + { + + colsptr->c_size = coltable[colindex].size; + colsptr->c_type = coltable[colindex].type; + colsptr->c_indp = (sb2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(sb2))); + memset((dvoid *)colsptr->c_indp, 0, MAX_ROWS_PER_INSERT * sizeof(sb2)); + colsptr->c_rlen = (ub2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(ub2))); + memset((dvoid *)colsptr->c_rlen, 0, MAX_ROWS_PER_INSERT * sizeof(ub2)); + colsptr->c_rcode = (ub2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(ub2))); + memset((dvoid *)colsptr->c_rcode, 0, MAX_ROWS_PER_INSERT * sizeof(ub2)); + colsptr->c_buf = + (ub1 *)malloc((size_t)(MAX_ROWS_PER_INSERT*colsptr->c_size)); + memset((dvoid *)colsptr->c_buf, 0, MAX_ROWS_PER_INSERT * colsptr->c_size); + colsptr->c_curlen = 0; + + switch (colindex) { + case(0) : + +/* GOTCHA!!! - need to pass in zeroes for mal and cal parameters when + running a regular insert. Set it to non-zero when using plsql */ + if (obndra(&cda, (text *)":col1", -1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, colsptr->c_rlen, colsptr->c_rcode, + (ub4)0, (ub4 *)0, + (text *)0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + break; + } + + } + +} + +/* + * Function: insert_data + * + * Description: This routine inserts the data into the table + * + */ +void insert_data() +{ + + colp *colsptr; + sword colindex; + sword numinsert; /* number of rows to insert on the current pass */ + + row_count = 0; + while (row_count < numrows) + { + + colsptr = cols; + numinsert = numrows - row_count < MAX_ROWS_PER_INSERT ? + numrows - row_count : MAX_ROWS_PER_INSERT; + + for (colindex = 0; colindex < NUMCOLS; colsptr++, colindex++) + initialize_data(colsptr->c_buf, colsptr->c_size, colsptr->c_rlen, + numinsert); + + /* using offset zero - we want all the rows right away */ + if (oexn(&cda, numinsert, 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + row_count += numinsert; + } + +} + +/* + * Function: initialize_data + * + * Description: This routine generates data for insertion + * + */ +void initialize_data(arr, len, flen, numinsert) +ub1 *arr; +sword len; +ub2 *flen; +sword numinsert; +{ + + static int pass = 0; + sword colindex; /* index */ + sword numchars; /* number of characters to extract */ + text *str = (text *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + + for (colindex = 0; colindex < numinsert; colindex++) + { + numchars = (pass * MAX_ROWS_PER_INSERT) + colindex + 1; + memcpy((dvoid *)(arr + colindex*len), (dvoid *)str, numchars); + *(arr + colindex*len + numchars ) = '\0'; /* null terminate */ + printf("iteration %d string is %s length is %d\n", + pass, arr + colindex *len, + strlen((char *)(arr + colindex *len))); + +/* GOTCHA!! - The null must be found within the length specified so add one */ +/* or just use the max length allowed for the array element */ + + *(flen + colindex) = strlen((char *)(arr + colindex*len)) + 1; + /* *(flen + colindex) = 30; <--- or use this */ + } + + pass++; + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci14.sql b/oci14.sql new file mode 100644 index 0000000..43514a8 --- /dev/null +++ b/oci14.sql @@ -0,0 +1,27 @@ +rem +rem $Header: oci14.sql 11-oct-2006.15:55:33 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci14.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci14.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect,resource to ocitest; +connect ocitest/OCITEST; + +create table oci14tab (col1 varchar2(30)); + +commit; diff --git a/oci15.c b/oci15.c new file mode 100644 index 0000000..77fd0f9 --- /dev/null +++ b/oci15.c @@ -0,0 +1,393 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci15.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests array insert with user prompt on each pass + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + whe 10/20/99 - #1039217: add int for static variable pass + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + azhao 09/11/97 - increase response buffer size to 3 + ehayes 05/22/97 - Fix VMS porting exceptions + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ +/* + * Name: oci15.c + * + * Description: This program performs an array insert one column using + * an INSERT statement. + * Always inserting 5 rows at a time. + * + * Based on: oci14.c + * Changes: user to press enter after each cycle + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires ONE argument - number of rows to insert + * + * oci15 4 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - none insert statement + * Execute - oexec + * Fetch - none insert + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +uword row_count = 0; /* number of rows inserted so far */ +uword numrows; /* get it as input */ + +/* Function prototypes */ +void logon (); +void logoff (); +void setup(); +void err_report(); +void insert_data(); +void do_exit(); +void initialize_data(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"INSERT INTO oci15tab (col1) values (:col1)"; + +#define NUMCOLS 1 /* number of columns returned by above query */ +#define MAX_ROWS_PER_INSERT 5 /* 5 rows max per insert */ + +/* array fetch definitions */ +struct col_struct{ + sword size; /* length of the column */ + sword type; /* type of the column */ + } ; + +struct col_struct coltable [] = + { {MAX_NAME_LENGTH+1, SQLT_STR} + }; + + +struct colp { /* Buffer descriptor */ + sword c_type; /* What type is this column fetched as */ + ub1 *c_buf; /* The area to store the column */ + ub2 c_size; /* Size of the storage area */ + sb2 *c_indp; /* Indicator variable for this column */ + ub2 *c_rlen; /* Fetched length of the column */ + ub2 *c_rcode; /* array of return codes */ + sb4 c_curlen; /* current length */ + };/* COLUMN STRUCTURE */ +typedef struct colp colp; +#define malloc_col(n) (colp *)malloc((size_t)(n * sizeof(colp))); + +colp *cols; /* column structure */ + +main(argc, argv) +eword argc; +text **argv; +{ + + if (argc != 2) + { + printf("\n\n Usage: where numrows is the number of \ +rows the user wants to insert \n"); + do_exit(OCI_EXIT_FAILURE); + } + + numrows = atoi((char *)argv[1]); + if (numrows > 26) + { + printf("Please input a number under 26\n"); + do_exit(OCI_EXIT_FAILURE); + } + printf("\n Total number of rows to be inserted is %d\n", numrows); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + insert_data(); + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + colp *colsptr; /* temporary pointer */ + sword colindex; + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + cols = malloc_col(NUMCOLS); + colsptr = cols; + for (colindex = 0; colindex < NUMCOLS; colindex++, colsptr++) + { + + colsptr->c_size = coltable[colindex].size; + colsptr->c_type = coltable[colindex].type; + colsptr->c_indp = (sb2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(sb2))); + memset((dvoid *)colsptr->c_indp, 0, MAX_ROWS_PER_INSERT * sizeof(sb2)); + colsptr->c_rlen = (ub2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(ub2))); + memset((dvoid *)colsptr->c_rlen, 0, MAX_ROWS_PER_INSERT * sizeof(ub2)); + colsptr->c_rcode = (ub2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(ub2))); + memset((dvoid *)colsptr->c_rcode, 0, MAX_ROWS_PER_INSERT * sizeof(ub2)); + colsptr->c_buf = + (ub1 *)malloc((size_t)(MAX_ROWS_PER_INSERT*colsptr->c_size)); + memset((dvoid *)colsptr->c_buf, 0, MAX_ROWS_PER_INSERT * colsptr->c_size); + colsptr->c_curlen = 0; + + switch (colindex) { + case(0) : + +/* GOTCHA!!! - need to pass in zeroes for mal and cal parameters when + running a regular insert. Set it to non-zero when using plsql */ + if (obndra(&cda, (text *)":col1", -1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, colsptr->c_rlen, colsptr->c_rcode, + (ub4)0, (ub4 *)0, + (text *)0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + break; + } + + } + +} + +/* + * Function: insert_data + * + * Description: This routine inserts the data into the table + * + */ +void insert_data() +{ + + colp *colsptr; + sword colindex; + sword numinsert; /* number of rows to insert on the current pass */ + text response[3]; + + row_count = 0; + while (row_count < numrows) + { + + colsptr = cols; + numinsert = numrows - row_count < MAX_ROWS_PER_INSERT ? + numrows - row_count : MAX_ROWS_PER_INSERT; + + for (colindex = 0; colindex < NUMCOLS; colsptr++, colindex++) + initialize_data(colsptr->c_buf, colsptr->c_size, colsptr->c_rlen, + numinsert); + + /* using offset zero - we want all the rows right away */ + if (oexn(&cda, numinsert, 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + printf("\n Do a select * from the table in another window \n"); + printf(" Then press return to continue -->"); + gets((char *)response); + + row_count += numinsert; + } + +} + +/* + * Function: initialize_data + * + * Description: This routine generates data for insertion + * + */ +void initialize_data(arr, len, flen, numinsert) +ub1 *arr; +sword len; +ub2 *flen; +sword numinsert; +{ + + static int pass = 0; + sword colindex; /* index */ + sword numchars; /* number of characters to extract */ + text *str = (text *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + + for (colindex = 0; colindex < numinsert; colindex++) + { + numchars = (pass * MAX_ROWS_PER_INSERT) + colindex + 1; + memcpy((dvoid *)(arr + colindex*len), (dvoid *)str, numchars); + *(arr + colindex*len + numchars ) = '\0'; /* null terminate */ + printf("iteration %d string is %s length is %d\n", + pass, arr + colindex *len, + strlen((char *)(arr + colindex *len))); + +/* GOTCHA!! - The null must be found within the length specified so add one */ +/* or just use the max length allowed for the array element */ + + *(flen + colindex) = strlen((char *)(arr + colindex*len)) + 1; + /* *(flen + colindex) = 30; <--- or use this */ + } + + pass++; + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} + diff --git a/oci15.sql b/oci15.sql new file mode 100644 index 0000000..e6a3cbd --- /dev/null +++ b/oci15.sql @@ -0,0 +1,27 @@ +rem +rem $Header: oci15.sql 11-oct-2006.15:55:33 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci15.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci15.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect,resource to ocitest; +connect ocitest/OCITEST; + +create table oci15tab (col1 varchar2(30)); + +commit; diff --git a/oci16.c b/oci16.c new file mode 100644 index 0000000..eb10036 --- /dev/null +++ b/oci16.c @@ -0,0 +1,432 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci16.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests array insert with autocommit on/off demonstration + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + whe 10/20/99 - #1039217: add int for static variable pass + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + azhao 09/11/97 - increase response buffer size to 3 + ehayes 05/22/97 - Fix VMS porting exceptions + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci16.c + * + * Description: This program performs an array insert one column using + * an INSERT statement. + * Always inserting 5 rows at a time. + * User presses enter at each cycle. Autocommit is turned + * at each odd pass and turned on at each even pass + * + * Based on: oci15.c + * Changes: user to press enter after each cycle + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires ONE argument - number of rows to insert + * + * oci16 4 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - none insert statement + * Execute - oexec + * Fetch - none insert + * Close - oclose + * Logoff - olof + * Commit On - ocon + * Commit Off- ocof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +uword row_count = 0; /* number of rows inserted so far */ +uword numrows; /* get it as input */ + +/* Function prototypes */ +void logon (); +void logoff (); +void setup(); +void err_report(); +void insert_data(); +void do_exit(); +void initialize_data(); +void toggle_autocommit(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"INSERT INTO oci16tab (col1) values (:col1)"; + +#define NUMCOLS 1 /* number of columns returned by above query */ +#define MAX_ROWS_PER_INSERT 5 /* 5 rows max per insert */ + +/* array fetch definitions */ +struct col_struct{ + sword size; /* length of the column */ + sword type; /* type of the column */ + } ; + +struct col_struct coltable [] = + { {MAX_NAME_LENGTH+1, SQLT_STR} + }; + + +struct colp { /* Buffer descriptor */ + sword c_type; /* What type is this column fetched as */ + ub1 *c_buf; /* The area to store the column */ + ub2 c_size; /* Size of the storage area */ + sb2 *c_indp; /* Indicator variable for this column */ + ub2 *c_rlen; /* Fetched length of the column */ + ub2 *c_rcode; /* array of return codes */ + sb4 c_curlen; /* current length */ + };/* COLUMN STRUCTURE */ +typedef struct colp colp; +#define malloc_col(n) (colp *)malloc((size_t)(n * sizeof(colp))); + +colp *cols; /* column structure */ + +main(argc, argv) +eword argc; +text **argv; +{ + + if (argc != 2) + { + printf("\n\n Usage: where numrows is the number of \ +rows the user wants to insert \n"); + do_exit(OCI_EXIT_FAILURE); + } + + numrows = atoi((char *)argv[1]); + if (numrows > 26) + { + printf("Please input a number under 26\n"); + do_exit(OCI_EXIT_FAILURE); + } + printf("\n Total number of rows to be inserted is %d\n", numrows); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + insert_data(); + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + colp *colsptr; /* temporary pointer */ + sword colindex; + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + cols = malloc_col(NUMCOLS); + colsptr = cols; + for (colindex = 0; colindex < NUMCOLS; colindex++, colsptr++) + { + + colsptr->c_size = coltable[colindex].size; + colsptr->c_type = coltable[colindex].type; + colsptr->c_indp = (sb2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(sb2))); + memset((dvoid *)colsptr->c_indp, 0, MAX_ROWS_PER_INSERT * sizeof(sb2)); + colsptr->c_rlen = (ub2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(ub2))); + memset((dvoid *)colsptr->c_rlen, 0, MAX_ROWS_PER_INSERT * sizeof(ub2)); + colsptr->c_rcode = (ub2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(ub2))); + memset((dvoid *)colsptr->c_rcode, 0, MAX_ROWS_PER_INSERT * sizeof(ub2)); + colsptr->c_buf = + (ub1 *)malloc((size_t)(MAX_ROWS_PER_INSERT*colsptr->c_size)); + memset((dvoid *)colsptr->c_buf, 0, MAX_ROWS_PER_INSERT * colsptr->c_size); + colsptr->c_curlen = 0; + + switch (colindex) { + case(0) : + +/* GOTCHA!!! - need to pass in zeroes for mal and cal parameters when + running a regular insert. Set it to non-zero when using plsql */ + if (obndra(&cda, (text *)":col1", -1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, colsptr->c_rlen, colsptr->c_rcode, + (ub4)0, (ub4 *)0, + (text *)0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + break; + } + + } + +} + +/* + * Function: insert_data + * + * Description: This routine inserts the data into the table + * + */ +void insert_data() +{ + + colp *colsptr; + sword colindex; + sword numinsert; /* number of rows to insert on the current pass */ + text response[3]; + + row_count = 0; + while (row_count < numrows) + { + + toggle_autocommit(); + + colsptr = cols; + numinsert = numrows - row_count < MAX_ROWS_PER_INSERT ? + numrows - row_count : MAX_ROWS_PER_INSERT; + + for (colindex = 0; colindex < NUMCOLS; colsptr++, colindex++) + initialize_data(colsptr->c_buf, colsptr->c_size, colsptr->c_rlen, + numinsert); + + /* using offset zero - we want all the rows right away */ + if (oexn(&cda, numinsert, 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + printf("\n Do a select * from the table in another window \n"); + printf(" Then press return to continue -->"); + gets((char *)response); + + row_count += numinsert; + } + +} + +/* + * Function: initialize_data + * + * Description: This routine generates data for insertion + * + */ +void initialize_data(arr, len, flen, numinsert) +ub1 *arr; +sword len; +ub2 *flen; +sword numinsert; +{ + + static int pass = 0; + sword colindex; /* index */ + sword numchars; /* number of characters to extract */ + text *str = (text *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + + for (colindex = 0; colindex < numinsert; colindex++) + { + numchars = (pass * MAX_ROWS_PER_INSERT) + colindex + 1; + memcpy((dvoid *)(arr + colindex*len), (dvoid *)str, numchars); + *(arr + colindex*len + numchars ) = '\0'; /* null terminate */ + printf("iteration %d string is %s length is %d\n", + pass, arr + colindex *len, + strlen((char *)(arr + colindex *len))); + +/* GOTCHA!! - The null must be found within the length specified so add one */ +/* or just use the max length allowed for the array element */ + + *(flen + colindex) = strlen((char *)(arr + colindex*len)) + 1; + /* *(flen + colindex) = 30; <--- or use this */ + } + + pass++; + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} + + +/* + * Function: logoff + * + * Description: This routine toggles between turning autocommit off and on + * with each pass. + * + */ +void toggle_autocommit() +{ + + static sword odd_pass = 1; + + if ((odd_pass % 2 ) == 0) + { + if (ocon(&lda)) + { + err_report((Cda_Def *)&lda); + do_exit(OCI_EXIT_FAILURE); + } + } + else + { + if (ocof(&lda)) + { + err_report((Cda_Def *)&lda); + do_exit(OCI_EXIT_FAILURE); + } + } + odd_pass++; +} diff --git a/oci16.sql b/oci16.sql new file mode 100644 index 0000000..016fa16 --- /dev/null +++ b/oci16.sql @@ -0,0 +1,28 @@ +rem +rem $Header: oci16.sql 11-oct-2006.15:55:34 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci16.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci16.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect,resource to ocitest; +connect ocitest/OCITEST; + +create table oci16tab (col1 varchar2(30)); + +commit; + diff --git a/oci17.c b/oci17.c new file mode 100644 index 0000000..0519ef7 --- /dev/null +++ b/oci17.c @@ -0,0 +1,433 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci17.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests array insert with demonstration of commit/rollback + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + whe 10/20/99 - #1039217: add int for static variable pass + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + azhao 09/11/97 - increase response buffer size to 3 + ehayes 05/22/97 - Fix VMS porting exceptions + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci17.c + * + * Description: This program performs an array insert one column using + * an INSERT statement. + * Always inserting 5 rows at a time. + * User presses enter at each cycle. Commit and rollback + * on every other pass. + * + * Based on: oci15.c + * Changes: user to press enter after each cycle + * added ocom and orol calls + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires ONE argument - number of rows to insert + * + * oci17 4 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - none insert statement + * Execute - oexec + * Fetch - none insert + * Close - oclose + * Logoff - olof + * Commit - ocom + * Rollback - orol + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +uword row_count = 0; /* number of rows inserted so far */ +uword numrows; /* get it as input */ + +/* Function prototypes */ +void logon (); +void logoff (); +void setup(); +void err_report(); +void insert_data(); +void do_exit(); +void initialize_data(); +void toggle_com_rol(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"INSERT INTO oci17tab (col1) values (:col1)"; + +#define NUMCOLS 1 /* number of columns returned by above query */ +#define MAX_ROWS_PER_INSERT 5 /* 5 rows max per insert */ + +/* array fetch definitions */ +struct col_struct{ + sword size; /* length of the column */ + sword type; /* type of the column */ + } ; + +struct col_struct coltable [] = + { {MAX_NAME_LENGTH+1, SQLT_STR} + }; + + +struct colp { /* Buffer descriptor */ + sword c_type; /* What type is this column fetched as */ + ub1 *c_buf; /* The area to store the column */ + ub2 c_size; /* Size of the storage area */ + sb2 *c_indp; /* Indicator variable for this column */ + ub2 *c_rlen; /* Fetched length of the column */ + ub2 *c_rcode; /* array of return codes */ + sb4 c_curlen; /* current length */ + };/* COLUMN STRUCTURE */ +typedef struct colp colp; +#define malloc_col(n) (colp *)malloc((size_t)(n * sizeof(colp))); + +colp *cols; /* column structure */ + +main(argc, argv) +eword argc; +text **argv; +{ + + if (argc != 2) + { + printf("\n\n Usage: where numrows is the number of \ +rows the user wants to insert \n"); + do_exit(OCI_EXIT_FAILURE); + } + + numrows = atoi((char *)argv[1]); + if (numrows > 26) + { + printf("Please input a number under 26\n"); + do_exit(OCI_EXIT_FAILURE); + } + printf("\n Total number of rows to be inserted is %d\n", numrows); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statment */ + + insert_data(); + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + colp *colsptr; /* temporary pointer */ + sword colindex; + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + cols = malloc_col(NUMCOLS); + colsptr = cols; + for (colindex = 0; colindex < NUMCOLS; colindex++, colsptr++) + { + + colsptr->c_size = coltable[colindex].size; + colsptr->c_type = coltable[colindex].type; + colsptr->c_indp = (sb2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(sb2))); + memset((dvoid *)colsptr->c_indp, 0, MAX_ROWS_PER_INSERT * sizeof(sb2)); + colsptr->c_rlen = (ub2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(ub2))); + memset((dvoid *)colsptr->c_rlen, 0, MAX_ROWS_PER_INSERT * sizeof(ub2)); + colsptr->c_rcode = (ub2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(ub2))); + memset((dvoid *)colsptr->c_rcode, 0, MAX_ROWS_PER_INSERT * sizeof(ub2)); + colsptr->c_buf = + (ub1 *)malloc((size_t)(MAX_ROWS_PER_INSERT*colsptr->c_size)); + memset((dvoid *)colsptr->c_buf, 0, MAX_ROWS_PER_INSERT * colsptr->c_size); + colsptr->c_curlen = 0; + + switch (colindex) { + case(0) : + +/* GOTCHA!!! - need to pass in zeroes for mal and cal parameters when + running a regular insert. Set it to non-zero when using plsql */ + if (obndra(&cda, (text *)":col1", -1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, colsptr->c_rlen, colsptr->c_rcode, + (ub4)0, (ub4 *)0, + (text *)0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + break; + } + + } + +} + +/* + * Function: insert_data + * + * Description: This routine inserts the data into the table + * + */ +void insert_data() +{ + + colp *colsptr; + sword colindex; + sword numinsert; /* number of rows to insert on the current pass */ + text response[3]; + + row_count = 0; + while (row_count < numrows) + { + + toggle_com_rol(); + + colsptr = cols; + numinsert = numrows - row_count < MAX_ROWS_PER_INSERT ? + numrows - row_count : MAX_ROWS_PER_INSERT; + + for (colindex = 0; colindex < NUMCOLS; colsptr++, colindex++) + initialize_data(colsptr->c_buf, colsptr->c_size, colsptr->c_rlen, + numinsert); + + /* using offset zero - we want all the rows right away */ + if (oexn(&cda, numinsert, 0)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + printf("\n Do a select * from the table in another window \n"); + printf(" Then press return to continue -->"); + gets((char *)response); + + row_count += numinsert; + } + +} + +/* + * Function: initialize_data + * + * Description: This routine generates data for insertion + * + */ +void initialize_data(arr, len, flen, numinsert) +ub1 *arr; +sword len; +ub2 *flen; +sword numinsert; +{ + + static int pass = 0; + sword colindex; /* index */ + sword numchars; /* number of characters to extract */ + text *str = (text *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + + for (colindex = 0; colindex < numinsert; colindex++) + { + numchars = (pass * MAX_ROWS_PER_INSERT) + colindex + 1; + memcpy((dvoid *)(arr + colindex*len), (dvoid *)str, numchars); + *(arr + colindex*len + numchars ) = '\0'; /* null terminate */ + printf("iteration %d string is %s length is %d\n", + pass, arr + colindex *len, + strlen((char *)(arr + colindex *len))); + +/* GOTCHA!! - The null must be found within the length specified so add one */ +/* or just use the max length allowed for the array element */ + + *(flen + colindex) = strlen((char *)(arr + colindex*len)) + 1; + /* *(flen + colindex) = 30; <--- or use this */ + } + + pass++; + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} + + +/* + * Function: toggle_com_rol + * + * Description: This routine toggles between rollback and commit calls + * with each pass. + * + */ +void toggle_com_rol() +{ + + static sword odd_pass = 1; + + if ((odd_pass % 2 ) == 0) + { + if (orol(&lda)) + { + err_report((Cda_Def *)&lda); + do_exit(OCI_EXIT_FAILURE); + } + } + else + { + if (ocom(&lda)) + { + err_report((Cda_Def *)&lda); + do_exit(OCI_EXIT_FAILURE); + } + } + odd_pass++; +} diff --git a/oci17.sql b/oci17.sql new file mode 100644 index 0000000..2cfffe1 --- /dev/null +++ b/oci17.sql @@ -0,0 +1,27 @@ +rem +rem $Header: oci17.sql 11-oct-2006.15:55:34 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci17.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci17.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect,resource to ocitest; +connect ocitest/OCITEST; + +create table oci17tab (col1 varchar2(30)); + +commit; diff --git a/oci18.c b/oci18.c new file mode 100644 index 0000000..9a62cac --- /dev/null +++ b/oci18.c @@ -0,0 +1,417 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci18.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests array insert via PL/SQL function + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + whe 10/20/99 - #1039217: add int for static variable pass + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/22/97 - Fix VMS porting exceptions + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci18.c + * + * Description: This program performs an array insert one column using + * an PLSQL FUNCTION. + * Always inserting 5 rows at a time. + * + * Based on: oci14.c + * Changes: made it a function + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires ONE argument - number of rows to insert + * + * oci18 4 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - none insert statement + * Execute - oexec + * Fetch - none insert + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +uword row_count = 0; /* number of rows inserted so far */ +uword numrows; /* get it as input */ + +/* Function prototypes */ +void logon (); +void logoff (); +void setup(); +void err_report(); +void insert_data(); +void do_exit(); +void initialize_data(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"\ + begin \ + :retval := oci18pkg.oci18func(:col1, :numins);\ + end;"; + +#define NUMCOLS 1 /* number of columns returned by above query */ +#define MAX_ROWS_PER_INSERT 5 /* 5 rows max per insert */ + +uword numinsert; /* number of rows to insert on the current pass */ +uword retval; /* return value from function */ + +/* array fetch definitions */ +struct col_struct{ + sword size; /* length of the column */ + sword type; /* type of the column */ + } ; + +struct col_struct coltable [] = + { {MAX_NAME_LENGTH+1, SQLT_STR} + }; + + +struct colp { /* Buffer descriptor */ + sword c_type; /* What type is this column fetched as */ + ub1 *c_buf; /* The area to store the column */ + ub2 c_size; /* Size of the storage area */ + sb2 *c_indp; /* Indicator variable for this column */ + ub2 *c_rlen; /* Fetched length of the column */ + ub2 *c_rcode; /* array of return codes */ + sb4 c_curlen; /* current length */ + };/* COLUMN STRUCTURE */ +typedef struct colp colp; +#define malloc_col(n) (colp *)malloc((size_t)(n * sizeof(colp))); + +colp *cols; /* column structure */ + +main(argc, argv) +eword argc; +text **argv; +{ + + if (argc != 2) + { + printf("\n\n Usage: where numrows is the number of \ +rows the user wants to insert \n"); + do_exit(OCI_EXIT_FAILURE); + } + + numrows = atoi((char *)argv[1]); + if (numrows > 26) + { + printf("Please input a number under 26\n"); + do_exit(OCI_EXIT_FAILURE); + } + printf("\n Total number of rows to be inserted is %d\n", numrows); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statment */ + + insert_data(); + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + colp *colsptr; /* temporary pointer */ + sword colindex; + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + /* bind the scalar */ + + if (obndra(&cda, (text *)":numins", -1, + (ub1 *)&numinsert, (sword)sizeof(numinsert), + SQLT_INT, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) /* bind */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (obndra(&cda, (text *)":retval", -1, + (ub1 *)&retval, (sword)sizeof(retval), + SQLT_INT, -1, (sb2 *) 0, (ub2 *)0, (ub2 *)0, + (ub4)0, (ub4 *)0, (text *)0, -1, -1)) /* bind */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + cols = malloc_col(NUMCOLS); + colsptr = cols; + for (colindex = 0; colindex < NUMCOLS; colindex++, colsptr++) + { + + colsptr->c_size = coltable[colindex].size; + colsptr->c_type = coltable[colindex].type; + colsptr->c_indp = (sb2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(sb2))); + memset((dvoid *)colsptr->c_indp, 0, MAX_ROWS_PER_INSERT * sizeof(sb2)); + colsptr->c_rlen = (ub2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(ub2))); + memset((dvoid *)colsptr->c_rlen, 0, MAX_ROWS_PER_INSERT * sizeof(ub2)); + colsptr->c_rcode = (ub2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(ub2))); + memset((dvoid *)colsptr->c_rcode, 0, MAX_ROWS_PER_INSERT * sizeof(ub2)); + colsptr->c_buf = + (ub1 *)malloc((size_t)(MAX_ROWS_PER_INSERT*colsptr->c_size)); + memset((dvoid *)colsptr->c_buf, 0, MAX_ROWS_PER_INSERT * colsptr->c_size); + colsptr->c_curlen = 0; + + switch (colindex) { + case(0) : + +/* GOTCHA!!! - need to pass in zeroes for mal and cal parameters when + running a regular insert. Set it to non-zero when using plsql */ + if (obndra(&cda, (text *)":col1", -1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, colsptr->c_rlen, colsptr->c_rcode, + (ub4)MAX_ROWS_PER_INSERT, (ub4 *)&(colsptr->c_curlen), + (text *)0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + break; + } + + } + +} + +/* + * Function: insert_data + * + * Description: This routine inserts the data into the table + * + */ +void insert_data() +{ + + colp *colsptr; + sword colindex; + + row_count = 0; + while (row_count < numrows) + { + + colsptr = cols; + numinsert = numrows - row_count < MAX_ROWS_PER_INSERT ? + numrows - row_count : MAX_ROWS_PER_INSERT; + + for (colindex = 0; colindex < NUMCOLS; colsptr++, colindex++) + { + initialize_data(colsptr->c_buf, colsptr->c_size, colsptr->c_rlen, + numinsert); + colsptr->c_curlen = numinsert; + } + + /* using offset zero - we want all the rows right away */ + if (oexec(&cda)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + printf(" Number of rows processed so far is %d\n", retval); + + row_count += numinsert; + } + +} + +/* + * Function: initialize_data + * + * Description: This routine generates data for insertion + * + */ +void initialize_data(arr, len, flen, numinsert) +ub1 *arr; +sword len; +ub2 *flen; +sword numinsert; +{ + + static int pass = 0; + sword colindex; /* index */ + sword numchars; /* number of characters to extract */ + text *str = (text *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + + for (colindex = 0; colindex < numinsert; colindex++) + { + numchars = (pass * MAX_ROWS_PER_INSERT) + colindex + 1; + memcpy((dvoid *)(arr + colindex*len), (dvoid *)str, numchars); + *(arr + colindex*len + numchars ) = '\0'; /* null terminate */ + printf("iteration %d string is %s length is %d\n", + pass, arr + colindex *len, + strlen((char *)(arr + colindex *len))); + +/* GOTCHA!! - The null must be found within the length specified so add one */ +/* or just use the max length allowed for the array element */ + + *(flen + colindex) = strlen((char *)(arr + colindex*len)) + 1; + /* *(flen + colindex) = 30; <--- or use this */ + } + + pass++; + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci18.sql b/oci18.sql new file mode 100644 index 0000000..e7fd007 --- /dev/null +++ b/oci18.sql @@ -0,0 +1,63 @@ +rem +rem $Header: oci18.sql 11-oct-2006.15:55:34 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci18.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci18.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect,resource to ocitest; +connect ocitest/OCITEST; + +create table oci18tab (col1 varchar2(30)); + +create or replace package oci18pkg as + + type char_array is table of varchar2(30) index by binary_integer; + + function oci18func( + col1 in char_array, -- array to put cname in + numins in integer) + return integer; + +end; +/ + +create or replace package body oci18pkg as + + + function oci18func( + col1 in char_array, + numins in integer + ) return integer is retval integer; + + begin + + for i in 1..numins loop + insert into oci18tab values (col1(i)); + end loop; + commit; + + retval := numins; + return(retval); + + end; + +end; +/ + +commit; + diff --git a/oci19.c b/oci19.c new file mode 100644 index 0000000..c9b7f18 --- /dev/null +++ b/oci19.c @@ -0,0 +1,403 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci19.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests array insert with multiple retries + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + whe 10/20/99 - #1039217: add int for static variable pass + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/22/97 - Fix VMS porting exceptions + echen 03/11/97 - no stderr + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci19.c + * + * Description: This program performs an array insert one column using + * an INSERT statement. + * Always inserting 5 rows at a time. + * If one of the rows fails, retry the insert with the next + * row (offset) + * + * Based on: oci14.c + * Changes: added offset call + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires ONE argument - number of rows to insert + * + * oci19 4 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - none insert statement + * Execute - oexec + * Fetch - none insert + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +uword row_count = 0; /* number of rows inserted so far */ +uword numrows; /* get it as input */ + +/* Function prototypes */ +void logon (); +void logoff (); +void setup(); +void err_report(); +void insert_data(); +void do_exit(); +void initialize_data(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"INSERT INTO oci19tab (col1) values (:col1)"; + +#define NUMCOLS 1 /* number of columns returned by above query */ +#define MAX_ROWS_PER_INSERT 5 /* 5 rows max per insert */ + +/* array fetch definitions */ +struct col_struct{ + sword size; /* length of the column */ + sword type; /* type of the column */ + } ; + +struct col_struct coltable [] = + { {MAX_NAME_LENGTH+1, SQLT_STR} + }; + + +struct colp { /* Buffer descriptor */ + sword c_type; /* What type is this column fetched as */ + ub1 *c_buf; /* The area to store the column */ + ub2 c_size; /* Size of the storage area */ + sb2 *c_indp; /* Indicator variable for this column */ + ub2 *c_rlen; /* Fetched length of the column */ + ub2 *c_rcode; /* array of return codes */ + sb4 c_curlen; /* current length */ + };/* COLUMN STRUCTURE */ +typedef struct colp colp; +#define malloc_col(n) (colp *)malloc((size_t)(n * sizeof(colp))); + +colp *cols; /* column structure */ + +main(argc, argv) +eword argc; +text **argv; +{ + + if (argc != 2) + { + printf("\n\n Usage: where numrows is the number of \ +rows the user wants to insert \n"); + do_exit(OCI_EXIT_FAILURE); + } + + numrows = atoi((char *)argv[1]); + if (numrows > 26) + { + printf("Please input a number under 26\n"); + do_exit(OCI_EXIT_FAILURE); + } + printf("\n Total number of rows to be inserted is %d\n", numrows); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + insert_data(); + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + colp *colsptr; /* temporary pointer */ + sword colindex; + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + cols = malloc_col(NUMCOLS); + colsptr = cols; + for (colindex = 0; colindex < NUMCOLS; colindex++, colsptr++) + { + + colsptr->c_size = coltable[colindex].size; + colsptr->c_type = coltable[colindex].type; + colsptr->c_indp = (sb2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(sb2))); + memset((dvoid *)colsptr->c_indp, 0, MAX_ROWS_PER_INSERT * sizeof(sb2)); + colsptr->c_rlen = (ub2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(ub2))); + memset((dvoid *)colsptr->c_rlen, 0, MAX_ROWS_PER_INSERT * sizeof(ub2)); + colsptr->c_rcode = (ub2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(ub2))); + memset((dvoid *)colsptr->c_rcode, 0, MAX_ROWS_PER_INSERT * sizeof(ub2)); + colsptr->c_buf = + (ub1 *)malloc((size_t)(MAX_ROWS_PER_INSERT*colsptr->c_size)); + memset((dvoid *)colsptr->c_buf, 0, MAX_ROWS_PER_INSERT * colsptr->c_size); + colsptr->c_curlen = 0; + + switch (colindex) { + case(0) : + +/* GOTCHA!!! - need to pass in zeroes for mal and cal parameters when + running a regular insert. Set it to non-zero when using plsql */ + if (obndra(&cda, (text *)":col1", -1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, colsptr->c_rlen, colsptr->c_rcode, + (ub4)0, (ub4 *)0, + (text *)0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + break; + } + + } + +} + +/* + * Function: insert_data + * + * Description: This routine inserts the data into the table + * + */ +void insert_data() +{ + + colp *colsptr; + sword colindex; + sword numinsert; /* number of rows to insert on the current pass */ + sword offset; /* offset for oexn call */ + + row_count = 0; + while (row_count < numrows) + { + + colsptr = cols; + numinsert = numrows - row_count < MAX_ROWS_PER_INSERT ? + numrows - row_count : MAX_ROWS_PER_INSERT; + + for (colindex = 0; colindex < NUMCOLS; colsptr++, colindex++) + initialize_data(colsptr->c_buf, colsptr->c_size, colsptr->c_rlen, + numinsert); + + offset = -1; /* first time oexn will have offset 0 */ + while (offset < numinsert) + { + offset++; + if (oexn(&cda, numinsert, offset)) + { + err_report(&cda); + } + + offset += cda.rpc; + + /* this case checks for the last row that failed insertion */ + if (offset + 1 == numinsert) + break; + + if (offset < numinsert) + printf("retrying with offset %d\n", offset + 1); + } + + row_count += numinsert; + } + +} + +/* + * Function: initialize_data + * + * Description: This routine generates data for insertion + * + */ +void initialize_data(arr, len, flen, numinsert) +ub1 *arr; +sword len; +ub2 *flen; +sword numinsert; +{ + + static int pass = 0; + sword colindex; /* index */ + sword numchars; /* number of characters to extract */ + text *str = (text *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + + for (colindex = 0; colindex < numinsert; colindex++) + { + numchars = (pass * MAX_ROWS_PER_INSERT) + colindex + 1; + memcpy((dvoid *)(arr + colindex*len), (dvoid *)str, numchars); + *(arr + colindex*len + numchars ) = '\0'; /* null terminate */ + printf("iteration %d string is %s length is %d\n", + pass, arr + colindex *len, + strlen((char *)(arr + colindex *len))); + +/* GOTCHA!! - The null must be found within the length specified so add one */ +/* or just use the max length allowed for the array element */ + + *(flen + colindex) = strlen((char *)(arr + colindex*len)) + 1; + /* *(flen + colindex) = 30; <--- or use this */ + } + + pass++; + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + printf("%s\n", msg); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci19.sql b/oci19.sql new file mode 100644 index 0000000..df0950a --- /dev/null +++ b/oci19.sql @@ -0,0 +1,30 @@ +rem +rem $Header: oci19.sql 11-oct-2006.15:55:34 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci19.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci19.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect,resource to ocitest; +connect ocitest/OCITEST; + +create table oci19tab (col1 varchar2(30) unique); +insert into oci19tab values ('AB'); +insert into oci19tab values ('ABCDEFG'); +insert into oci19tab values ('ABCDEFGHIJ'); +insert into oci19tab values ('ABCDEFGHIJKLMNO'); +commit; diff --git a/oci20.c b/oci20.c new file mode 100644 index 0000000..81e3ba7 --- /dev/null +++ b/oci20.c @@ -0,0 +1,415 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci20.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests OOPT call + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + whe 10/20/99 - #1039217: add int for static variable pass + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/22/97 - Fix VMS porting exceptions + echen 03/11/97 - no stderr + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci20.c + * + * Description: This program performs an array insert one column using + * an INSERT statement. + * Always inserting 5 rows at a time. + * If one of the rows fails, retry the insert with the next + * row (offset) + * Adding a nonblocking oopt call if table is locked + * + * Based on: oci19.c + * Changes: added offset call + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires ONE argument - number of rows to insert + * Lock table in another window before running this program + * + * oci20 4 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - none insert statement + * Execute - oexec + * Fetch - none insert + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Globals needed */ +uword row_count = 0; /* number of rows inserted so far */ +uword numrows; /* get it as input */ + +/* Function prototypes */ +void logon (); +void logoff (); +void setup(); +void err_report(); +void insert_data(); +void do_exit(); +void initialize_data(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"INSERT INTO oci20tab (col1) values (:col1)"; + +#define NUMCOLS 1 /* number of columns returned by above query */ +#define MAX_ROWS_PER_INSERT 5 /* 5 rows max per insert */ + +/* array fetch definitions */ +struct col_struct{ + sword size; /* length of the column */ + sword type; /* type of the column */ + } ; + +struct col_struct coltable [] = + { {MAX_NAME_LENGTH+1, SQLT_STR} + }; + + +struct colp { /* Buffer descriptor */ + sword c_type; /* What type is this column fetched as */ + ub1 *c_buf; /* The area to store the column */ + ub2 c_size; /* Size of the storage area */ + sb2 *c_indp; /* Indicator variable for this column */ + ub2 *c_rlen; /* Fetched length of the column */ + ub2 *c_rcode; /* array of return codes */ + sb4 c_curlen; /* current length */ + };/* COLUMN STRUCTURE */ +typedef struct colp colp; +#define malloc_col(n) (colp *)malloc((size_t)(n * sizeof(colp))); + +colp *cols; /* column structure */ + +main(argc, argv) +eword argc; +text **argv; +{ + + if (argc != 2) + { + printf("\n\n Usage: where numrows is the number of \ +rows the user wants to insert \n"); + do_exit(OCI_EXIT_FAILURE); + } + + numrows = atoi((char *)argv[1]); + if (numrows > 26) + { + printf("Please input a number under 26\n"); + do_exit(OCI_EXIT_FAILURE); + } + printf("\n Total number of rows to be inserted is %d\n", numrows); + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + insert_data(); + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + colp *colsptr; /* temporary pointer */ + sword colindex; + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + cols = malloc_col(NUMCOLS); + colsptr = cols; + for (colindex = 0; colindex < NUMCOLS; colindex++, colsptr++) + { + + colsptr->c_size = coltable[colindex].size; + colsptr->c_type = coltable[colindex].type; + colsptr->c_indp = (sb2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(sb2))); + memset((dvoid *)colsptr->c_indp, 0, MAX_ROWS_PER_INSERT * sizeof(sb2)); + colsptr->c_rlen = (ub2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(ub2))); + memset((dvoid *)colsptr->c_rlen, 0, MAX_ROWS_PER_INSERT * sizeof(ub2)); + colsptr->c_rcode = (ub2*)malloc((size_t)(MAX_ROWS_PER_INSERT*sizeof(ub2))); + memset((dvoid *)colsptr->c_rcode, 0, MAX_ROWS_PER_INSERT * sizeof(ub2)); + colsptr->c_buf = + (ub1 *)malloc((size_t)(MAX_ROWS_PER_INSERT*colsptr->c_size)); + memset((dvoid *)colsptr->c_buf, 0, MAX_ROWS_PER_INSERT * colsptr->c_size); + colsptr->c_curlen = 0; + + switch (colindex) { + case(0) : + +/* GOTCHA!!! - need to pass in zeroes for mal and cal parameters when + running a regular insert. Set it to non-zero when using plsql */ + if (obndra(&cda, (text *)":col1", -1, + colsptr->c_buf, colsptr->c_size, + (sword)colsptr->c_type, (sword) -1, + (sb2 *)colsptr->c_indp, colsptr->c_rlen, colsptr->c_rcode, + (ub4)0, (ub4 *)0, + (text *)0, -1, -1)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + break; + } + + } + +#define ROLLBACK_TXN 0 /* rollback entire transaction of non-fatal error */ + /* as documented, this behavior does not exist anymore */ +#define WAIT_OPTION 4 /* don't block for resources */ + + if (oopt(&cda, ROLLBACK_TXN, WAIT_OPTION)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: insert_data + * + * Description: This routine inserts the data into the table + * + */ +void insert_data() +{ + + colp *colsptr; + sword colindex; + sword numinsert; /* number of rows to insert on the current pass */ + sword offset; /* offset for oexn call */ + + row_count = 0; + while (row_count < numrows) + { + + colsptr = cols; + numinsert = numrows - row_count < MAX_ROWS_PER_INSERT ? + numrows - row_count : MAX_ROWS_PER_INSERT; + + for (colindex = 0; colindex < NUMCOLS; colsptr++, colindex++) + initialize_data(colsptr->c_buf, colsptr->c_size, colsptr->c_rlen, + numinsert); + + offset = -1; /* first time oexn will have offset 0 */ + while (offset < numinsert) + { + offset++; + if (oexn(&cda, numinsert, offset)) + { + err_report(&cda); + } + + offset += cda.rpc; + + /* this case checks for the last row that failed insertion */ + if (offset + 1 == numinsert) + break; + + if (offset < numinsert) + printf("retrying with offset %d\n", offset + 1); + } + + row_count += numinsert; + } + +} + +/* + * Function: initialize_data + * + * Description: This routine generates data for insertion + * + */ +void initialize_data(arr, len, flen, numinsert) +ub1 *arr; +sword len; +ub2 *flen; +sword numinsert; +{ + + static int pass = 0; + sword colindex; /* index */ + sword numchars; /* number of characters to extract */ + text *str = (text *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + + for (colindex = 0; colindex < numinsert; colindex++) + { + numchars = (pass * MAX_ROWS_PER_INSERT) + colindex + 1; + memcpy((dvoid *)(arr + colindex*len), (dvoid *)str, numchars); + *(arr + colindex*len + numchars ) = '\0'; /* null terminate */ + printf("iteration %d string is %s length is %d\n", + pass, arr + colindex *len, + strlen((char *)(arr + colindex *len))); + +/* GOTCHA!! - The null must be found within the length specified so add one */ +/* or just use the max length allowed for the array element */ + + *(flen + colindex) = strlen((char *)(arr + colindex*len)) + 1; + /* *(flen + colindex) = 30; <--- or use this */ + } + + pass++; + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + printf("%s\n", msg); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci20.sql b/oci20.sql new file mode 100644 index 0000000..d775d5a --- /dev/null +++ b/oci20.sql @@ -0,0 +1,30 @@ +rem +rem $Header: oci20.sql 11-oct-2006.15:55:34 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci20.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci20.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect,resource to ocitest; +connect ocitest/OCITEST; + +create table oci20tab (col1 varchar2(30) unique); +insert into oci20tab values ('AB'); +insert into oci20tab values ('ABCDEFG'); +insert into oci20tab values ('ABCDEFGHIJ'); +insert into oci20tab values ('ABCDEFGHIJKLMNO'); +commit; diff --git a/oci21.c b/oci21.c new file mode 100644 index 0000000..f2f5043 --- /dev/null +++ b/oci21.c @@ -0,0 +1,278 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci21.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests non-blocking operations by changing a blocking connection to + non-blocking + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + azhao 09/11/97 - comment out printf when blocked + ehayes 05/29/97 - Fix olint errors + emendez 06/16/97 - + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci21.c + * + * Description: This program performs a "long" running hardcoded insert + * and demonstrates the use of non-blocking calls. + * + * Based on: - + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. Program requires no arguments. + * This demo assumes the existence of the alias inst1_nonblock + * in your tnsnames.ora file to access a non-blocking + * protocol + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - none insert statement + * Execute - oexec + * Fetch - none insert + * Close - oclose + * Logoff - olof + * Nonblocking - onbtst, onbclr, onbset + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +#define BLOCKED -3123 +#define SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Function prototypes */ +void logon (); +void logoff (); +void setup(); +void err_report(); +void insert_data(); +void do_exit(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"INSERT INTO oci21tab (col1)\ + SELECT a.col1 \ + FROM oci21tab a, oci21tab b"; + +main(argc, argv) +eword argc; +text **argv; +{ + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + insert_data(); + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + if (onbset(&lda)) /* make the connection non-blocking */ + { + err_report((Cda_Def *)&lda); + do_exit(OCI_EXIT_FAILURE); + } + + if (onbtst(&lda)) /* verify that it is non-blocking */ + { + printf("connection is still blocking!!!\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: insert_data + * + * Description: This routine inserts the data into the table + * + */ +void insert_data() +{ + + ub1 done = 0; + static ub1 printed = FALSE; /* just print blocked message once */ + while (!done) + { + switch(oexec(&cda)) + { + case BLOCKED:/* will come through here multiple times, print msg once */ +/* + if (!printed) + printf("Blocked - do something else while SQL stmt executes...\n"); + printed = TRUE; +*/ + break; + case SUCCESS: + done = 1; + break; + default: + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); /* get out of application */ + } + + } + + if (onbclr(&lda)) /* clear the non-blocking status of the connection */ + { + err_report((Cda_Def *)&lda); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", + -1, (text*)"inst1_nonblock" , -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci21.sql b/oci21.sql new file mode 100644 index 0000000..1a61513 --- /dev/null +++ b/oci21.sql @@ -0,0 +1,40 @@ +rem +rem $Header: oci21.sql 11-oct-2006.15:55:35 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci21.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci21.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect,resource to ocitest; +connect ocitest/OCITEST; + +create table oci21tab (col1 varchar2(30)); +insert into oci21tab values ('A'); +insert into oci21tab values ('AB'); +insert into oci21tab values ('ABC'); +insert into oci21tab values ('ABCD'); +insert into oci21tab values ('ABCDE'); +insert into oci21tab values ('ABCDEF'); +insert into oci21tab values ('ABCDEFG'); +insert into oci21tab values ('ABCDEFGH'); +insert into oci21tab values ('ABCDEFGHI'); +insert into oci21tab values ('ABCDEFGHIJ'); +insert into oci21tab values ('ABCDEFGHIJK'); +insert into oci21tab values ('ABCDEFGHIJKL'); + +commit; + diff --git a/oci22.c b/oci22.c new file mode 100644 index 0000000..68b2561 --- /dev/null +++ b/oci22.c @@ -0,0 +1,293 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci22.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests non-blocking connections + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + azhao 09/11/97 - comment out printf when blocked + emendez 06/16/97 - + ehayes 05/29/97 - Fix olint errors + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci22.c + * + * Description: This program performs a "long" running hardcoded insert + * and demonstrates the use of non-blocking calls. + * + * Based on: oci21.c + * Changes: modified login to non-blocking + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. Program requires no arguments. + * This demo assumes the existence of the alias inst1_nonblock + * in your tnsnames.ora file to access a non-blocking + * protocol + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog use nonblocking argument + * Open - oopen + * Parse - oparse + * Bind - obndra + * Describe - none Hard-coded query + * Define - none insert statement + * Execute - oexec + * Fetch - none insert + * Close - oclose + * Logoff - olof + * Nonblocking - onbtst, onbclr + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +#define BLOCKED -3123 +#define SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Function prototypes */ +void logon (); +void logoff (); +void setup(); +void err_report(); +void insert_data(); +void do_exit(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"INSERT INTO oci22tab (col1)\ + SELECT a.col1 \ + FROM oci22tab a, oci22tab b"; + +main(argc, argv) +eword argc; +text **argv; +{ + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + insert_data(); + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (onbtst(&lda)) + { + printf("connection is still blocking!!!\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: insert_data + * + * Description: This routine inserts the data into the table + * + */ +void insert_data() +{ + + ub1 done = 0; + static ub1 printed = FALSE; /* just print blocked message once */ + while (!done) + { + switch(oexec(&cda)) + { + case BLOCKED:/* will come through here multiple times, print msg once */ +/* + if (!printed) + printf("Blocked - do something else while SQL stmt executes...\n"); + printed = TRUE; +*/ + break; + case SUCCESS: + done = 1; + break; + default: + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); /* get out of application */ + } + + } + + if (onbclr(&lda)) /* clear the non-blocking status of the connection */ + { + err_report((Cda_Def *)&lda); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + ub1 done = 0; + static ub1 logprint = FALSE; /* just print blocked logon once */ + while (!done) + { + switch (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, + (text *)"OCITEST", -1, + (text *)"inst1_nonblock", -1, (ub4)OCI_LM_NBL)) + { + + case BLOCKED:/* will come through here multiple times, print msg once */ +/* + if (!logprint) + printf("blocked - keep trying to log on\n"); + logprint = TRUE; +*/ + break; + case SUCCESS: + printf("logged on\n"); + done = 1; + break; + default: + err_report((Cda_Def *)&lda); + do_exit(OCI_EXIT_FAILURE); + } + + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci22.sql b/oci22.sql new file mode 100644 index 0000000..8d0d2df --- /dev/null +++ b/oci22.sql @@ -0,0 +1,40 @@ +rem +rem $Header: oci22.sql 11-oct-2006.15:55:35 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci22.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci22.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect,resource to ocitest; +connect ocitest/OCITEST; + +create table oci22tab (col1 varchar2(30)); +insert into oci22tab values ('A'); +insert into oci22tab values ('AB'); +insert into oci22tab values ('ABC'); +insert into oci22tab values ('ABCD'); +insert into oci22tab values ('ABCDE'); +insert into oci22tab values ('ABCDEF'); +insert into oci22tab values ('ABCDEFG'); +insert into oci22tab values ('ABCDEFGH'); +insert into oci22tab values ('ABCDEFGHI'); +insert into oci22tab values ('ABCDEFGHIJ'); +insert into oci22tab values ('ABCDEFGHIJK'); +insert into oci22tab values ('ABCDEFGHIJKL'); + +commit; + diff --git a/oci23.c b/oci23.c new file mode 100644 index 0000000..6e3a825 --- /dev/null +++ b/oci23.c @@ -0,0 +1,297 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci23.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests describe function + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/29/97 - Fix olint errors + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci23.c + * + * Description: This program illustrates how to do a describe on a query + * + * Based on: + * Changes: + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires NO arguments + * + * oci23 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - none + * Describe - odescr + * Define - none + * Execute - none + * Fetch - none + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Function prototypes */ +void logon (); +void logoff (); +void setup(); +void err_report(); +void dump_data(); +void do_exit(); +void do_describe(); + +/* SQL statement used in this program */ + +text *sqlstmt = (text *)"SELECT one, two, three, four FROM oci23tab"; + +main(argc, argv) +eword argc; +text **argv; +{ + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + do_describe(); + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oparse(&cda, sqlstmt, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: do_describe + * + * Description: This routine actually describes a sql statement and prints + * the information pertaining to it. + * + */ +void do_describe() +{ + +#define COL_SIZE 20 +#define NUM_SELECT_ITEMS 4 + +sword items = NUM_SELECT_ITEMS; /* number of select items */ +sword colindex; +sb4 *dbsize; /* maximum size of column */ +sb2 *dbtype; /* internal column datatype */ +sb1 *column_name; /* buffer to store column names */ +sb4 *col_buf_len; /* length of column */ +sb4 *display_size; /* maximum display size */ +sb2 *precision; /* precision */ +sb2 *scale; /* scale */ +sb2 *nullok; /* column can have null values in it * + + /* allocate the needed storage */ + + dbsize = (sb4 *)malloc((ub4)(items * sizeof(sb4))); + dbtype = (sb2 *)malloc((ub4)(items * sizeof(sb2))); + column_name = (sb1 *)malloc((ub4)(items * sizeof(sb1) * COL_SIZE)); + col_buf_len = (sb4 *)malloc((ub4)(items * sizeof(sb4))); + display_size = (sb4 *)malloc((ub4)(items * sizeof(sb4))); + precision = (sb2 *)malloc((ub4)(items * sizeof(sb2))); + scale = (sb2 *)malloc((ub4)(items * sizeof(sb2))); + nullok = (sb2 *)malloc((ub4)(items * sizeof(sb2))); + + for (colindex = 0; colindex < items; colindex++) + { + + /* Have to initialize length, otherwise nothing is returned */ + *(col_buf_len + colindex) = COL_SIZE; + + if (odescr(&cda, colindex + 1, + dbsize + colindex, dbtype + colindex, + column_name + (COL_SIZE * colindex), col_buf_len + colindex, + display_size + colindex, precision + colindex, + scale + colindex, nullok + colindex)) + { + err_report(&cda); + do_exit (OCI_EXIT_FAILURE); + } + + } + + printf("printing out results of the describe \n"); + + for (colindex = 0; colindex < items; colindex++) + { + printf("\n\n\nInformation from desc for column %d\n\n", colindex + 1); + + printf("Column Maximum Size is %d\n", *(dbsize + colindex)); + printf("Column Type is %d\n", *(dbtype + colindex)); + + printf("Column Name Length is %d\n", *(col_buf_len + colindex)); + *(column_name + (COL_SIZE*colindex) + *(col_buf_len+colindex))='\0'; + printf("Column Name is %s\n", + column_name + (COL_SIZE*colindex)); + + printf("Column Length is %d\n", *(col_buf_len + colindex)); + printf("Column Display Size is %d\n", *(display_size + colindex)); + printf("Column Precision is %d\n", *(precision + colindex)); + printf("Column Scale is %d\n", *(scale + colindex)); + printf("Column Nulls allowed is %d\n", *(nullok + colindex)); + + } + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci23.sql b/oci23.sql new file mode 100644 index 0000000..9f9bde9 --- /dev/null +++ b/oci23.sql @@ -0,0 +1,34 @@ +rem +rem $Header: oci23.sql 11-oct-2006.15:55:35 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci23.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci23.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem emendez 06/16/97 - +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +rem +rem Create a new user - call it ocitest +rem +connect sys/knl_test7 as sysdba; +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect, resource to ocitest; + +rem +rem Created needed tables +rem +connect ocitest/OCITEST; + +create table oci23tab (one number not null, two long, three date, + four char(10)); + diff --git a/oci24.c b/oci24.c new file mode 100644 index 0000000..ffdd69a --- /dev/null +++ b/oci24.c @@ -0,0 +1,263 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci24.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests describe of a PL/SQL package + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + chliang 02/06/01 - merge request for porting exception #1593298. + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/29/97 - Fix olint errors + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ + +/* + * Name: oci24.c + * + * Description: This program illustrates how to do a describe on a procedure + * using odessp + * + * Based on: + * Changes: + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires NO arguments + * + * oci24 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse + * Bind - none + * Describe - odescr + * Define - none + * Execute - none + * Fetch - none + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + +#define MAX_NAME_LENGTH 30 /* Maximum length of a column name */ +#define ASIZE 15 + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Function prototypes */ +void logon (); +void logoff (); +void setup (); +void err_report(); +void do_exit(); +void do_describe(); + +/* odessp uses the object name directly, no SQL statement involved */ + +text *objname = (text *)"oci24pkg.oci24proc"; /* name of object */ + +main(argc, argv) +eword argc; +text **argv; +{ + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + do_describe(); + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: do_describe + * + * Description: This routine actually describes a sql statement and prints + * the information pertaining to it. + * + */ +void do_describe() +{ + + +ub2 ovrld[ASIZE]; /* overloading information */ +ub2 pos[ASIZE]; /* parameter position */ +ub2 level[ASIZE]; /* level for composite parameters */ +text argnm[ASIZE][MAX_NAME_LENGTH]; /* parameter names */ +ub2 arnlen[ASIZE]; /* length of parameter names */ +ub2 dtype[ASIZE]; /* Oracle datatype codes for parameters */ +ub1 defsup[ASIZE]; /* returns "default supplied" indicators */ +ub1 mode[ASIZE]; /* mode ie. IN, OUT, IN/OUT */ +ub4 dtsize[ASIZE]; /* lengths */ +sb2 prec[ASIZE]; /* precision, if a number */ +sb2 scale[ASIZE]; /* scale, if a number */ +ub1 radix[ASIZE]; /* radix, if a number */ +ub4 spare[ASIZE]; /* reserved, must be passed */ +ub4 array_size; /* size of the OUT arrays */ +ub2 i; /* counter */ + + array_size = ASIZE; /* gotcha - you need to input the array size */ + + + if (odessp(&lda, objname, -1, (ub1 *)0, 0, (ub1 *)0, 0, + ovrld, pos, level, (text **)argnm, arnlen, dtype, defsup, mode, + dtsize, prec, scale, radix, spare, &array_size)) + { + err_report((Cda_Def *)&lda); + do_exit(OCI_EXIT_FAILURE); + } + + printf("array contains information for %d entries \n", array_size); + + printf("Overload\tLevel\tPos\tprocName\tDatatype\n"); + for (i = 0; i < array_size; i++) + { + printf("%8d\t%5d\t%3d\t%.*s\t%16d\n", + ovrld[i], level[i], pos[i], arnlen[i], argnm[i], dtype[i]); + } +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} diff --git a/oci24.sql b/oci24.sql new file mode 100644 index 0000000..2728fc5 --- /dev/null +++ b/oci24.sql @@ -0,0 +1,52 @@ +rem +rem $Header: oci24.sql 11-oct-2006.15:55:35 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci24.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci24.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem svedala 09/11/98 - a "/" required after create package-bug 717842 +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; + +rem +rem Create a new user - call it ocitest +rem +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect, resource to ocitest; + +rem +rem Created needed tables +rem +connect ocitest/OCITEST; + +create table oci24tab (ename char(10), empno number, sal number); + +create or replace package oci24pkg as + +procedure oci24proc( + name in oci24tab.ename%type, + salary out oci24tab.sal%type); + +procedure oci24proc( + id_num in oci24tab.empno%type, + salary out oci24tab.sal%type); + +function oci24proc ( + name oci24tab.ename%type) return number; + +end oci24pkg; +/ + + diff --git a/oci25.c b/oci25.c new file mode 100644 index 0000000..b1d5077 --- /dev/null +++ b/oci25.c @@ -0,0 +1,246 @@ +/* Copyright (c) 1995, 2006, Oracle. All rights reserved. +*/ + +/* + NAME + oci25.c + DESCRIPTION + Demo program for A22400 OCI Techniques White Paper + Tests DDL operations + MODIFIED (MM/DD/YY) + kmohan 03/28/06 - change hda to size_t + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + ehayes 05/29/97 - Fix olint errors + ehayes 08/22/97 - + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + vraghuna 03/01/95 - Creation +*/ +/* + * Name: oci25.c + * + * Description: This program illustrates how to do DDL with oparse + * + * Based on: + * Changes: + * + * Setup: Run corresponding ociXX.sql before running this program. + * Link program and run it. + * Program requires NO arguments + * + * oci25 + * + * OCI Calls used: + * + * Phase OCI Call Notes + * ------------------------------------------------------------------ + * Login - olog Use instead of orlon as of 7.2 + * Open - oopen + * Parse - oparse does the DDL for us + * Bind - none + * Describe - none + * Define - none + * Execute - none + * Fetch - none + * Close - oclose + * Logoff - olof + * + * This program is for educational purposes. + * + */ + +#include +#include +#include +#include + +#include +/* LDA and CDA struct declarations */ +#include +#ifdef __STDC__ +#include +#else +#include +#endif +/* demo constants and structs */ +#include + + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +/* exit flags */ +#define OCI_EXIT_FAILURE 1 +#define OCI_EXIT_SUCCESS 0 + +Lda_Def lda; /* login area */ +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +Cda_Def cda; /* cursor area */ + +/* Function prototypes */ +void logon (); +void logoff (); +void setup(); +void err_report(); +void dump_data(); +void do_exit(); +void do_describe(); + +/* SQL statement used in this program */ + +text *sqlstm1 = (text *)"CREATE TABLE test1 (col1 number)"; +text *sqlstm2 = (text *)"CREATE TABLE test2 (col1 number)"; +text *sqlstm3 = (text *)"CREATE TABLE test3 (col1 number)"; + +main(argc, argv) +eword argc; +text **argv; +{ + + logon(); /* logon to Oracle database */ + + setup(); /* prepare sql statement */ + + logoff(); /* logoff Oracle database */ + + do_exit(OCI_EXIT_SUCCESS); + +} + +/* + * Function: setup + * + * Description: This routine does the necessary setup to execute the SQL + * statement. Specifically, it does the open, parse, bind and + * define phases as needed. + * + */ +void setup() +{ + + if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) /* open */ + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +/* try creating test1 with a deferred parse but no execute */ + + if (oparse(&cda, sqlstm1, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +/* try creating test2 with a non-deferred parse */ + + if (oparse(&cda, sqlstm2, (sb4) -1, 0, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +/* try creating test3 with a deferred parse AND execute */ + + if (oparse(&cda, sqlstm3, (sb4) -1, DEFER_PARSE, /* parse */ + (ub4) VERSION_7)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + + if (oexec(&cda)) + { + err_report(&cda); + do_exit(OCI_EXIT_FAILURE); + } + +} + +/* + * Function: err_report + * + * Description: This routine prints out the most recent OCI error + * + */ +void err_report(cursor) +Cda_Def *cursor; +{ + sword n; + text msg[512]; /* message buffer to hold error text */ + + if (cursor->fc > 0) + printf("\n-- ORACLE error when processing OCI function %s \n\n", + oci_func_tab[cursor->fc]); + else + printf("\n-- ORACLE error\n"); + + n = (sword)oerhms(&lda, cursor->rc, msg, (sword) sizeof msg); + fprintf(stderr, "%s\n", msg); + +} + +/* + * Function: do_exit + * + * Description: This routine exits with a status + * + */ +void do_exit(status) +eword status; +{ + + if (status == OCI_EXIT_FAILURE) + printf("\n Exiting with FAILURE status %d\n", status); + else + printf("\n Exiting with SUCCESS status %d\n", status); + + exit(status); +} + +/* + * Function: login + * + * Description: This routine logs on onto the database as OCITEST/OCITEST + * + */ +void logon() +{ + + if (olog(&lda, (ub1 *)hda, (text *)"OCITEST", -1, (text *)"OCITEST", -1, + (text *)0, -1, (ub4)OCI_LM_DEF)) + { + err_report((Cda_Def *)&lda); + exit(OCI_EXIT_FAILURE); + } + + printf("\n Connected to ORACLE as ocitest\n"); + +} + +/* + * Function: logoff + * + * Description: This routine closes out any cursors and logs off the database + * + */ +void logoff() +{ + + if (oclose(&cda)) /* close cursor */ + { + fprintf(stderr, "Error closing cursor 1.\n"); + do_exit(OCI_EXIT_FAILURE); + } + + if (ologof(&lda)) /* log off the database */ + { + fprintf(stderr, "Error on disconnect.\n"); + do_exit(OCI_EXIT_FAILURE); + } + +} + diff --git a/oci25.sql b/oci25.sql new file mode 100644 index 0000000..79a06b2 --- /dev/null +++ b/oci25.sql @@ -0,0 +1,35 @@ +rem +rem $Header: oci25.sql 11-oct-2006.15:55:35 azhao Exp $ +rem +rem Copyright (c) 1995, 2006, Oracle. All rights reserved. +rem +rem NAME +rem oci25.sql +rem DESCRIPTION +rem Script for A22400 OCI Techniques White Paper +rem Demo script for oci25.c +rem MODIFIED (MM/DD/YY) +rem azhao 10/11/06 - case-senstive password change +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem cchau 08/18/97 - enable dictionary protection +rem echen 01/10/97 - change internal to sys/change_on_install +rem vraghuna 03/01/95 - Creation + +set echo on; +connect sys/knl_test7 as sysdba; + +rem +rem Create a new user - call it ocitest +rem +drop user ocitest cascade; +create user ocitest identified by OCITEST; +grant connect, resource to ocitest; + +rem +rem Created needed tables +rem +connect ocitest/OCITEST; +drop table test1; +drop table test2; +drop table test3; + diff --git a/oci_f.sed b/oci_f.sed new file mode 100644 index 0000000..2896625 --- /dev/null +++ b/oci_f.sed @@ -0,0 +1,86 @@ +# NAME +# oci_f.sed +# DESCRIPTION +# This sed script changes the OCI function and type names to long +# names +# MODIFIED +# 10/03/96 - Peter Vasterd - Creation +# 10/04/96 - Sreenivas Gollapudi - Added ComplexObjectComp +# +s/ocianyd/ocianyd/g +s/ociatch/OCIServerAttach/g +s/ociauth/OCISessionBegin/g +s/ocibda/OCIBindDynamic/g +s/ocibicfp/OCICallbackInBind/g +s/ociblobl/OCIBlobLocator/g +s/ociclobl/OCIClobLocator/g +s/ocibocfp/OCICallbackOutBind/g +s/ocidcfp/OCICallbackDefine/g +s/ocibndh/OCIBind/g +s/ocibndt/OCIBindObject/g +s/ocibreak/OCIBreak/g +s/ocibsa/OCIBindArrayOfStruct/g +s/ocicorh/OCIComplexObject/g +s/ocicord/OCIComplexObjectComp/g +s/ocicpw/OCIPasswordChange/g +s/ocidarr/OCIDefineArrayOfStruct/g +s/ociddf/OCIDefineDynamic/g +s/ocidfnh/OCIDefine/g +s/ocidndt/OCIDefineObject/g +s/ocidsca/OCIDescribeAny/g +s/ocidsch/OCIDescribe/g +s/ocidtch/OCIServerDetach/g +s/ocienvh/OCIEnv/g +s/ocierrh/OCIError/g +s/ociexec/OCIStmtExecute/g +s/ocifch/OCIStmtFetch/g +s/ocifcls/OCILobFileClose/g +s/ocifcrt/OCILobFileCreate/g +s/ocifdel/OCILobFileDelete/g +s/ocifdesc/OCIDescriptorFree/g +s/ocifhndl/OCIHandleFree/g +s/ocifopn/OCILobFileOpen/g +s/ocifreem/OCIMemoryFree/g +s/ocigattr/OCIAttrGet/g +s/ocigbp/OCIStmtGetBindInfo/g +s/ocigdesc/OCIDescriptorAlloc/g +s/ocigdr/OCIErrorGet/g +s/ocighndl/OCIHandleAlloc/g +s/ocigparm/OCIParamGet/g +s/ocisparm/OCIParamSet/g +s/ocigpi/OCIStmtGetPieceInfo/g +s/ociinit/OCIEnvInit/g +s/ocild2sv/OCILdaToSvcCtx/g +s/ocilfap/OCILobAppend/g +s/ocilfcp/OCILobCopy/g +s/ocilfer/OCILobErase/g +s/ocilfln/OCILobGetLength/g +s/ocilfrd/OCILobRead/g +s/ocilftr/OCILobTrim/g +s/ocilfwr/OCILobWrite/g +s/ocilobd/OCILobLocator/g +s/ocilobl/OCILobLocator/g +s/ocipard/OCIParam/g +s/ocipi/OCIInitialize/g +s/ocirefd/ocirefd/g +s/ocireq/OCIStmtPrepare/g +s/ociridd/OCIRowid/g +s/ocirs2sh/OCIResultSetToStmt/g +s/ocirstd/OCIResult/g +s/ocisattr/OCIAttrSet/g +s/ocisnad/OCISnapshot/g +s/ocispi/OCIStmtSetPieceInfo/g +s/ocisrvh/OCIServer/g +s/ocistmh/OCIStmt/g +s/ocisv2ld/OCISvcCtxToLda/g +s/ocisvch/OCISvcCtx/g +s/ocitac/OCISessionEnd/g +s/ocitxcm/OCITransCommit/g +s/ocitxdt/OCITransDetach/g +s/ocitxfgt/OCITransForget/g +s/ocitxnh/OCITrans/g +s/ocitxpre/OCITransPrepare/g +s/ocitxrl/OCITransRollback/g +s/ocitxst/OCITransStart/g +s/ociusrh/OCISession/g +s/ocivers/OCIServerVersion/g diff --git a/oci_m.sed b/oci_m.sed new file mode 100644 index 0000000..3dcb177 --- /dev/null +++ b/oci_m.sed @@ -0,0 +1,136 @@ +# NAME +# oci_m.sed +# DESCRIPTION +# This sed script changes the OCI macro names to long +# names +# MODIFIED +# 10/03/96 - Peter Vasterd - Creation +# 10/04/96 - Sreenivas Gollapudi - Added OCI_STM and OCI_TX stuff +# 10/21/96 - Peter Vasterd - TOPROW -> PREFETCH +# +s/OCI_ATTR_ENVCTXT/OCI_ATTR_ENV/g +s/OCI_ATTR_SRVRCTXT/OCI_ATTR_SERVER/g +s/OCI_ATTR_TXCTXT/OCI_ATTR_TRANS/g +s/OCI_ATTR_USERCTXT/OCI_ATTR_SESSION/g +s/OCI_ATTR_FUNCODE/OCI_ATTR_FNCODE/g +s/OCI_ATTR_NBLMODE/OCI_ATTR_NONBLOCKING_MODE/g +s/OCI_ATTR_ROWCNT/OCI_ATTR_ROW_COUNT/g +s/OCI_ATTR_TOPRCNT/OCI_ATTR_PREFETCH_ROWS/g +s/OCI_ATTR_NSTD_RCNT/OCI_ATTR_NESTED_ROW_COUNT/g +s/OCI_ATTR_TOP_RMSZ/OCI_ATTR_PREFETCH_MEMORY/g +s/OCI_ATTR_NSTD_RMSZ/OCI_ATTR_NESTED_PREFETCH_MEMORY/g +s/OCI_ATTR_CHRCNT/OCI_ATTR_CHAR_COUNT/g +s/OCI_ATTR_PARMCNT/OCI_ATTR_PARAM_COUNT/g +s/OCI_ATTR_STMTYP/OCI_ATTR_STMT_TYPE/g +s/OCI_ATTR_TXLOCK/OCI_ATTR_TRANS_LOCK/g +s/OCI_ATTR_TXNAME/OCI_ATTR_TRANS_NAME/g +s/OCI_ATTR_CHRSETID/OCI_ATTR_CHARSET_ID/g +s/OCI_ATTR_CHRSETFORM/OCI_ATTR_CHARSET_FORM/g +s/OCI_ATTR_CHRSET/OCI_ATTR_CHARSET/g +s/OCI_ATTR_MAXDATASZ/OCI_ATTR_MAXDATA_SIZE/g +s/OCI_ATTR_OPTSIZE/OCI_ATTR_CACHE_OPT_SIZE/g +s/OCI_ATTR_MAXSIZE/OCI_ATTR_CACHE_MAX_SIZE/g +s/OCI_ATTR_ALLOCDUR/OCI_ATTR_ALLOC_DURATION/g +s/OCI_ATTR_PINDUR/ OCI_ATTR_PIN_DURATION/g +s/OCI_ATTR_CORTYP/OCI_ATTR_COMPLEXOBJECTCOMP_TYPE/g +s/OCI_ATTR_CORLVL/OCI_ATTR_COMPLEXOBJECTCOMP_LEVEL/g +s/OCI_HTYPE_BND/OCI_HTYPE_BIND/g +s/OCI_HTYPE_DFN/OCI_HTYPE_DEFINE/g +s/OCI_HTYPE_DSC/OCI_HTYPE_DESCRIBE/g +s/OCI_HTYPE_ENV/OCI_HTYPE_ENV/g +s/OCI_HTYPE_ERR/OCI_HTYPE_ERROR/g +s/OCI_HTYPE_SRV/OCI_HTYPE_SERVER/g +s/OCI_HTYPE_STM/OCI_HTYPE_STMT/g +s/OCI_HTYPE_SVC/OCI_HTYPE_SVCCTX/g +s/OCI_HTYPE_TXN/OCI_HTYPE_TRANS/g +s/OCI_HTYPE_COR/OCI_HTYPE_COMPLEXOBJECT/g +s/OCI_HTYPE_USR/OCI_HTYPE_SESSION/g +s/OCIATCH/OCI_FNCODE_SERVERATTACH/g +s/OCIAUTH/OCI_FNCODE_SESSIONBEGIN/g +s/OCIBDA/OCI_FNCODE_BINDDYNAMIC/g +s/OCIBNDH/OCI_FNCODE_BIND/g +s/OCIBNDN/OCI_FNCODE_STMTBINDBYNAME/g +s/OCIBNDP/OCI_FNCODE_STMTBINDBYPOS/g +s/OCIBNDT/OCI_FNCODE_BINDOBJECT/g +s/OCIBREAK/OCI_FNCODE_SVCCTXBREAK/g +s/OCIBSA/OCI_FNCODE_BINDARRAYOFSTRUCT/g +s/OCIBSVT/OCI_FNCODE_BINDRECORD/g +s/OCICPW/OCI_FNCODE_PASSWORDCHANGE/g +s/OCIDARR/OCI_FNCODE_DEFINEARRAYOFSTRUCT/g +s/OCIDDF/OCI_FNCODE_DEFINEDYNAMIC/g +s/OCIDEFN/OCI_FNCODE_DEFINE/g +s/OCIDNDT/OCI_FNCODE_DEFINEOBJECT/g +s/OCIDSCA/OCI_FNCODE_DESCRIBEANY/g +s/OCIEXEC/OCI_FNCODE_STMTEXECUTE/g +s/OCIFCH/OCI_FNCODE_STMTFETCH/g +s/OCIFCLS/OCI_FNCODE_LOBCLOSEFILE/g +s/OCIFCRT/OCI_FNCODE_LOBCREATEFILE/g +s/OCIFDEL/OCI_FNCODE_LOBDELFILE/g +s/OCIFDESC/OCI_FNCODE_DESCRIPTORFREE/g +s/OCIFHNDL/OCI_FNCODE_HANDLEFREE/g +s/OCIFOPN/OCI_FNCODE_LOBOPENFILE/g +s/OCIFREEM/OCI_FNCODE_MEMORYFREE/g +s/OCIGATTR/OCI_FNCODE_ATTRGET/g +s/OCIGBP/OCI_FNCODE_STMTGETBIND/g +s/OCIGDESC/OCI_FNCODE_DESCRIPTORALLOC/g +s/OCIGDR/OCI_FNCODE_ERRORGET/g +s/OCIGHNDL/OCI_FNCODE_HANDLEALLOC/g +s/OCIGPARM/OCI_FNCODE_PARAMGET/g +s/OCIGPI/OCI_FNCODE_STMTGETPIECEINFO/g +s/OCIINIT/OCI_FNCODE_ENVINIT/g +s/OCILD2SV/OCI_FNCODE_LDATOSVCCTX/g +s/OCILFAP/OCI_FNCODE_LOBAPPEND/g +s/OCILFCP/OCI_FNCODE_LOBCOPY/g +s/OCILFER/OCI_FNCODE_LOBERASE/g +s/OCILFLN/OCI_FNCODE_LOBGETLENGTH/g +s/OCILFRD/OCI_FNCODE_LOBREAD/g +s/OCILFTR/OCI_FNCODE_LOBTRIM/g +s/OCILFWR/OCI_FNCODE_LOBWRITE/g +s/OCIPI/OCI_FNCODE_INITIALIZE/g +s/OCIREQ/OCI_FNCODE_STMTPREPARE/g +s/OCIRS2SH/OCI_FNCODE_RESULTSETTOSTMT/g +s/OCISATTR/OCI_FNCODE_ATTRSET/g +s/OCISPI/OCI_FNCODE_STMTSETPIECEINFO/g +s/OCISV2LD/OCI_FNCODE_SVCCTXTOLDA/g +s/OCITAC/OCI_FNCODE_SESSIONEND/g +s/OCITXCM/OCI_FNCODE_TRANSCOMMIT/g +s/OCITXDT/OCI_FNCODE_TRANSDETACH/g +s/OCITXFGT/OCI_FNCODE_TRANSFORGET/g +s/OCITXPRE/OCI_FNCODE_TRANSPREPARE/g +s/OCITXRL/OCI_FNCODE_TRANSROLLBACK/g +s/OCITXST/OCI_FNCODE_TRANSSTART/g +s/OCIVERS/OCI_FNCODE_SERVERVERSION/g +s/OCI_FILE_RDWR/OCI_FILE_READWRITE/g +s/OCI_FILE_RDONLY/OCI_FILE_READONLY/g +s/SQLT_CFIL/SQLT_CFILE/g +s/SQLT_BFIL/SQLT_BFILE/g +s/OCI_STM_SELECT/OCI_STMT_SELECT/g +s/OCI_STM_UPDATE/OCI_STMT_UPDATE/g +s/OCI_STM_DELETE/OCI_STMT_DELETE/g +s/OCI_STM_INSERT/OCI_STMT_INSERT/g +s/OCI_STM_DROP/OCI_STMT_DROP/g +s/OCI_STM_ALTER/OCI_STMT_ALTER/g +s/OCI_STM_BEGIN/OCI_STMT_BEGIN/g +s/OCI_STM_DEC/OCI_STMT_DECLARE/g +s/OCI_TX_OLD/OCI_TRANS_OLD/g +s/OCI_TX_NEW/OCI_TRANS_NEW/g +s/OCI_TX_JOIN/OCI_TRANS_JOIN/g +s/OCI_TX_RESUME/OCI_TRANS_RESUME/g +s/OCI_TX_STARTMASK/OCI_TRANS_STARTMASK/g +s/OCI_TX_READONLY/OCI_TRANS_READONLY/g +s/OCI_TX_READWRITE/OCI_TRANS_READWRITE/g +s/OCI_TX_SERIALIZABLE/OCI_TRANS_SERIALIZABLE/g +s/OCI_TX_ISOLMASK/OCI_TRANS_ISOLMASK/g +s/OCI_TX_LOOSE/OCI_TRANS_LOOSE/g +s/OCI_TX_TIGHT/OCI_TRANS_TIGHT/g +s/OCI_TX_TYPEMASK/OCI_TRANS_TYPEMASK/g +s/OCI_TX_NOMIGRATE/OCI_TRANS_NOMIGRATE/g +s/OCI_TX_TWOPHASE/OCI_TRANS_TWOPHASE/g +s/OCI_DTYPE_PARM/OCI_DTYPE_PARAM/g +s/OCI_DTYPE_COR/OCI_DTYPE_COMPLEXOBJECTCOMP/g +s/OCI_DTYPE_RDD/OCI_DTYPE_ROWID/g +s/OCI_SB2_INDP/OCI_SB2_IND_PTR/g +s/OCI_IN_PARAMETER/OCI_PARAM_IN/g +s/OCI_OUT_PARAMETER/OCI_PARAM_OUT/g +s/OCISQLSTATESZ/OCI_SQLSTATE_SIZE/g +s/OCIMAXMSGSZ/OCI_ERROR_MAXMSG_SIZE/g diff --git a/ociaqarraydeq.c b/ociaqarraydeq.c new file mode 100644 index 0000000..f149130 --- /dev/null +++ b/ociaqarraydeq.c @@ -0,0 +1,237 @@ +/* Copyright (c) 2003, 2007, Oracle. All rights reserved. */ + +/* + + NAME + ociaqarraydeq.c - + + DESCRIPTION + + + EXPORT FUNCTION(S) + + + INTERNAL FUNCTION(S) + + + STATIC FUNCTION(S) + + + NOTES + + aqdemo09.sql (present in the $ORACLE_HOME/rdbms/demo directory) has to be + run as SYS to set up the required queue tables, queues, subscribers etc. + + aqdemo10.sql (present in the $ORACLE_HOME/rdbms/demo directory) has to then + be run to enqueue some messages into the queue, so that they can be + dequeued by this program.. + + ociaqarrayenq.c - enqueues a batch of 10 msgs into my_queue + ociaqarraydeq.c - dequeues a batch of 10 msgs from my_queue + + aqdemo12.sql (present in the $ORACLE_HOME/rdbms/demo directory) has to be + run as SYS to clean up all objects. + + MODIFIED (MM/DD/YY) + dprasann 04/05/07 - lowercase username/password + azhao 03/27/06 - fix 4993505 + rbhyrava 04/05/04 - linux porting + ekarichk 12/18/03 - bug3328852: missing prototypes + aahluwal 10/17/03 - aahluwal_create_arrenqdeq_demos + aahluwal 10/07/03 - Creation + +*/ + +#include +#include +#include +#include + +#ifndef OCI_ORACLE +#include +#endif + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ +struct message +{ + OCIString *data; +}; +typedef struct message message; + +struct null_message +{ + OCIInd null_adt; + OCIInd null_data; +}; +typedef struct null_message null_message; + +/*--------------------------------------------------------------------------- + STATIC FUNCTION DECLARATIONS + ---------------------------------------------------------------------------*/ +static void checkerr( OCIError *errhp, sword status); + +static void checkerr( OCIError *errhp, sword status) +{ + text errbuf[512]; + ub4 buflen; + sb4 errcode; + + if (status == OCI_SUCCESS) return; + + switch (status) + { + case OCI_SUCCESS_WITH_INFO: + printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + printf("Error - OCI_NO_DATA\n"); + break; + case OCI_ERROR: + OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); + printf("Error - %s\n", errbuf); + break; + case OCI_INVALID_HANDLE: + printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + printf("Error - OCI_CONTINUE\n"); + + break; + default: + printf("Error - %d\n", status); + break; + } +} + +int main(int argc, char *argv[]) +{ + OCIEnv *envhp; + OCIServer *srvhp; + OCIError *errhp; + OCISvcCtx *svchp; + OCISession *usrhp; + dvoid *tmp; + message *mesgp[100]; + int i, j, k; + null_message *nmesgp[100]; + ub4 priority = 0; + OCIAQDeqOptions *deqopt = (OCIAQDeqOptions *)0; + ub4 iters = 10; + OCIType *mesg_tdo = (OCIType *) 0; + ub4 batch_size = iters; + ub4 deq_size = batch_size; + + printf("session start\n"); + /* establish a session */ + + OCIInitialize((ub4) OCI_OBJECT, (dvoid *)0, (dvoid * (*)(dvoid *,size_t)) 0, + (dvoid * (*)(dvoid *,dvoid * ,size_t)) 0, (dvoid (*)(dvoid *,dvoid *)) 0 ); + + + OCIHandleAlloc( (dvoid *) NULL, (dvoid **) &envhp, (ub4) OCI_HTYPE_ENV, + 52, (dvoid **) &tmp); + + OCIEnvInit( &envhp, (ub4) OCI_DEFAULT, 21, (dvoid **) &tmp ); + + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, (ub4) OCI_HTYPE_ERROR, + 52, (dvoid **) &tmp); + + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, (ub4) OCI_HTYPE_SERVER, + 52, (dvoid **) &tmp); + + printf("server attach\n"); + OCIServerAttach( srvhp, errhp, (text *) 0, (sb4) 0, (ub4) OCI_DEFAULT); + + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, (ub4) OCI_HTYPE_SVCCTX, + 52, (dvoid **) &tmp); + + /* set attribute server context in the service context */ + OCIAttrSet( (dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, (dvoid *)srvhp, (ub4) 0, + (ub4) OCI_ATTR_SERVER, (OCIError *) errhp); + + /* allocate a user context handle */ + OCIHandleAlloc((dvoid *)envhp, (dvoid **)&usrhp, (ub4) OCI_HTYPE_SESSION, + (size_t) 0, (dvoid **) 0); + + OCIAttrSet((dvoid *)usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"aquser", (ub4)strlen("aquser"), + OCI_ATTR_USERNAME, errhp); + + OCIAttrSet((dvoid *)usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"aquser", (ub4)strlen("aquser"), + OCI_ATTR_PASSWORD, errhp); + + checkerr(errhp, OCISessionBegin (svchp, errhp, usrhp, OCI_CRED_RDBMS, + OCI_DEFAULT)); + + OCIAttrSet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)usrhp, (ub4)0, OCI_ATTR_SESSION, errhp); + + /* get descriptor for dequeue options */ + checkerr(errhp, OCIDescriptorAlloc(envhp, (dvoid **)&deqopt, + OCI_DTYPE_AQDEQ_OPTIONS, 0, + (dvoid **)0)); + + printf("deq options set\n"); + /* set dequeue options - for consumer name, wait and navigation */ + checkerr(errhp, OCIAttrSet(deqopt, OCI_DTYPE_AQDEQ_OPTIONS, + (dvoid *)"SUB1", + (ub4)strlen("SUB1"), + OCI_ATTR_CONSUMER_NAME, errhp)); + + for (k=0 ; k < iters ; k++) + { + mesgp[k] = (message *)0; + nmesgp[k] = (null_message *)0; + } + + printf("check message tdo\n"); + checkerr(errhp, OCITypeByName(envhp, errhp, svchp, + (CONST text *)"AQUSER", (ub4)strlen("AQUSER"), + (CONST text *)"MESSAGE", (ub4)strlen("MESSAGE"), (text *)0, 0, + OCI_DURATION_SESSION, OCI_TYPEGET_ALL, &mesg_tdo)); + + + k=0; + + while (k < iters) + { + deq_size = batch_size; + checkerr(errhp, OCIAQDeqArray(svchp, errhp, + (text *)"AQUSER.MY_QUEUE", + (OCIAQDeqOptions *)deqopt, + &deq_size, (OCIAQMsgProperties **)0, mesg_tdo, + (dvoid **)mesgp, + (dvoid **)nmesgp,(OCIRaw **)0, (void *)0, + (OCICallbackAQDeq)0, 0)); + k+=(int) batch_size; + } + printf("%i messages dequeued\n", k); + + for (j=0; jdata)); + } + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + printf("dequeue committed\n"); + + checkerr(errhp, OCISessionEnd ( svchp, errhp, usrhp, (ub4) OCI_DEFAULT)); + + checkerr(errhp, OCIServerDetach( srvhp, errhp, (ub4) OCI_DEFAULT)); + return 0; +} + + +/* end of file ociaqarraydeq.c */ + diff --git a/ociaqarrayenq.c b/ociaqarrayenq.c new file mode 100644 index 0000000..a902358 --- /dev/null +++ b/ociaqarrayenq.c @@ -0,0 +1,250 @@ +/* Copyright (c) 2003, 2007, Oracle. All rights reserved. */ + +/* + + NAME + ociaqarrayenq.c - + + DESCRIPTION + + + EXPORT FUNCTION(S) + + + INTERNAL FUNCTION(S) + + + STATIC FUNCTION(S) + + + NOTES + aqdemo09.sql (present in the $ORACLE_HOME/rdbms/demo directory) has to be + run after connecting as SYS to set up the required queue tables, queues, + subscribers etc. + + ociaqarrayenq.c - enqueues a batch of 10 msgs into my_queue + ociaqarraydeq.c - dequeues a batch of 10 msgs from my_queue + + aqdemo12.sql (present in the $ORACLE_HOME/rdbms/demo directory) has to be + run as SYS to clean up all objects. + + MODIFIED (MM/DD/YY) + dprasann 04/05/07 - lowercase username/password + dprasann 02/15/06 - bug 4993505 + rbhyrava 04/05/04 - linux porting + aahluwal 10/17/03 - aahluwal_create_arrenqdeq_demos + aahluwal 10/07/03 - Creation + +*/ + +#include +#include +#include +#include + +#ifdef WIN64 +#include +#endif + +#ifndef OCI_ORACLE +#include +#endif + +/*--------------------------------------------------------------------------- + PRIVATE TYPES AND CONSTANTS + ---------------------------------------------------------------------------*/ +struct message +{ + OCIString *data; +}; +typedef struct message message; + +struct null_message +{ + OCIInd null_adt; + OCIInd null_data; +}; +typedef struct null_message null_message; + +/*--------------------------------------------------------------------------- + STATIC FUNCTION DECLARATIONS + ---------------------------------------------------------------------------*/ + +static void checkerr( OCIError *errhp, sword status); + +static void checkerr( OCIError *errhp, sword status) +{ + text errbuf[512]; + ub4 buflen; + sb4 errcode; + + if (status == OCI_SUCCESS) return; + + switch (status) + { + case OCI_SUCCESS_WITH_INFO: + printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + printf("Error - OCI_NO_DATA\n"); + break; + case OCI_ERROR: + OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); + printf("Error - %s\n", errbuf); + break; + case OCI_INVALID_HANDLE: + printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + printf("Error - OCI_CONTINUE\n"); + break; + default: + printf("Error - %d\n", status); + break; + } +} + +int main(int argc, char *argv[]) +{ + OCIEnv *envhp; + OCIServer *srvhp; + OCIError *errhp; + OCISvcCtx *svchp; + OCISession *usrhp; + dvoid *tmp; + OCIType *mesg_tdo = (OCIType *) 0; + message mesg[100]; + message *mesgp[100]; + null_message nmesg[100]; + null_message *nmesgp[100]; + int i, j, k; + OCIInd ind[100]; + dvoid *indptr[100]; + ub4 priority; + OCIAQEnqOptions *enqopt = (OCIAQEnqOptions *)0; + OCIAQMsgProperties *msgprop= (OCIAQMsgProperties *)0; + ub4 wait = 1; + ub4 navigation = OCI_DEQ_NEXT_MSG; + ub4 iters = 10; + text *qname ; + text mesgdata[30]; + ub4 payload_size = 5; + text *payload = (text *)0; + ub4 batch_size = iters; + ub4 enq_size = 2; + char repeat_char = '0'; + + printf("session start\n"); + /* establish a session */ + + OCIInitialize((ub4) OCI_OBJECT, (dvoid *)0, (dvoid * (*)(dvoid *,size_t)) 0, + (dvoid * (*)(dvoid *,dvoid * ,size_t)) 0, (dvoid (*)(dvoid *,dvoid *)) 0 ); + + OCIHandleAlloc( (dvoid *) NULL, (dvoid **) &envhp, (ub4) OCI_HTYPE_ENV, + 52, (dvoid **) &tmp); + + OCIEnvInit( &envhp, (ub4) OCI_DEFAULT, 21, (dvoid **) &tmp ); + + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, (ub4) OCI_HTYPE_ERROR, + 52, (dvoid **) &tmp); + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, (ub4) OCI_HTYPE_SERVER, + 52, (dvoid **) &tmp); + + printf("server attach\n"); + OCIServerAttach( srvhp, errhp, (text *) 0, (sb4) 0, (ub4) OCI_DEFAULT); + + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, (ub4) OCI_HTYPE_SVCCTX, + 52, (dvoid **) &tmp); + + /* set attribute server context in the service context */ + OCIAttrSet( (dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, (dvoid *)srvhp, (ub4) 0, + (ub4) OCI_ATTR_SERVER, (OCIError *) errhp); + + /* allocate a user context handle */ + OCIHandleAlloc((dvoid *)envhp, (dvoid **)&usrhp, (ub4) OCI_HTYPE_SESSION, + (size_t) 0, (dvoid **) 0); + + OCIAttrSet((dvoid *)usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"aquser", (ub4)strlen("aquser"), + OCI_ATTR_USERNAME, errhp); + + OCIAttrSet((dvoid *)usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"aquser", (ub4)strlen("aquser"), + OCI_ATTR_PASSWORD, errhp); + + checkerr(errhp, OCISessionBegin (svchp, errhp, usrhp, OCI_CRED_RDBMS, + OCI_DEFAULT)); + + OCIAttrSet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)usrhp, (ub4)0, OCI_ATTR_SESSION, errhp); + + /* get descriptor for enqueue options */ + checkerr(errhp, OCIDescriptorAlloc(envhp, (dvoid **)&enqopt, + OCI_DTYPE_AQENQ_OPTIONS, 0, + (dvoid **)0)); + + printf("enq options set\n"); + /* set enqueue options - for consumer name, wait and navigation */ + + /* construct null terminated payload string */ + payload = (text *)malloc(payload_size+1); + + for (k=0 ; k < batch_size ; k++) + { + indptr[k] = &ind[k]; + mesgp[k] = &mesg[k]; + nmesgp[k] = &nmesg[k]; + nmesg[k].null_adt = nmesg[k].null_data = OCI_IND_NOTNULL; + mesg[k].data = (OCIString *)0; + + for (j=0 ; j < payload_size ; j++) + payload[j] = (text)repeat_char; + payload[payload_size] = (text)'\0'; + + OCIStringAssignText(envhp, errhp, (const oratext *)payload, + (ub4)strlen((const char *)payload), &(mesg[k].data)); + printf("Message #%i has payload: \"%s\"\n", k, payload); + repeat_char++; + } + + printf("check message tdo\n"); + checkerr(errhp, OCITypeByName(envhp, errhp, svchp, + (CONST text *)"AQUSER", (ub4)strlen("AQUSER"), + (CONST text *)"MESSAGE", (ub4)strlen("MESSAGE"), (text *)0, 0, + OCI_DURATION_SESSION, OCI_TYPEGET_ALL, &mesg_tdo)); + + k=0; + + while (k < iters) + { + enq_size = batch_size; + checkerr(errhp, OCIAQEnqArray(svchp, errhp, + (dvoid *)"AQUSER.MY_QUEUE", + (OCIAQEnqOptions *)0, &enq_size, + (OCIAQMsgProperties **)0, mesg_tdo, + (dvoid **)&mesgp, + (dvoid **)&nmesgp, (OCIRaw **)0, + (void *)0, (OCICallbackAQEnq) 0, 0)); + k+=(int)batch_size; + } + printf("%i messages enqueued\n", k); + + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + + printf("enqueue committed\n"); + + checkerr(errhp, OCISessionEnd ( svchp, errhp, usrhp, (ub4) OCI_DEFAULT)); + checkerr(errhp, OCIServerDetach( srvhp, errhp, (ub4) OCI_DEFAULT)); + + return 0; +} + +/* end of file ociaqarrayenq.c */ + diff --git a/ociaqdemo00.c b/ociaqdemo00.c new file mode 100644 index 0000000..dab80c0 --- /dev/null +++ b/ociaqdemo00.c @@ -0,0 +1,304 @@ +#ifdef RCSID +static char *RCSid = + "$Header: ociaqdemo00.c 27-mar-2006.22:31:21 azhao Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1998, 2006, Oracle. All rights reserved. +*/ + +/* + + NAME + ociaqdemo00.c - + + DESCRIPTION + ociaqdemo00.c enqueues 100 messages into the input_queue. (10 messages are + enqueued every 3 seconds to a maximum of 100 messages) + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + + + NOTES + + aqdemo00.sql (present in the $ORACLE_HOME/rdbms/demo directory) has + to be run first as user SYS to set up the required queue tables, + queues, subscribers etc. + + ociaqdemo00.c enqueues 100 messages into the input_queue. + ociaqdemo01.c dequeues messages by blocking on prop_queue for agent "prog3" + ociaqdemo02.c listens on input_queue and dequeues messages for agents + "prog1" and "prog2". + + + MODIFIED (MM/DD/YY) + azhao 03/27/06 - fix 4993505 + lzhao 04/16/04 - nt lrg + rbhyrava 04/05/04 - linux porting + ekarichk 12/18/03 - bug3328852: missing prototypes + rbhyrava 11/14/00 - rename newaqdemo00 + mrhodes 01/25/00 - make sleep call nt compatible + bnainani 09/23/99 - Bug 996772: change order of freeing handles + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + kmeiyyap 06/30/99 - free handles + kmeiyyap 06/29/99 - free descriptor + kmeiyyap 10/06/98 - oci enqueue + kmeiyyap 10/06/98 - Creation + +*/ +/* for WINDOWS compatibility of 'sleep' call */ +#if defined(WIN32COMMON) || defined(WIN32) || defined(_WIN32) +#include +#define sleep(x) Sleep(1000*(x)) +#endif + +#include + +#ifndef OCI_ORACLE +#include +#endif + +#include +#include +#include + +static void checkerr( OCIError *errhp, sword status); + +static void checkerr( OCIError *errhp, sword status) +{ + text errbuf[512]; + ub4 buflen; + sb4 errcode; + + if (status == OCI_SUCCESS) return; + + switch (status) + { + case OCI_SUCCESS_WITH_INFO: + printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + printf("Error - OCI_NO_DATA\n"); + break; + case OCI_ERROR: + OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); + printf("Error - %s\n", errbuf); + exit(1); + case OCI_INVALID_HANDLE: + printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + printf("Error - OCI_CONTINUE\n"); + break; + default: + printf("Error - %d\n", status); + break; + } +} + +void clean_up(OCIEnv *envhp, + OCISvcCtx *svchp, + OCIServer *srvhp, + OCIError *errhp, + OCISession *usrhp, + OCIAQMsgProperties *msgprop) +{ + /* free the message properties decriptor */ + checkerr(errhp, OCIDescriptorFree((dvoid *)msgprop, + OCI_DTYPE_AQMSG_PROPERTIES)); + + /* detach from the server */ + checkerr(errhp, OCISessionEnd(svchp, errhp, usrhp, OCI_DEFAULT)); + checkerr(errhp, OCIServerDetach(srvhp, errhp, (ub4)OCI_DEFAULT)); + + if (usrhp) + (void) OCIHandleFree((dvoid *) usrhp, (ub4) OCI_HTYPE_SESSION); + if (svchp) + (void) OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX); + if (srvhp) + (void) OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER); + if (errhp) + (void) OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR); + if (envhp) + (void) OCIHandleFree((dvoid *) envhp, (ub4) OCI_HTYPE_ENV); + +} + +struct message +{ + OCINumber id; + OCIString *city; + OCINumber priority; +}; +typedef struct message message; + +struct null_message +{ + OCIInd null_adt; + OCIInd null_id; + OCIInd null_city; + OCIInd null_priority; +}; +typedef struct null_message null_message; + + + +int main() +{ + OCIEnv *envhp; + OCIServer *srvhp; + OCIError *errhp; + OCISvcCtx *svchp; + OCISession *usrhp; + + dvoid *tmp; + OCIType *mesg_tdo = (OCIType *) 0; + OCIAQMsgProperties *msgprop = (OCIAQMsgProperties *)0; + message msg; + null_message nmsg; + message *mesg = &msg; + null_message *nmesg = &nmsg; + int i; + int priority; + + /* Standard OCI initialization */ + + OCIInitialize((ub4) OCI_OBJECT, (dvoid *)0, (dvoid * (*)(dvoid *,size_t)) 0, + (dvoid * (*)(dvoid *,dvoid * ,size_t)) 0, (dvoid (*)(dvoid *,dvoid *)) 0 ); + + OCIHandleAlloc( (dvoid *) NULL, (dvoid **) &envhp, + (ub4) OCI_HTYPE_ENV, 52, (dvoid **) &tmp); + + OCIEnvInit( &envhp, (ub4) OCI_DEFAULT, 21, (dvoid **) &tmp ); + + /* allocate a error report handle */ + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, 52, (dvoid **) &tmp); + + /* allocate a server context handle */ + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, 52, (dvoid **) &tmp); + + /* Create an assocaition between the server and the oci application */ + OCIServerAttach( srvhp, errhp, (text *) 0, (sb4) 0, (ub4) OCI_DEFAULT); + + /* allocate a service context handle */ + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, 52, (dvoid **) &tmp); + + /* set attribute server context in the service context */ + OCIAttrSet( (dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, (dvoid *)srvhp, + (ub4) 0 , (ub4) OCI_ATTR_SERVER, (OCIError *) errhp); + + /* allocate a user session handle */ + OCIHandleAlloc((dvoid *)envhp, (dvoid **)&usrhp, (ub4) OCI_HTYPE_SESSION, + (size_t) 0, (dvoid **) 0); + + OCIAttrSet( (dvoid *)usrhp, (ub4)OCI_HTYPE_SESSION, (dvoid *)"aquser", + (ub4)strlen("aquser"), OCI_ATTR_USERNAME, errhp); + + + OCIAttrSet( (dvoid *)usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"aquser", (ub4)strlen("aquser"), + OCI_ATTR_PASSWORD, errhp); + + checkerr(errhp, OCISessionBegin (svchp, errhp, usrhp, OCI_CRED_RDBMS, + OCI_DEFAULT)); + + OCIAttrSet( (dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)usrhp, (ub4)0, OCI_ATTR_SESSION, errhp); + + checkerr(errhp, OCITypeByName(envhp, errhp, svchp, + (CONST text *)"AQUSER", (ub4)strlen("AQUSER"), + (CONST text *)"MESSAGE", (ub4)strlen("MESSAGE"), (text *)0, 0, + OCI_DURATION_SESSION, OCI_TYPEGET_ALL, &mesg_tdo)); + + checkerr(errhp, OCIDescriptorAlloc(envhp, (dvoid **)&msgprop, + OCI_DTYPE_AQMSG_PROPERTIES, 0, (dvoid **)0)); + + printf("Enqueueing messages ...\n"); + /* enqueue 100 messages into input_queue */ + for (i = 1; i <= 100; i++) + { + mesg->city = (OCIString *)0; + priority = i%3 + 1; + + checkerr(errhp, OCINumberFromInt(errhp, &i, sizeof(i), 0, &mesg->id)); + checkerr(errhp, OCINumberFromInt(errhp, &priority, + sizeof(priority), 0, &mesg->priority)); + + /* Set the priority in message property */ + checkerr(errhp, OCIAttrSet(msgprop, OCI_DTYPE_AQMSG_PROPERTIES, + (dvoid *)&priority, sizeof(ub4), OCI_ATTR_PRIORITY, errhp)); + + if (i%3 == 0) + { + checkerr(errhp, OCIStringAssignText(envhp, errhp, + (CONST text *)"BELMONT", (ub4)strlen("BELMONT"), + &mesg->city)); + + nmesg->null_adt = nmesg->null_id = 0; + nmesg->null_city = nmesg->null_priority = 0; + } + else if (i%4 == 0) + { + checkerr(errhp, OCIStringAssignText(envhp, errhp, + (CONST text *)"REDWOOD SHORES", (ub4)strlen("REDWOOD SHORES"), + &mesg->city)); + + nmesg->null_adt = nmesg->null_id = 0; + nmesg->null_city = nmesg->null_priority = 0; + } + else if (i%2 == 0) + { + checkerr(errhp, OCIStringAssignText(envhp, errhp, + (CONST text *)"SUNNYVALE", (ub4)strlen("SUNNYVALE"), + &mesg->city)); + + nmesg->null_adt = nmesg->null_id = 0; + nmesg->null_city = nmesg->null_priority = 0; + } + else + { + checkerr(errhp, OCIStringAssignText(envhp, errhp, + (CONST text *)"BURLINGAME", (ub4)strlen("BURLINGAME"), + &mesg->city)); + + nmesg->null_adt = nmesg->null_id = 0; + nmesg->null_city = nmesg->null_priority = 0; + } + + + /* Enqueue the message */ + checkerr(errhp, OCIAQEnq(svchp, errhp, + (text *) "aquser.input_queue", (OCIAQEnqOptions *)0, + (OCIAQMsgProperties *)msgprop, + mesg_tdo, (dvoid **)&mesg, (dvoid **)&nmesg, (OCIRaw **)0, 0)); + + if ((i %10) == 0) + { + printf("Enqueueing messages %2d through %2d...\n", i-9, i); + sleep(3); + } + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + } + clean_up(envhp, svchp, srvhp, errhp, usrhp, msgprop); + printf("Done.\n"); + exit (0); +} + + +/* end of file ociaqdemo00.c */ + diff --git a/ociaqdemo01.c b/ociaqdemo01.c new file mode 100644 index 0000000..4da549f --- /dev/null +++ b/ociaqdemo01.c @@ -0,0 +1,344 @@ +#ifdef RCSID +static char *RCSid = + "$Header: ociaqdemo01.c 27-mar-2006.23:11:40 azhao Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1998, 2006, Oracle. All rights reserved. +*/ + +/* + + NAME + ociaqdemo01.c - + + DESCRIPTION + + This program dequeues messages by blocking on prop_queue for + approximately 2 minutes on behalf of agent "prog3". The contents + of the messages are inserted into prog3_processed_data table. + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + + + NOTES + + + MODIFIED (MM/DD/YY) + azhao 03/27/06 - fix 4993505 + rbhyrava 04/05/04 - linux porting + ekarichk 12/18/03 - bug3328852: missing prototypes + bnainani 09/23/99 - Bug 996772: change order of freeing handles + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + kmeiyyap 06/30/99 - free handles + kmeiyyap 06/29/99 - free descriptor + kmeiyyap 10/07/98 - added wait time for dequeue + kmeiyyap 10/06/98 - oci enqueue + kmeiyyap 10/06/98 - Creation + +*/ + +#ifndef OCI_ORACLE +#include +#endif + +#include +#include +#include +#include + +static void checkerr(OCIError *errhp, sword status); + +static void checkerr(OCIError *errhp, sword status) +{ + text errbuf[512]; + ub4 buflen; + sb4 errcode; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + printf("Error - OCI_NO_DATA\n"); + break; + case OCI_ERROR: + OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); + printf("Error - %s\n", errbuf); + exit(1); + case OCI_INVALID_HANDLE: + printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} + +struct message +{ + OCINumber id; + OCIString *city; + OCINumber priority; +}; +typedef struct message message; + +struct null_message +{ + OCIInd null_adt; + OCIInd null_id; + OCIInd null_city; + OCIInd null_priority; +}; +typedef struct null_message null_message; + +static void clean_up( OCIEnv *envhp, + OCISvcCtx *svchp, + OCIServer *srvhp, + OCIError *errhp, + OCIStmt *stmthp, + OCISession *usrhp, + OCIAQDeqOptions *deqopt, + message *mesg) ; + +static void clean_up( OCIEnv *envhp, + OCISvcCtx *svchp, + OCIServer *srvhp, + OCIError *errhp, + OCIStmt *stmthp, + OCISession *usrhp, + OCIAQDeqOptions *deqopt, + message *mesg) +{ + /* free dequeue options descriptor */ + checkerr(errhp, OCIDescriptorFree((dvoid *)deqopt, + OCI_DTYPE_AQDEQ_OPTIONS)); + /* free message buffer */ + if (mesg) + checkerr(errhp, OCIObjectFree(envhp, errhp, (dvoid *)mesg, + OCI_OBJECTFREE_FORCE)); + + /* detach from the server */ + checkerr(errhp, OCISessionEnd(svchp, errhp, usrhp, OCI_DEFAULT)); + checkerr(errhp, OCIServerDetach(srvhp, errhp, (ub4)OCI_DEFAULT)); + + if (usrhp) + (void) OCIHandleFree((dvoid *) usrhp, (ub4) OCI_HTYPE_SESSION); + if (svchp) + (void) OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX); + if (srvhp) + (void) OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER); + if (errhp) + (void) OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR); + if (stmthp) + (void) OCIHandleFree((dvoid *) stmthp, (ub4) OCI_HTYPE_STMT); + if (envhp) + (void) OCIHandleFree((dvoid *) envhp, (ub4) OCI_HTYPE_ENV); + + return; +} + +int main() +{ + + OCIEnv *envhp; + OCIServer *srvhp; + OCIError *errhp; + OCISvcCtx *svchp; + OCIStmt *stmthp; + OCISession *usrhp; + + dvoid *tmp; + OCIType *mesg_tdo = (OCIType *) 0; + OCIAQDeqOptions *deqopt = (OCIAQDeqOptions *)0; + message *mesg = (message *)0; + null_message *nmesg = (null_message *)0; + int i; + sb4 navigation = OCI_DEQ_FIRST_MSG; + ub4 wait = 120; + OCIBind *bndhp[3]; + sword status; + sword retval; + text *sqlstmt01; + int id; + int priority; + text *city; + text errbuf[512]; + sb4 errcode; + + + + /* Standard OCI Initialization */ + + OCIInitialize((ub4) OCI_OBJECT, (dvoid *)0, (dvoid * (*)(dvoid *,size_t)) 0, + (dvoid * (*)(dvoid *,dvoid * ,size_t)) 0, (dvoid (*)(dvoid *,dvoid *)) 0 ); + + OCIHandleAlloc( (dvoid *) NULL, (dvoid **) &envhp, + (ub4) OCI_HTYPE_ENV, 52, (dvoid **) &tmp); + + OCIEnvInit( &envhp, (ub4) OCI_DEFAULT, 21, (dvoid **) &tmp ); + + /* allocate a error report handle */ + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, + (ub4) OCI_HTYPE_ERROR, 52, (dvoid **) &tmp); + + /* allocate a server context handle */ + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, + (ub4) OCI_HTYPE_SERVER, 52, (dvoid **) &tmp); + + /* Create an assocaition between the server and the oci application */ + OCIServerAttach( srvhp, errhp, (text *) 0, (sb4) 0, (ub4) OCI_DEFAULT); + + /* allocate a service context handle */ + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, + (ub4) OCI_HTYPE_SVCCTX, 52, (dvoid **) &tmp); + + + /* set attribute server context in the service context */ + OCIAttrSet( (dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, (dvoid *)srvhp, + (ub4) 0, (ub4) OCI_ATTR_SERVER, (OCIError *) errhp); + + /* allocate a user session handle */ + OCIHandleAlloc((dvoid *)envhp, (dvoid **)&usrhp, (ub4) OCI_HTYPE_SESSION, + (size_t) 0, (dvoid **) 0); + + OCIAttrSet((dvoid *)usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"aquser", (ub4)strlen("aquser"), + OCI_ATTR_USERNAME, errhp); + + OCIAttrSet((dvoid *)usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)"aquser", (ub4)strlen("aquser"), + OCI_ATTR_PASSWORD, errhp); + + checkerr(errhp, OCISessionBegin (svchp, errhp, usrhp, OCI_CRED_RDBMS, + OCI_DEFAULT)); + + OCIAttrSet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)usrhp, (ub4)0, OCI_ATTR_SESSION, errhp); + + /* Allocate a statement handle */ + OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp, + (ub4) OCI_HTYPE_STMT, 52, (dvoid **) &tmp); + + checkerr(errhp, OCITypeByName(envhp, errhp, svchp, + (CONST text *)"AQUSER", (ub4)strlen("AQUSER"), + (CONST text *)"MESSAGE", (ub4)strlen("MESSAGE"), (text *)0, 0, + OCI_DURATION_SESSION, OCI_TYPEGET_ALL, &mesg_tdo)); + + + checkerr(errhp, OCIDescriptorAlloc(envhp, (dvoid **)&deqopt, + OCI_DTYPE_AQDEQ_OPTIONS, 0, (dvoid **)0)); + + /* set wait time of 120 seconds in dequeue option */ + checkerr(errhp, OCIAttrSet(deqopt, OCI_DTYPE_AQDEQ_OPTIONS, + (dvoid *) &wait, 0, OCI_ATTR_WAIT, errhp)); + + /* set navigation to OCI_DEQ_FIRST_MSG in dequeue option */ + checkerr(errhp, OCIAttrSet(deqopt, OCI_DTYPE_AQDEQ_OPTIONS, + (dvoid *)&navigation, sizeof(sb4), + OCI_ATTR_NAVIGATION, errhp)); + + + /* set consumer name to prog3 in dequeue option*/ + checkerr(errhp, OCIAttrSet(deqopt, OCI_DTYPE_AQDEQ_OPTIONS, + (dvoid *)"PROG3", (ub4)strlen("prog3"), + OCI_ATTR_CONSUMER_NAME, errhp)); + + printf("Dequeuing messages ...\n"); + + while(1) + { + printf("Waiting for messages ...\n"); + retval = OCIAQDeq(svchp, errhp, + (text *)"aquser.prop_queue", + deqopt, (OCIAQMsgProperties *)0, mesg_tdo, + (dvoid **)&mesg, + (dvoid **)&nmesg, + (OCIRaw **)0, 0); + if (retval == OCI_ERROR) + { + OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, + &errcode, errbuf, (ub4) sizeof(errbuf), + (ub4) OCI_HTYPE_ERROR); + + /* if no more messages to dequeue exit */ + if (errcode == 25228) + { + clean_up(envhp, svchp, srvhp, errhp, stmthp, usrhp, deqopt, + mesg); + printf("No more messages\n"); + exit(1); + } + else + { + printf("PROB HERE?\n"); + checkerr(errhp, retval); + } + } + else + { + checkerr(errhp, retval); + } + + + /* update the tables */ + checkerr(errhp, OCINumberToInt(errhp, &mesg->id, sizeof(id), + OCI_NUMBER_SIGNED, (dvoid *)&id)); + city = OCIStringPtr(envhp, mesg->city); + checkerr(errhp, OCINumberToInt(errhp, &mesg->priority, + sizeof(priority), OCI_NUMBER_SIGNED, (dvoid *)&priority)); + + printf("\tDequeueing message - id: %d\n", id); + printf("\tInserted message info into table PROG3_PROCESSED_DATA\n"); + sqlstmt01 = (text *)"INSERT INTO PROG3_PROCESSED_DATA \ + VALUES (:id, :city, :priority)"; + + /* prepare the statement */ + checkerr(errhp, OCIStmtPrepare(stmthp, errhp, sqlstmt01, + (ub4)strlen((char *)sqlstmt01), (ub4)OCI_NTV_SYNTAX, + (ub4)OCI_DEFAULT)); + + /* binding placeholders in the insert statement */ + + checkerr(errhp, OCIBindByName(stmthp, &bndhp[0], errhp, + (text *) ":id", -1, (dvoid *) &id, sizeof(id), + SQLT_INT, (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4) 0, (ub4 *)0, + OCI_DEFAULT)); + + checkerr(errhp, OCIBindByName(stmthp, &bndhp[1], errhp, + (text *)":city", -1, (dvoid *)city, (sb4)strlen((const signed char *)city)+1, + SQLT_STR, (dvoid *)0, (ub2 *)0, (ub2 *) 0, (ub4) 0, (ub4 *)0, + OCI_DEFAULT)); + + checkerr(errhp, OCIBindByName(stmthp, &bndhp[2], errhp, + (text *) ":priority", -1, (dvoid *) &priority, sizeof(priority), + SQLT_INT, (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)0, (ub4 *)0, + OCI_DEFAULT)); + + checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, (ub4) 0, + (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL , OCI_DEFAULT)); + + checkerr(errhp, OCITransCommit(svchp, errhp, (ub4) 0)); + } + exit(0); +} + +/* end of file ociaqdemo01.c */ + diff --git a/ociaqdemo02.c b/ociaqdemo02.c new file mode 100644 index 0000000..24df617 --- /dev/null +++ b/ociaqdemo02.c @@ -0,0 +1,550 @@ +#ifdef RCSID +static char *RCSid = + "$Header: ociaqdemo02.c 05-apr-2007.05:15:14 dprasann Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1998, 2007, Oracle. All rights reserved. +*/ + +/* + + NAME + ociaqdemo02.c - + + DESCRIPTION + + This program listens on input_queue for approxmately 2 minutes on behalf + of two agents, "prog1" and "prog2". When there are messages for the agents + in input_queue, the messages are dequeued and message contents are + inserted into appropriate tables (messages for "prog1" is inserted into + prog1_processed_data. messages for "prog2" is inserted into + prog2_processed_data.) + + PUBLIC FUNCTION(S) + + + PRIVATE FUNCTION(S) + + + RETURNS + + + NOTES + + + MODIFIED (MM/DD/YY) + dprasann 04/05/07 - lowercase username/password + azhao 03/27/06 - fix 4993505 + rbhyrava 04/05/04 - linux porting + ekarichk 12/18/03 - bug3328852: missing prototypes + lzhao 06/25/01 - comp warning fix + bnainani 09/23/99 - Bug 996772: change order of freeing handles + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + kmeiyyap 06/30/99 - free memory buffer + kmeiyyap 06/29/99 - remove time.h include file + kmeiyyap 11/14/98 - fix gettimeofday parameters + kmeiyyap 10/07/98 - handle timeout error + kmeiyyap 10/06/98 - listen on queue + kmeiyyap 10/06/98 - Creation + +*/ + +#ifndef OCI_ORACLE +#include +#endif + +#include +#include +#include +#include + +/* general OCI context */ +struct oci_ctx +{ + OCIEnv *envhp; /* Environment handle */ + OCISvcCtx *svchp; /* Service context handle */ + OCIServer *srvhp; /* Server handles */ + OCIError *errhp; /* Error handle */ + OCITrans *txnhp; /* Transaction handle */ + OCISession *usrhp; /* User handle */ + char server[40]; /* Server system id */ + OCIStmt *stmthp; /* Statement handle */ +}; +typedef struct oci_ctx oci_ctx; + + +/* dequeue context */ +struct deq_ctx +{ + OCIAQDeqOptions *dopt; + OCIAQMsgProperties *msgprop; + OCIType *mesg_tdo; +}; +typedef struct deq_ctx deq_ctx; + +struct message +{ + OCINumber id; + OCIString *city; + OCINumber priority; +}; +typedef struct message message; + +struct null_message +{ + OCIInd null_adt; + OCIInd null_id; + OCIInd null_city; + OCIInd null_priority; +}; +typedef struct null_message null_message; + +static void checkerr( + OCIError *errhp, + sword status) ; + +static void update_table( oci_ctx *ctx, + text *appname, + message *mesg); + +static void clean_up( oci_ctx ctx, + deq_ctx dctx, + message *mesg, + OCIAQAgent **agent_list); + +static void SetAgent( OCIAQAgent *agent, + text *appname, + text *queue, + OCIError *errhp); + +static text *GetAgent( OCIAQAgent *agent, + OCIError *errhp, + text *qname); + +static void init_ctx( oci_ctx *ctx, + text *username, + text *password ); + +static void setup_dequeue( + oci_ctx *octx, + deq_ctx *dqctx, + text *message_type); + +static void update_table( oci_ctx *ctx, + text *appname, + message *mesg); + +static void checkerr( OCIError *errhp, + sword status) +{ + text errbuf[512]; + ub4 buflen; + sb4 errcode; + + switch (status) + { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + printf("Error - OCI_SUCCESS_WITH_INFO\n"); + break; + case OCI_NEED_DATA: + printf("Error - OCI_NEED_DATA\n"); + break; + case OCI_NO_DATA: + printf("Error - OCI_NO_DATA\n"); + break; + case OCI_ERROR: + OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, + errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); + printf("Error - %s\n", errbuf); + exit(1); + case OCI_INVALID_HANDLE: + printf("Error - OCI_INVALID_HANDLE\n"); + break; + case OCI_STILL_EXECUTING: + printf("Error - OCI_STILL_EXECUTE\n"); + break; + case OCI_CONTINUE: + printf("Error - OCI_CONTINUE\n"); + break; + default: + break; + } +} + + +static void clean_up( oci_ctx ctx, + deq_ctx dctx, + message *mesg, + OCIAQAgent **agent_list) +{ + int i; + for(i = 0; i < 2; i++) + { + checkerr(ctx.errhp, OCIDescriptorFree(agent_list[i], + OCI_DTYPE_AQAGENT)); + } + + /* free dequeue options descriptor */ + checkerr(ctx.errhp, OCIDescriptorFree((dvoid *)dctx.dopt, + OCI_DTYPE_AQDEQ_OPTIONS)); + checkerr(ctx.errhp, OCIDescriptorFree((dvoid *)dctx.msgprop, + OCI_DTYPE_AQMSG_PROPERTIES)); + /* free message buffer */ + if (mesg) + checkerr(ctx.errhp, OCIObjectFree(ctx.envhp, ctx.errhp, + (dvoid *)mesg, OCI_OBJECTFREE_FORCE)); + + /* detach from the server */ + checkerr(ctx.errhp, OCISessionEnd(ctx.svchp, ctx.errhp, + ctx.usrhp, OCI_DEFAULT)); + checkerr(ctx.errhp, OCIServerDetach(ctx.srvhp, ctx.errhp, (ub4)OCI_DEFAULT)); + + /* free handles */ + if (ctx.usrhp) + (void) OCIHandleFree((dvoid *) ctx.usrhp, (ub4) OCI_HTYPE_SESSION); + if (ctx.svchp) + (void) OCIHandleFree((dvoid *) ctx.svchp, (ub4) OCI_HTYPE_SVCCTX); + if (ctx.srvhp) + (void) OCIHandleFree((dvoid *) ctx.srvhp, (ub4) OCI_HTYPE_SERVER); + if (ctx.errhp) + (void) OCIHandleFree((dvoid *) ctx.errhp, (ub4) OCI_HTYPE_ERROR); + if (ctx.stmthp) + (void) OCIHandleFree((dvoid *) ctx.stmthp, (ub4) OCI_HTYPE_STMT); + if (ctx.envhp) + (void) OCIHandleFree((dvoid *) ctx.envhp, (ub4) OCI_HTYPE_ENV); + return; +} + + +/* set agent into descriptor */ +static void SetAgent( OCIAQAgent *agent, + text *appname, + text *queue, + OCIError *errhp) +{ + /* Set agent name */ + checkerr(errhp, OCIAttrSet(agent, OCI_DTYPE_AQAGENT, + appname ? (dvoid *)appname : (dvoid *)"", + appname ? (ub4)strlen((const char *)appname) : 0, + OCI_ATTR_AGENT_NAME, errhp)); + + /* Set agent address */ + checkerr(errhp, OCIAttrSet(agent, OCI_DTYPE_AQAGENT, + queue ? (dvoid *)queue : (dvoid *)"", + queue ? (ub4)strlen((const char *)queue) : 0, + OCI_ATTR_AGENT_ADDRESS, errhp)); +} + + +/* get agent from descriptor */ +static text *GetAgent( OCIAQAgent *agent, + OCIError *errhp, + text *qname) +{ + text *appname; + text *queue; + ub4 appsz; + ub4 queuesz; + + if (!agent ) + { + printf("agent was NULL \n"); + return (text *)"agent was NULL"; + } + checkerr(errhp, OCIAttrGet(agent, OCI_DTYPE_AQAGENT, + (dvoid *)&appname, &appsz, OCI_ATTR_AGENT_NAME, errhp)); + checkerr(errhp, OCIAttrGet(agent, OCI_DTYPE_AQAGENT, + (dvoid *)&queue, &queuesz, OCI_ATTR_AGENT_ADDRESS, errhp)); + if (!appsz) + printf("agent name: NULL\n"); + + if (!queuesz) + printf("agent address: NULL\n"); + + memcpy((dvoid *)qname, (dvoid *)queue, (size_t)queuesz); + + qname[queuesz] = '\0'; + + return qname; +} + + +/* Initialize the OCI context */ + +static void init_ctx( oci_ctx *ctx, + text *username, + text *password ) +{ + dvoid *tmp; + + OCIHandleAlloc( (dvoid *) NULL, (dvoid **) &ctx->envhp, + (ub4) OCI_HTYPE_ENV, 52, (dvoid **) &tmp); + + OCIEnvInit( &ctx->envhp, (ub4) OCI_DEFAULT, 21, (dvoid **) &tmp ); + + /* allocate a error report handle */ + OCIHandleAlloc((dvoid *) ctx->envhp, (dvoid **) &ctx->errhp, + (ub4) OCI_HTYPE_ERROR, 52, (dvoid **) &tmp); + + /* allocate a server context handle */ + OCIHandleAlloc( (dvoid *) ctx->envhp, (dvoid **) &ctx->srvhp, + (ub4) OCI_HTYPE_SERVER, 52, (dvoid **) &tmp); + + /* Create an assocaition between the server and the oci application */ + OCIServerAttach(ctx->srvhp, ctx->errhp, (text *) 0, (sb4) 0, + (ub4) OCI_DEFAULT); + + /* allocate a service context handle */ + OCIHandleAlloc( (dvoid *) ctx->envhp, (dvoid **) &ctx->svchp, + (ub4) OCI_HTYPE_SVCCTX, 52, (dvoid **) &tmp); + + /* set attribute server context in the service context */ + OCIAttrSet( (dvoid *) ctx->svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *)ctx->srvhp, (ub4) 0, + (ub4) OCI_ATTR_SERVER, (OCIError *) ctx->errhp); + + /* allocate a user session handle */ + OCIHandleAlloc((dvoid *)ctx->envhp, (dvoid **)&ctx->usrhp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0); + + OCIAttrSet(ctx->usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)username, (ub4)strlen((const signed char *)username), + OCI_ATTR_USERNAME, ctx->errhp); + + + OCIAttrSet(ctx->usrhp, (ub4)OCI_HTYPE_SESSION, + (dvoid *)password, (ub4)strlen((const signed char *)password), + OCI_ATTR_PASSWORD, ctx->errhp); + + checkerr(ctx->errhp, OCISessionBegin(ctx->svchp, ctx->errhp, ctx->usrhp, + OCI_CRED_RDBMS, OCI_DEFAULT)); + + OCIAttrSet(ctx->svchp, (ub4)OCI_HTYPE_SVCCTX, + (dvoid *)ctx->usrhp, (ub4)0, OCI_ATTR_SESSION, ctx->errhp); + + /* Allocate a statement handle */ + OCIHandleAlloc( (dvoid *) ctx->envhp, (dvoid **) &ctx->stmthp, + (ub4) OCI_HTYPE_STMT, (size_t)0, (dvoid **) 0); + +} + + +/* set up the context for dequeue */ +static void setup_dequeue( + oci_ctx *octx, + deq_ctx *dqctx, + text *message_type) +{ + ub4 navigation = OCI_DEQ_FIRST_MSG; + OCIDescribe *dschp = (OCIDescribe *)0; + OCIParam *type_param = (OCIParam *)0; + + dqctx->dopt = (OCIAQDeqOptions *)0; + dqctx->msgprop = (OCIAQMsgProperties *)0; + dqctx->mesg_tdo = (OCIType *)0; + + /* message properties descriptor */ + checkerr(octx->errhp, + OCIDescriptorAlloc(octx->envhp, (dvoid **) &dqctx->msgprop, + OCI_DTYPE_AQMSG_PROPERTIES, 0, (dvoid **)0)); + + /* dequeue options descriptor */ + checkerr(octx->errhp, + OCIDescriptorAlloc(octx->envhp, (dvoid **) &dqctx->dopt, + OCI_DTYPE_AQDEQ_OPTIONS, 0, (dvoid **)0)); + + /* set navigation in dequeue options */ + checkerr(octx->errhp, OCIAttrSet(dqctx->dopt, OCI_DTYPE_AQDEQ_OPTIONS, + (dvoid *)&navigation, 0, + OCI_ATTR_NAVIGATION, octx->errhp)); + + + /* get TOID */ + checkerr(octx->errhp, OCIHandleAlloc((dvoid *) octx->envhp, + (dvoid **)&dschp, (ub4) OCI_HTYPE_DESCRIBE, (size_t) 0, (dvoid **) 0)); + + + checkerr(octx->errhp, OCIDescribeAny(octx->svchp, octx->errhp, + (dvoid *)message_type, (ub4)strlen((const signed char *)message_type), + OCI_OTYPE_NAME, 0, OCI_PTYPE_TYPE, dschp)); + + /* get the type descriptor */ + checkerr(octx->errhp, OCIAttrGet((dvoid *)dschp, + (ub4)OCI_HTYPE_DESCRIBE, (dvoid *)&type_param, + (ub4 *)0, (ub4)OCI_ATTR_PARAM, (OCIError *)octx->errhp)); + + + /* get the tdo of the type */ + checkerr(octx->errhp, OCIAttrGet((dvoid *)type_param, + (ub4)OCI_DTYPE_PARAM, (dvoid *)&dqctx->mesg_tdo, + (ub4 *)0, (ub4)OCI_ATTR_TDO, (OCIError *)octx->errhp)); +} + +static void update_table( oci_ctx *ctx, + text *appname, + message *mesg) +{ + + text *sqlstmt01; + OCIBind *bndhp[3]; + int id; + int priority; + text *city; + + if (strcmp((const signed char *)appname, "PROG1") == 0 ) + { + sqlstmt01 = (text *)"INSERT INTO PROG1_PROCESSED_DATA \ + VALUES (:id, :city, :priority)"; + } + else if (strcmp((const signed char *)appname, "PROG2") == 0) + { + sqlstmt01 = (text *)"INSERT INTO PROG2_PROCESSED_DATA \ + VALUES (:id, :city, :priority)"; + } + + checkerr(ctx->errhp, OCINumberToInt(ctx->errhp, &mesg->id, sizeof(id), + OCI_NUMBER_SIGNED, (dvoid *)&id)); + city = OCIStringPtr(ctx->envhp, mesg->city); + checkerr(ctx->errhp, OCINumberToInt(ctx->errhp, &mesg->priority, + sizeof(priority), OCI_NUMBER_SIGNED, (dvoid *)&priority)); + + printf("\tDequeueing message - id: %d for %s\n", id, appname); + if (strcmp((const signed char *)appname, "PROG1") == 0) + printf("\tInserting message info into table PROG1_PROCESSED_DATA\n"); + else if (strcmp((const signed char *)appname, "PROG2") == 0) + printf("\tInserting message info into table PROG2_PROCESSED_DATA\n"); + + /* prepare the statement */ + checkerr(ctx->errhp, OCIStmtPrepare(ctx->stmthp, ctx->errhp, sqlstmt01, + (ub4)strlen((char *)sqlstmt01), (ub4)OCI_NTV_SYNTAX, + (ub4)OCI_DEFAULT)); + + /* binding placeholders in the insert statement */ + + checkerr(ctx->errhp, OCIBindByName(ctx->stmthp, &bndhp[0], ctx->errhp, + (text *) ":id", -1, (dvoid *) &id, sizeof(id), SQLT_INT, + (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4) 0, (ub4 *)0, OCI_DEFAULT)); + + checkerr(ctx->errhp, OCIBindByName(ctx->stmthp, &bndhp[1], ctx->errhp, + (text *)":city",-1,(dvoid *)city, + (sb4)strlen((const signed char *)city)+1, SQLT_STR, + (dvoid *)0, (ub2 *)0, (ub2 *) 0, (ub4) 0, (ub4 *)0, OCI_DEFAULT)); + + checkerr(ctx->errhp, OCIBindByName(ctx->stmthp, &bndhp[2], ctx->errhp, + (text *)":priority", -1, (dvoid *) &priority, sizeof(priority), + SQLT_INT, (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)0, (ub4 *)0, + OCI_DEFAULT)); + + checkerr(ctx->errhp, OCIStmtExecute(ctx->svchp, ctx->stmthp, ctx->errhp, + (ub4)1 , (ub4) 0, (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL , + OCI_DEFAULT)); + +} + +int main() +{ + oci_ctx ctx; + deq_ctx dctx; + OCIAQAgent *agent_list[2]; + OCIAQAgent *agent = (OCIAQAgent *)0; + OCIRaw *msgID = (OCIRaw *)0; + text type_name[61] = "AQUSER.MESSAGE"; + OCIDescribe *dschp = (OCIDescribe *)0; + OCIParam *type_param = (OCIParam *)0; + OCIType *mesg_tdo = (OCIType *)0; + message *mesg = (message *)0; + null_message nmsg; + null_message *nmesg = &nmsg; + text qname[61]; + ub4 i; + sword retval; + text *appname; + ub4 appsz; + text errbuf[512]; + sb4 errcode; + + OCIInitialize((ub4) OCI_OBJECT, (dvoid *)0, (dvoid * (*)(dvoid *,size_t)) 0, + (dvoid * (*)(dvoid *,dvoid * ,size_t)) 0, (dvoid (*)(dvoid *,dvoid *)) 0 ); + + init_ctx(&ctx, (oratext *)"aquser",(oratext *) "aquser"); + + /* allocate agent handles */ + for (i = 0; i < 2; i++) + { + checkerr(ctx.errhp, OCIDescriptorAlloc(ctx.envhp, + (dvoid **)&agent_list[i], OCI_DTYPE_AQAGENT, 0, (dvoid **)0)); + } + + + SetAgent(agent_list[0], (oratext *)"prog1",(oratext *) "aquser.input_queue", ctx.errhp); + SetAgent(agent_list[1],(oratext *) "prog2", (oratext *)"aquser.input_queue", ctx.errhp); + + setup_dequeue(&ctx, &dctx, (oratext *)"AQUSER.MESSAGE"); + + printf("Listening and dequeuing messages ...\n"); + + while(1) + { + printf("Listening for messages for PROG1 and PROG2...\n"); + + retval = OCIAQListen(ctx.svchp, ctx.errhp, agent_list, 2, 120, &agent, + 0); + if (retval == OCI_ERROR) + { + OCIErrorGet ((dvoid *) ctx.errhp, (ub4) 1, (text *) NULL, + &errcode, errbuf, (ub4) sizeof(errbuf), + (ub4) OCI_HTYPE_ERROR); + + /* if listen call timed out, continue listen */ + if (errcode == 25254) + { + printf("No more messages\n"); + clean_up(ctx, dctx, mesg, agent_list); + exit(1); + } + else + checkerr(ctx.errhp, retval); + } + else + { + checkerr(ctx.errhp, retval); + } + + GetAgent(agent, ctx.errhp, qname); + + checkerr(ctx.errhp, OCIAttrGet(agent, OCI_DTYPE_AQAGENT, + (dvoid *)&appname, &appsz, OCI_ATTR_AGENT_NAME, ctx.errhp)); + + if (strcmp((const signed char *)appname, "PROG1") == 0) + { + /* set consumer name to prog1 */ + checkerr(ctx.errhp, OCIAttrSet(dctx.dopt, OCI_DTYPE_AQDEQ_OPTIONS, + (dvoid *)"PROG1", (ub4)strlen("PROG1"), + OCI_ATTR_CONSUMER_NAME, ctx.errhp)); + } + else if (strcmp((const signed char *)appname, "PROG2") == 0) + { + /* set consumer name to prog1 */ + checkerr(ctx.errhp, OCIAttrSet(dctx.dopt, OCI_DTYPE_AQDEQ_OPTIONS, + (dvoid *)"PROG2", (ub4)strlen("PROG2"), + OCI_ATTR_CONSUMER_NAME, ctx.errhp)); + } + + checkerr(ctx.errhp, OCIAQDeq(ctx.svchp, ctx.errhp, + (text *)qname, dctx.dopt, + dctx.msgprop, dctx.mesg_tdo, + (dvoid **)&mesg, (dvoid **)&nmesg, &msgID, 0)); + + update_table(&ctx, appname, mesg); + + checkerr(ctx.errhp, OCITransCommit(ctx.svchp, ctx.errhp, (ub4) 0)); + + } + exit(0); +} + + +/* end of file ociaqdemo02.c */ + diff --git a/ociucb.c b/ociucb.c new file mode 100644 index 0000000..249e9f8 --- /dev/null +++ b/ociucb.c @@ -0,0 +1,146 @@ +#ifdef RCSID +static char *RCSid = + "$Header: ociucb.c 14-jul-99.13:40:30 mjaeger Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1998, 1999, Oracle Corporation. All rights reserved. +*/ + +/* + + NAME + ociucb.c - OCI - User Call Back + + DESCRIPTION + Contains the defintion of ociucbInit and ociucbEnvCallback routines. + + The ociucbInit routine is called by OCI to initialize the shared library. + The ociucbEnvCallback routine is called by OCIEnvInit if ORA_OCI_UCBPKG + environment variable is set and OCIInitialize is not called with a mode of + OCI_ENV_NO_UCB. + + PUBLIC FUNCTION(S) + ociucbInit - OCI Shared Library Callback Main Function + ociucbEnvCallback - OCI ENVironment handle CALLBACK + + PRIVATE FUNCTION(S) + None yet. + + RETURNS + NA + + NOTES + + + MODIFIED (MM/DD/YY) + slari 09/10/99 - bg989981: remove envCallback from ociucbInit + slari 08/30/99 - provide ociucbInit + slari 08/23/99 - add OCIUcb in call to OCIEnvCallback + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + slari 04/12/98 - change message for OCIEnvCallback + slari 03/17/98 - add comments + slari 02/12/98 - user callback file to provide code for OCIEnvCallback + slari 02/12/98 - Creation + +*/ + + + +#include +#include +#include +#include + + + /* the forward declaration must be done so that + OCIShareLibInit can be passed a pointer to this function + */ + +sword ociucbEnvCallback(OCIEnv *env, ub4 mode, size_t xtramemsz, dvoid *usrmemp, + OCIUcb *ucbDesc); + + + +/*--------------------------------- ociucbInit ---------------------------------*/ + +/* + NAME: + ociucbInit - OCI Shared Library CallBack Main function + + PARAMETERS: + meta - The metacontext + libCtx - The context for this package + argfmt - The package argument format + argc - The number of arguments passed + argv - The arguments to the package + + DESCRIPTION: + This is called by OCI to load and initialize the shared library + (package). + + The OCI shared library initialization is done by passing all the + parameters passed to the the shared library initialization function to + the OCISharedLibInit function. User's environment callback function of + type OCIEnvCallbackType is also passed to the OCISharedLibInit call. + + + RETURNS: + the return code from OCISharedLibInit function. + + NOTES: +*/ + +sword ociucbInit(metaCtx, libCtx, argfmt, argc, argv) +dvoid * metaCtx; /* The metacontext */ +dvoid * libCtx; /* The context for this program or package if you + have previously been called. */ +ub4 argfmt; /* What am I supposed to do? */ +sword argc; /* argc if I am being called as a program */ +dvoid * argv[]; /* argv if I am being called as a program */ +{ + return (OCISharedLibInit(metaCtx, libCtx, argfmt, argc, argv, + ociucbEnvCallback)); +} + + +/*--------------------------------- ociucbEnvCallback -----------------------*/ + +/* + NAME: + ociucbEnvCallback - OCI ENVironment handle CALLBACK + + DESCRIPTION: + This function is called by the OCIEnvInit function at the end after it + has allocated and intialized the environment handle. + + PARAMETERS + env - The newly created environment handle + mode - The mode passed to the OCIEnvInit call + xtramemsz - The xtramemsz passed to the OCIEnvInit call + usrmemp - Pointer to additional memory allocated for user memory + requested + ucbDesc - OCIUcb descriptor + + RETURNS: + Success/Error Code + + NOTES: +*/ + + +sword ociucbEnvCallback(env, mode, xtramemsz, usrmemp, ucbDesc) +OCIEnv *env; +ub4 mode; +size_t xtramemsz; +dvoid *usrmemp; +OCIUcb *ucbDesc; +{ + printf("ociucbEnvCallback called.\n"); + + return OCI_CONTINUE; +} + + + +/* end of file ociucb.c */ + diff --git a/ociucb.mk b/ociucb.mk new file mode 100644 index 0000000..3e25488 --- /dev/null +++ b/ociucb.mk @@ -0,0 +1,32 @@ +# +# Makefile for building callback shared library +# +# To link user callback DLL: +# +# make -f ociucb.mk user_callback SHARED_LIBNAME=libname +# OBJS="user.o ..." +# e.g. make -f ociucb.mk user_callback SHARED_LIBNAME=ociucb.so.1.0 \ +# OBJS=ociucb.o +# +# +# +# +# NOTE: 1. ORACLE_HOME must be either: +# . set in the user's environment +# . passed in on the command line +# . defined in a modified version of this makefile +# +# 2. Look in the platform specific documentation for information +# about environment variables that need to be properly +# defined (e.g. LD_LIBRARY_PATH in Solaris). +# + +include $(ORACLE_HOME)/rdbms/lib/env_rdbms.mk + +.SUFFIXES: .o + +.c.o: + $(C2O) + +user_callback: $(OBJS) + $(BUILD_USERCALLBACK) diff --git a/ociucb32.mk b/ociucb32.mk new file mode 100644 index 0000000..e39f236 --- /dev/null +++ b/ociucb32.mk @@ -0,0 +1,32 @@ +# +# Makefile for building callback shared library +# +# To link user callback DLL: +# +# make -f ociucb32.mk user_callback SHARED_LIBNAME=libname +# OBJS="user.o ..." +# e.g. make -f ociucb32.mk user_callback SHARED_LIBNAME=ociucb.so.1.0 \ +# OBJS=ociucb.o +# +# +# +# +# NOTE: 1. ORACLE_HOME must be either: +# . set in the user's environment +# . passed in on the command line +# . defined in a modified version of this makefile +# +# 2. Look in the platform specific documentation for information +# about environment variables that need to be properly +# defined (e.g. LD_LIBRARY_PATH in Solaris). +# + +include $(ORACLE_HOME)/rdbms/lib/env_rdbms.mk + +.SUFFIXES: .o + +.c.o: + $(C2O32) + +user_callback: $(OBJS) + $(BUILD_USERCALLBACK32) diff --git a/olsdemo.sql b/olsdemo.sql new file mode 100644 index 0000000..505d915 --- /dev/null +++ b/olsdemo.sql @@ -0,0 +1,748 @@ +Rem +Rem $Header: olsdemo.sql 29-may-2007.01:55:55 srramara Exp $ +Rem +Rem olsdemo.sql +Rem +Rem Copyright (c) 2001, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem olsdemo.sql - Oracle Label Security demo +Rem +Rem DESCRIPTION +Rem Builds Oracle Label Security demonstration labels and tables +Rem +Rem NOTES +Rem Executing user must have DBA and LBAC_DBA roles +Rem Install with NUMERIC labels assumed +Rem First clean up previous install using olsdrp.sql +Rem +Rem MODIFIED (MM/DD/YY) +Rem srramara 05/29/07 - passwd case sensitivity changes +Rem vpesati 01/21/02 - modify label function +Rem vpesati 01/18/02 - change to varchar2, trim blank padding +Rem snamudur 10/17/01 - For adding orderby clause +Rem gmurphy 02/02/01 - Merged gmurphy_ols_2rdbms +Rem vpesati 01/18/01 - oracle label security demo +Rem vpesati 01/18/01 - Created +Rem + +spool olsdemo.log +rem ==================================================================== +rem Building Oracle Label Security demo +rem ==================================================================== + +rem ==================================================================== +rem Create admin users and demo owner +rem ==================================================================== + +CONNECT SYSTEM/manager; +CREATE USER "HR_ADMIN" IDENTIFIED BY "HR_ADMIN"; +GRANT CONNECT, RESOURCE, SELECT_CATALOG_ROLE TO HR_ADMIN; + +CREATE USER "DEFENSE_ADMIN" IDENTIFIED BY "DEFENSE_ADMIN"; +GRANT CONNECT, RESOURCE, SELECT_CATALOG_ROLE TO DEFENSE_ADMIN; + +CREATE USER "SA_DEMO" IDENTIFIED BY "SA_DEMO"; +GRANT CONNECT, RESOURCE, SELECT_CATALOG_ROLE TO SA_DEMO; + +rem ==================================================================== +rem Connect as LBACSYS to grant authorization to SA_DEMO +rem ==================================================================== + +CONNECT LBACSYS/lbacsys + +GRANT EXECUTE ON sa_components TO SA_DEMO WITH GRANT OPTION; +GRANT EXECUTE ON sa_user_admin TO SA_DEMO WITH GRANT OPTION; +GRANT EXECUTE ON sa_user_admin TO SA_DEMO WITH GRANT OPTION; +GRANT EXECUTE ON sa_label_admin TO SA_DEMO WITH GRANT OPTION; +GRANT EXECUTE ON sa_policy_admin TO SA_DEMO WITH GRANT OPTION; +GRANT EXECUTE ON sa_audit_admin TO SA_DEMO WITH GRANT OPTION; + +GRANT LBAC_DBA TO SA_DEMO; +GRANT EXECUTE ON sa_sysdba TO SA_DEMO; +GRANT EXECUTE ON to_lbac_data_label TO SA_DEMO; + +CONNECT SA_DEMO/SA_DEMO +rem ==================================================================== +rem Creating Employee Policy: 'human_resources' +rem ==================================================================== + +EXECUTE SA_SYSDBA.CREATE_POLICY('human_resources','hr_label'); +GRANT HUMAN_RESOURCES_DBA TO HR_ADMIN; + +GRANT EXECUTE ON sa_components TO HR_ADMIN; +GRANT EXECUTE ON sa_user_admin TO HR_ADMIN; +GRANT EXECUTE ON sa_user_admin TO HR_ADMIN; +GRANT EXECUTE ON sa_label_admin TO HR_ADMIN; +GRANT EXECUTE ON sa_policy_admin TO HR_ADMIN; +GRANT EXECUTE ON sa_audit_admin TO HR_ADMIN; + +rem ==================================================================== +rem Creating DEFENSE Policy: 'defense' +rem ==================================================================== +EXECUTE SA_SYSDBA.CREATE_POLICY('defense','defense_label'); +GRANT DEFENSE_DBA TO DEFENSE_ADMIN; + +GRANT EXECUTE ON sa_components TO DEFENSE_ADMIN; +GRANT EXECUTE ON sa_user_admin TO DEFENSE_ADMIN; +GRANT EXECUTE ON sa_user_admin TO DEFENSE_ADMIN; +GRANT EXECUTE ON sa_label_admin TO DEFENSE_ADMIN; +GRANT EXECUTE ON sa_policy_admin TO DEFENSE_ADMIN; +GRANT EXECUTE ON sa_audit_admin TO DEFENSE_ADMIN; + +rem ==================================================================== +rem Creating Demo Tables: Dept, Emp and URLTable +rem +rem The Department Table will be the standard Department table +rem with no Secure Access Policy Protections. +rem +rem The Emp Table will be Protected by Secure Access and +rem Labels with a Rules Based Policy. +rem +rem The URLTable Table will be Protected by Secure Access +rem and rely on explicit Labeling +rem +rem ==================================================================== +rem Creating Secure Access Definitions to Support Label Policies +rem ==================================================================== + +rem ==================================================================== +rem Creating Levels, Compartments and Groups for Emp table +rem ==================================================================== + +CONNECT HR_ADMIN/HR_ADMIN + +EXECUTE SA_COMPONENTS.CREATE_LEVEL('human_resources',50,'L3','Level 3'); +EXECUTE SA_COMPONENTS.CREATE_LEVEL('human_resources',30,'L2','Level 2'); +EXECUTE SA_COMPONENTS.CREATE_LEVEL('human_resources',10,'L1','Level 1'); + +EXECUTE SA_COMPONENTS.CREATE_COMPARTMENT('human_resources',100,'M','MANAGEMENT'); +EXECUTE SA_COMPONENTS.CREATE_COMPARTMENT('human_resources',110,'E','EMPLOYEE'); + +EXECUTE SA_COMPONENTS.CREATE_GROUP('human_resources',10,'D10','DEPARTMENT 10'); +EXECUTE SA_COMPONENTS.CREATE_GROUP('human_resources',20,'D20','DEPARTMENT 20'); +EXECUTE SA_COMPONENTS.CREATE_GROUP('human_resources',30,'D30','DEPARTMENT 30'); +EXECUTE SA_COMPONENTS.CREATE_GROUP('human_resources',40,'D40','DEPARTMENT 40'); + +EXECUTE SA_USER_ADMIN.SET_USER_PRIVS('human_resources','sa_demo','FULL'); +EXECUTE SA_USER_ADMIN.SET_USER_PRIVS('human_resources','hr_admin','FULL,PROFILE_ACCESS'); + + +rem ==================================================================== +rem Creating Dept Table +rem ==================================================================== + +CONNECT SA_DEMO/SA_DEMO + +CREATE TABLE SA_DEMO.DEPT ( + DEPTNO NUMBER(2) NOT NULL, + DNAME VARCHAR2(14), + LOC VARCHAR2(13), + CONSTRAINT DEPT_PRIMARY_KEY PRIMARY KEY (DEPTNO)); + +GRANT SELECT, INSERT, UPDATE, DELETE ON DEPT to PUBLIC; + +rem ==================================================================== +rem Populating Dept table +rem ==================================================================== + +INSERT INTO SA_DEMO.DEPT VALUES (10,'ACCOUNTING','NEW YORK'); +INSERT INTO SA_DEMO.DEPT VALUES (20,'RESEARCH','DALLAS'); +INSERT INTO SA_DEMO.DEPT VALUES (30,'SALES','CHICAGO'); +INSERT INTO SA_DEMO.DEPT VALUES (40,'OPERATIONS','BOSTON'); + +COMMIT; + +rem ==================================================================== +rem Creating Emp Table +rem ==================================================================== + +CREATE TABLE SA_DEMO.EMP ( + EMPNO NUMBER(4) NOT NULL, + ENAME VARCHAR2(10), + JOB VARCHAR2(9), + MGR NUMBER(4), + HIREDATE DATE, + SAL NUMBER(7,2), + COMM NUMBER(7,2), + DEPTNO NUMBER(2) NOT NULL, + CONSTRAINT EMP_PRIMARY_KEY PRIMARY KEY (EMPNO)); + +GRANT SELECT, INSERT, UPDATE, DELETE ON EMP TO PUBLIC; + +rem ==================================================================== +rem Creating Rules Based Label Policy for EMP Table +rem ==================================================================== + +CREATE OR REPLACE FUNCTION sa_demo.gen_emp_label + (Job varchar2, + Deptno number, + Total_sal number) + Return LBACSYS.LBAC_LABEL +as + i_label varchar2(80); +Begin + /* Determine Class Level */ + if total_sal > 2000 then + i_label := 'L3:'; + elsif total_sal >1000 then + i_label := 'L2:'; + else + i_label := 'L1:'; + end if; + + /* Determine Compartment */ + IF TRIM(' ' from UPPER(Job)) in ('MANAGER','PRESIDENT') then + i_label := i_label||'M:'; + else + i_label := i_label||'E:'; + end if; + /* Determine Groups */ + i_label := i_label||'D'||to_char(deptno); + return TO_LBAC_DATA_LABEL('human_resources',i_label); +End; +/ + +SHOW ERRORS + +rem ==================================================================== +rem Populating Emp Table +rem ==================================================================== + +INSERT INTO SA_DEMO.EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) + VALUES (7839,'KING','PRESIDENT',NULL,'17-NOV-81',5000,NULL,10); +INSERT INTO SA_DEMO.EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) + VALUES (7698,'BLAKE','MANAGER',7839,'1-MAY-81',2850,NULL,30); +INSERT INTO SA_DEMO.EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) + VALUES (7782,'CLARK','MANAGER',7839,'9-JUN-81',2450,NULL,10); +INSERT INTO SA_DEMO.EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) + VALUES (7566,'JONES','MANAGER',7839,'2-APR-81',2975,NULL,20); +INSERT INTO SA_DEMO.EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) + VALUES (7654,'MARTIN','SALESMAN',7698,'28-SEP-81',1250,1400,30); +INSERT INTO SA_DEMO.EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) + VALUES (7499,'ALLEN','SALESMAN',7698,'20-FEB-81',1600,300,30); +INSERT INTO SA_DEMO.EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) + VALUES (7844,'TURNER','SALESMAN',7698,'8-SEP-81',1500,0,30); +INSERT INTO SA_DEMO.EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) + VALUES (7900,'JAMES','CLERK',7698,'3-DEC-81',950,NULL,30); +INSERT INTO SA_DEMO.EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) + VALUES (7521,'WARD','SALESMAN',7698,'22-FEB-81',1250,500,30); +INSERT INTO SA_DEMO.EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) + VALUES (7902,'FORD','ANALYST',7566,'3-DEC-81',3000,NULL,20); +INSERT INTO SA_DEMO.EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) + VALUES (7369,'SMITH','CLERK',7902,'17-DEC-80',800,NULL,20); +INSERT INTO SA_DEMO.EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) + VALUES (7788,'SCOTT','ANALYST',7566,'09-DEC-82',3000,NULL,20); +INSERT INTO SA_DEMO.EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) + VALUES (7876,'ADAMS','CLERK',7788,'12-JAN-83',1100,NULL,20); +INSERT INTO SA_DEMO.EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) + VALUES (7934,'MILLER','CLERK',7782,'23-JAN-82',1300,NULL,10); +COMMIT; + +rem ==================================================================== +rem Apply HR policy to EMP to add HR_LABEL colulmn +rem Specify NO_CONTROL to disable policy enforcement +rem HR_ADMIN is authorized to apply policies, not SA_DEMO +rem ==================================================================== + +CONNECT HR_ADMIN/HR_ADMIN + +BEGIN + SA_POLICY_ADMIN.APPLY_TABLE_POLICY('human_resources', + 'sa_demo','emp','no_control'); +END; +/ + +rem ==================================================================== +rem Initialize hr_label to 'L1' for existing data. +rem Note: if label is NULL and policy is ENABLED, +rem then no access will be allowed. +rem ==================================================================== + +UPDATE SA_DEMO.EMP SET hr_label = CHAR_TO_LABEL('human_resources','L1'); +COMMIT; + +rem ==================================================================== +rem Remove policy and re-apply with LABEL FUNCTION specified +rem ==================================================================== + +BEGIN + SA_POLICY_ADMIN.REMOVE_TABLE_POLICY('human_resources','sa_demo','emp'); + SA_POLICY_ADMIN.APPLY_TABLE_POLICY ( + POLICY_NAME => 'human_resources', + SCHEMA_NAME => 'sa_demo', + TABLE_NAME => 'emp', + TABLE_OPTIONS => 'READ_CONTROL,WRITE_CONTROL,CHECK_CONTROL', + LABEL_FUNCTION => 'sa_demo.gen_emp_label(:new.job,:new.deptno,:new.sal)', + PREDICATE => NULL); +END; +/ + +rem ==================================================================== +rem Now force an Update to Relabel the data with rules in place. +rem ==================================================================== + +UPDATE SA_DEMO.EMP SET deptno=deptno; +COMMIT; + +col hr_label format a15 +SELECT empno, sal, deptno, label_to_char(hr_label) AS hr_label FROM SA_DEMO.EMP; + +rem ==================================================================== +rem Displaying generated labels +rem ==================================================================== + +COLUMN policy_name FORMAT A15 +COLUMN label FORMAT A15 +SELECT * FROM DBA_SA_LABELS WHERE policy_name='HUMAN_RESOURCES' + ORDER BY POLICY_NAME, LABEL_TAG; + +rem ==================================================================== +rem Now re-apply policy with READ, WRITE, and CHECK_CONTROL enforcement +rem ==================================================================== + +BEGIN + SA_POLICY_ADMIN.REMOVE_TABLE_POLICY('human_resources','sa_demo','emp'); + SA_POLICY_ADMIN.APPLY_TABLE_POLICY ( + POLICY_NAME => 'human_resources', + SCHEMA_NAME => 'sa_demo', + TABLE_NAME => 'emp', + TABLE_OPTIONS => 'READ_CONTROL,WRITE_CONTROL,CHECK_CONTROL', + LABEL_FUNCTION => 'sa_demo.gen_emp_label(:new.job,:new.deptno,:new.sal)', + PREDICATE => NULL); +END; +/ + +rem ==================================================================== +rem Create Trusted Function compute average salary +rem ==================================================================== + +CONNECT SA_DEMO/SA_DEMO + +CREATE OR REPLACE FUNCTION sa_demo.average_sal +RETURN NUMBER IS + a NUMBER; +BEGIN + SELECT avg(sal) INTO a FROM emp; + RETURN a; +END; +/ +GRANT EXECUTE ON average_sal TO PUBLIC; + + +CONNECT HR_ADMIN/HR_ADMIN +EXECUTE SA_USER_ADMIN.SET_PROG_PRIVS('Human_resources','sa_demo','average_sal','READ'); + +rem ==================================================================== +rem Creating Levels, Compartments and Groups for URLTABLE table +rem ==================================================================== + +CONNECT DEFENSE_ADMIN/DEFENSE_ADMIN + +EXECUTE SA_COMPONENTS.CREATE_LEVEL('defense',500,'TS','TOP SECRET'); +EXECUTE SA_COMPONENTS.CREATE_LEVEL('defense',300,'SE','SECRET'); +EXECUTE SA_COMPONENTS.CREATE_LEVEL('defense',100,'UN','UNCLASSIFIED'); + +EXECUTE SA_COMPONENTS.CREATE_COMPARTMENT('defense',100,'US_SPCL','United States Special Data'); +EXECUTE SA_COMPONENTS.CREATE_COMPARTMENT('defense',200,'US_ONLY','United States Only Data'); + +EXECUTE SA_COMPONENTS.CREATE_GROUP('defense',10,'COAL','Coalition'); +EXECUTE SA_COMPONENTS.CREATE_GROUP('defense',11,'US','United States','COAL'); +EXECUTE SA_COMPONENTS.CREATE_GROUP('defense',12,'CA','Canada','COAL'); +EXECUTE SA_COMPONENTS.CREATE_GROUP('defense',13,'UK','United Kingdom','COAL'); +EXECUTE SA_COMPONENTS.CREATE_GROUP('defense',14,'AU','Austrailia','COAL'); + +rem ==================================================================== +rem Creating Table URLTable +rem This example includes the DEFENSE_LABEL in the design +rem ==================================================================== + +CONNECT SA_DEMO/SA_DEMO +CREATE TABLE SA_DEMO.URLTABLE( + ITEM_NUMBER NUMBER, + FILE_NAME VARCHAR2(2000), + CRITERION VARCHAR2(500) Not Null, + TYPEDATA VARCHAR2(100) Not Null, + NOTATION VARCHAR2(2000) Not Null, + RLABEL NUMBER, + OWNER VARCHAR2(30), + LAST_UPDATED DATE, + DEFENSE_LABEL NUMBER(10) NOT NULL, + CONSTRAINT URL_PRIMARY_KEY PRIMARY KEY (ITEM_NUMBER)); + +GRANT SELECT, UPDATE, DELETE, INSERT ON URLTABLE TO PUBLIC; + +rem ==================================================================== +rem Add Explicit Security Labels to support the DEFENSE Policy +rem ==================================================================== + +CONNECT DEFENSE_ADMIN/DEFENSE_ADMIN +EXECUTE SA_LABEL_ADMIN.CREATE_LABEL('defense',1100,'UN:US_SPCL:'); +EXECUTE SA_LABEL_ADMIN.CREATE_LABEL('defense',2100,'SE:US_SPCL:'); +EXECUTE SA_LABEL_ADMIN.CREATE_LABEL('defense',2110,'SE:US_SPCL:US'); +EXECUTE SA_LABEL_ADMIN.CREATE_LABEL('defense',2120,'SE:US_SPCL:US,CA'); +EXECUTE SA_LABEL_ADMIN.CREATE_LABEL('defense',2130,'SE:US_SPCL:US,CA,UK,AU'); +EXECUTE SA_LABEL_ADMIN.CREATE_LABEL('defense',2140,'SE:US_SPCL:COAL'); +EXECUTE SA_LABEL_ADMIN.CREATE_LABEL('defense',3110,'TS:US_SPCL:US'); +EXECUTE SA_LABEL_ADMIN.CREATE_LABEL('defense',2200,'SE:US_ONLY:'); +EXECUTE SA_LABEL_ADMIN.CREATE_LABEL('defense',3200,'TS:US_ONLY:'); + +rem ==================================================================== +rem Displaying created labels +rem ==================================================================== + +COLUMN policy_name FORMAT A12 +COLUMN label FORMAT A25 +SELECT * FROM DBA_SA_LABELS WHERE policy_name='DEFENSE' + ORDER BY POLICY_NAME, LABEL_TAG; + +rem ==================================================================== +rem Inserted data into table with Explicit label included in statement. +rem ==================================================================== + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(5, +'http://security.us.oracle.com:80/demo_images/sbox.gif', +'UAV Imagery', +'SAR', +'Sensor Box US Demo36 Data', +char_to_label('defense','SE:US_SPCL:US')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(6, +'http://security.us.oracle.com:80/demo_images/image_nyc14.jpg', +'JSTARS Imagery', +'Imagery', +'Korona imagery minefield', +char_to_label('defense','SE:US_SPCL:US')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(7, +'http://security.us.oracle.com:80/demo_images/radar_sumara_russia.gif', +'JSTARS Imagery', +'SAR', +'Terrorist training camp', +char_to_label('defense','SE:US_SPCL:US,CA')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(8, +'http://security.us.oracle.com:80/demo_images/radar_rondonia_brazil.gif', +'UAV Imagery', +'SAR', +'UAV detects probable WMD storage sites', +char_to_label('defense','SE:US_SPCL:US,CA')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(9, +'http://security.us.oracle.com:80/demo_images/p0086.gif', +'Triggers', +'19.06.073', +'Mine Recovery and exploit, mine image', +char_to_label('defense','SE:US_SPCL:US,CA,UK,AU')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(10, +'http://security.us.oracle.com:80/demo_images/p0392.gif', +'Triggers', +'19.06.073', +'Mine Profile for Recovery', +char_to_label('defense','SE:US_SPCL:US,CA,UK,AU')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(11, +'http://security.us.oracle.com:80/demo_images/nyc.jpg', +'JSTARS Imagery', +'SAR', +'Potential Rendezvous sites', +char_to_label('defense','TS:US_SPCL:US')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(12, +'http://security.us.oracle.com:80/demo_images/track.gif', +'Triggers', +'19.01.276', +'Track Data DEFENSE Day3 from COP, Demo85', +char_to_label('defense','TS:US_SPCL:US')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(13, +'http://security.us.oracle.com:80/demo_images/sigs0014.gif', +'Triggers', +'19.01.112', +'Pull for OPS primary image GBS Misson planning', +char_to_label('defense','UN:US_SPCL:')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(14, +'http://security.us.oracle.com:80/demo_images/sigs0060.gif', +'Triggers', +'19.01.112', +'Misson planning, SIGS imagery from Sensor Box', +char_to_label('defense','UN:US_SPCL:')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(15, +'http://security.us.oracle.com:80/demo_images/sigs0081.gif', +'Triggers', +'22.01.112', +'SIGS Imagery for coalition planning, from Sensor Box', +char_to_label('defense','SE:US_SPCL:')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(16, +'http://security.us.oracle.com:80/demo_images/coalition_sar_day1.gif', +'UAV Imagery', +'SAR', +'Coalition UAV SAR for DEFENSE97 day3 US Demo85', +char_to_label('defense','SE:US_SPCL:')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(21, +'http://security.us.oracle.com:80/demo_images/photo_c130_hercules.jpg', +'Transport', +'Photo', +'C-130 Hercules kicking up a lot of dust', +char_to_label('defense','SE:US_SPCL:COAL')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(22, +'http://security.us.oracle.com:80/demo_images/photo_f14_tomcat.jpg', +'Fighter', +'Photo', +'In-flight view of an F-14 Tomcat escorting a pair of Russian bombers', +char_to_label('defense','SE:US_SPCL:COAL')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(17, +'http://security.us.oracle.com:80/demo_images/sigs0271.gif', +'UAV Imagery', +'SAR', +'Coalition DEFENSE97 day3 Kartuna Tank Platoon', +char_to_label('defense','SE:US_ONLY:')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(18, +'http://security.us.oracle.com:80/demo_images/sar.gif', +'UAV Imagery', +'SAR', +'US Demo85 SAR data', +char_to_label('defense','SE:US_ONLY:')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(19, +'http://security.us.oracle.com:80/demo_images/onslow.gif', +'Triggers', +'19.01.085', +'METOC Amphibious Opernations Area Forecast, Onslow Beach', +char_to_label('defense','TS:US_ONLY:')); + +INSERT INTO SA_DEMO.URLTABLE (ITEM_NUMBER, FILE_NAME, CRITERION,TYPEDATA,NOTATION, DEFENSE_LABEL) +Values +(20, +'http://security.us.oracle.com:80/demo_images/nyc.jpg', +'UAV Imagery', +'Photo', +'Kartuna field operations HQ', +char_to_label('defense','TS:US_ONLY:')); +rem ==================================================================== +rem Apply Secure Acess DEFENSE policy to URLTABLE +rem ==================================================================== + +Begin + SA_POLICY_ADMIN.APPLY_TABLE_POLICY ( + POLICY_NAME => 'defense', + SCHEMA_NAME => 'sa_demo', + TABLE_NAME => 'urltable', + TABLE_OPTIONS => 'ALL_CONTROL', + LABEL_FUNCTION => NULL, + PREDICATE => NULL); +End; +/ + +rem ==================================================================== +rem Create Secure Access User Accounts +rem ==================================================================== +CONNECT SYSTEM/manager; + +CREATE USER "PRES" IDENTIFIED BY "SA"; +CREATE USER "MD10" IDENTIFIED BY "SA"; +CREATE USER "ED10" IDENTIFIED BY "SA"; +CREATE USER "ED20" IDENTIFIED BY "SA"; + +CREATE USER "UN_SP" IDENTIFIED BY "SA"; +CREATE USER "SE_SP" IDENTIFIED BY "SA"; +CREATE USER "TS_SP" IDENTIFIED BY "SA"; +CREATE USER "SE_US" IDENTIFIED BY "SA"; +CREATE USER "SE_CA" IDENTIFIED BY "SA"; +CREATE USER "SE_UK" IDENTIFIED BY "SA"; +CREATE USER "SE_AU" IDENTIFIED BY "SA"; +CREATE USER "SE_CO" IDENTIFIED BY "SA"; +CREATE USER "TS_US" IDENTIFIED BY "SA"; +CREATE USER "SE_USO" IDENTIFIED BY "SA"; +CREATE USER "TS_USO" IDENTIFIED BY "SA"; + + +rem ==================================================================== +rem Set User Labels For HUMAN_RESOURCES Policy +rem ==================================================================== +CONNECT HR_ADMIN/HR_ADMIN + +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('human_resources','PRES','L3:M,E'); +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('human_resources','MD10','L3:M,E:D10'); +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('human_resources','ED10','L3:E:D10'); +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('human_resources','ED20','L3:E:D20'); + +EXECUTE SA_USER_ADMIN.ALTER_COMPARTMENTS('human_resources','PRES','E',sa_utl.read_only); + +rem ==================================================================== +rem Set User Labels For DEFENSE Policy +rem ==================================================================== +CONNECT DEFENSE_ADMIN/DEFENSE_ADMIN + +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('defense','UN_SP','UN:US_SPCL:'); +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('defense','SE_SP','SE:US_SPCL:'); +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('defense','TS_SP','TS:US_SPCL:'); + +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('defense','SE_US','SE:US_SPCL:US'); +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('defense','SE_CA','SE:US_SPCL:CA'); +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('defense','SE_UK','SE:US_SPCL:UK'); +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('defense','SE_AU','SE:US_SPCL:AU'); +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('defense','SE_CO','SE:US_SPCL:COAL'); +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('defense','TS_US','TS:US_SPCL:US'); + +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('defense','SE_USO','SE:US_ONLY:'); +EXECUTE SA_USER_ADMIN.SET_USER_LABELS('defense','TS_USO','TS:US_ONLY:'); + +EXECUTE SA_USER_ADMIN.ALTER_COMPARTMENTS('defense','SE_CA','US_SPCL',sa_utl.read_only); +EXECUTE SA_USER_ADMIN.ALTER_COMPARTMENTS('defense','SE_UK','US_SPCL',sa_utl.read_only); +EXECUTE SA_USER_ADMIN.ALTER_COMPARTMENTS('defense','SE_AU','US_SPCL',sa_utl.read_only); +EXECUTE SA_USER_ADMIN.ALTER_GROUPS('defense','SE_CA','CA',sa_utl.read_only); +EXECUTE SA_USER_ADMIN.ALTER_GROUPS('defense','SE_UK','UK',sa_utl.read_only); +EXECUTE SA_USER_ADMIN.ALTER_GROUPS('defense','SE_AU','AU',sa_utl.read_only); + +rem ==================================================================== +rem Set User PRIVILEGES For DEFENSE Policy +rem ==================================================================== + +EXECUTE SA_USER_ADMIN.SET_USER_PRIVS('defense','defense_admin','full,profile_access'); +EXECUTE SA_USER_ADMIN.SET_USER_PRIVS('defense','se_co','compaccess,writeacross'); +EXECUTE SA_USER_ADMIN.SET_USER_PRIVS('defense','Se_sp','compaccess,writeacross,writeup,writedown'); + + +rem ==================================================================== +rem Check data dictionary views and other functionality +rem ==================================================================== + +COLUMN NOTATION FORMAT A50 +COLUMN LABEL FORMAT A25 +COLUMN POLICY_NAME FORMAT A15 +COLUMN USER_NAME FORMAT A15 +COLUMN USER_PRIVILEGES FORMAT A30 + +SET PAGESIZE 80 +SET ECHO ON +rem ==================================================================== +rem Display Secure Access data dictionary views +rem ==================================================================== + +CONNECT HR_ADMIN/HR_ADMIN + +SELECT * FROM DBA_SA_POLICIES +ORDER BY policy_name; + +SELECT * FROM DBA_SA_LABELS +ORDER BY policy_name, label_tag; + +SELECT * FROM DBA_SA_USERS +ORDER BY policy_name, user_name; + +SELECT * FROM DBA_SA_PROG_PRIVS +ORDER BY policy_name, schema_name, program_name; + +SELECT * FROM DBA_SA_SCHEMA_POLICIEs +ORDER BY policy_name, schema_name; + +SELECT * FROM DBA_SA_TABLE_POLICIES +ORDER BY policy_name, schema_name, table_name; + +rem ==================================================================== +rem Use average_sal Trusted Function +rem HR_ADMIN has FULL privilege +rem ==================================================================== + +SELECT avg(sal) FROM SA_DEMO.EMP; + +rem ==================================================================== +rem ED10 has NO privileges +rem ==================================================================== + +EXECUTE SA_SESSION.SET_ACCESS_PROFILE('human_resources','ED10'); +SELECT avg(sal) FROM SA_DEMO.EMP; + +rem ==================================================================== +rem average_sal function has READ privilege +rem ==================================================================== +SET SERVEROUTPUT ON +DECLARE averg NUMBER; +BEGIN + averg := sa_demo.average_sal; + DBMS_OUTPUT.PUT_LINE('Average is ' || averg); +END; +/ +SET SERVEROUTPUT OFF + +rem ==================================================================== +rem Retrieve different results as different users +rem ==================================================================== + +CONNECT DEFENSE_ADMIN/DEFENSE_ADMIN + +SET PAGESIZE 0 + +rem ==================================================================== +rem DEFENSE_ADMIN as FULL and PROFILE_ACCESS privilege +rem ==================================================================== + +SELECT * FROM USER_SA_SESSION +WHERE policy_name='DEFENSE'; +SELECT label_to_char(defense_label) as label, notation FROM SA_DEMO.URLTABLE; + +EXECUTE SA_SESSION.SET_ACCESS_PROFILE('defense','ts_us'); +SELECT * FROM USER_SA_SESSION +WHERE policy_name='DEFENSE'; +SELECT label_to_char(defense_label) as label, notation FROM SA_DEMO.URLTABLE; + +EXECUTE SA_SESSION.SET_ACCESS_PROFILE('defense','se_ca'); +SELECT * FROM USER_SA_SESSION +WHERE policy_name='DEFENSE'; +SELECT label_to_char(defense_label) as label, notation FROM SA_DEMO.URLTABLE; + +EXECUTE SA_SESSION.SET_ACCESS_PROFILE('defense','un_sp'); +SELECT * FROM USER_SA_SESSION +WHERE policy_name='DEFENSE'; +SELECT label_to_char(defense_label) as label, notation FROM SA_DEMO.URLTABLE; + + +rem ==================================================================== +rem Demo Build ..... Complete +rem Review olsdemo.log file +rem ==================================================================== + +spool off diff --git a/olsdrp.sql b/olsdrp.sql new file mode 100644 index 0000000..b688ca6 --- /dev/null +++ b/olsdrp.sql @@ -0,0 +1,61 @@ +Rem +Rem $Header: olsdrp.sql 29-may-2007.01:56:44 srramara Exp $ +Rem +Rem olsdrp.sql +Rem +Rem Copyright (c) 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem olsdrp.sql - Drop Oracle Label Security demo +Rem +Rem DESCRIPTION +Rem Drops Oracle Label Security demonstration policies, tables and users +Rem +Rem NOTES +Rem Run this script before olsdemo to clean up previous demo installs +Rem +Rem MODIFIED (MM/DD/YY) +Rem srramara 05/29/07 - passwd case sensitivity changes +Rem gmurphy 02/02/01 - Merged gmurphy_ols_2rdbms +Rem vpesati 01/18/01 - oracle label security demo drop script +Rem vpesati 01/18/01 - Created +Rem + +rem ==================================================================== +rem Dropping HUMAN_RESOURCES and DEFENSE policies +rem ==================================================================== + +CONNECT SA_DEMO/SA_DEMO +EXECUTE SA_SYSDBA.DROP_POLICY('human_resources'); +EXECUTE SA_SYSDBA.DROP_POLICY('defense'); + +rem ==================================================================== +rem Dropping SA_DEMO, HR_ADMIN, DEFENSE_ADMIN and other users +rem ==================================================================== + +CONNECT SYSTEM/manager as sysdba; +DROP USER SA_DEMO CASCADE; +DROP USER HR_ADMIN CASCADE; +DROP USER DEFENSE_ADMIN CASCADE; + +DROP USER PRES CASCADE; +DROP USER MD10 CASCADE; +DROP USER ED10 CASCADE; +DROP USER ED20 CASCADE; + +DROP USER UN_SP CASCADE; +DROP USER SE_SP CASCADE; +DROP USER TS_SP CASCADE; +DROP USER SE_US CASCADE; +DROP USER SE_CA CASCADE; +DROP USER SE_UK CASCADE; +DROP USER SE_AU CASCADE; +DROP USER SE_CO CASCADE; +DROP USER TS_US CASCADE; +DROP USER SE_USO CASCADE; +DROP USER TS_USO CASCADE; + + +rem ==================================================================== +rem Drop Demo ..... Complete +rem ==================================================================== diff --git a/ori_f.sed b/ori_f.sed new file mode 100644 index 0000000..e13bffd --- /dev/null +++ b/ori_f.sed @@ -0,0 +1,35 @@ +# NAME +# ori_f.sed +# DESCRIPTION +# This sed script changes the ORI function and type names to long +# MODIFIED +# 10/03/96 - Peter Vasterd - Creation +# 10/16/96 - Peter Vasterd - Add changes from Calvin +s/oricfls/OCICacheFlush/g +s/origbgu/OCIDurationBegin/g +s/origedu/OCIDurationEnd/g +s/origpdr/OCIDurationGetParent/g +s/orioapn/OCIObjectArrayPin/g +s/oricfre/OCICacheFree/g +s/oriocpy/OCIObjectCopy/g +s/oricrfs/OCICacheRefresh/g +s/oricunp/OCICacheUnpin/g +s/oriogex/OCIObjectExists/g +s/oriogfl/OCIObjectFlushStatus/g +s/oriogns/OCIObjectGetInd/g +s/oriogor/OCIObjectGetObjectRef/g +s/oriogtb/OCIObjectPinTable/g +s/oriogtr/OCIObjectGetTypeRef/g +s/orionew/OCIObjectNew/g +s/oriofls/OCIObjectFlush/g +s/oriofre/OCIObjectFree/g +s/oriolck/OCIObjectLock/g +s/oriordl/OCIObjectMarkDeleteByRef/g +s/oriopin/OCIObjectPin/g +s/oriopdl/OCIObjectMarkDelete/g +s/oriorfs/OCIObjectRefresh/g +s/oriounp/OCIObjectUnpin/g +s/orioupd/OCIObjectMarkUpdate/g +s/orioupz/OCIObjectPinCountReset/g +s/oridset/OCIObjectSetAttr/g +s/oridget/OCIObjectGetAttr/g diff --git a/orl_f.sed b/orl_f.sed new file mode 100644 index 0000000..d3192cc --- /dev/null +++ b/orl_f.sed @@ -0,0 +1,128 @@ +# NAME +# orl_f.sed +# DESCRIPTION +# This sed script changes the ORL function and type +# MODIFIED +# 10/03/96 - Peter Vasterd - Creation +# 10/10/96 - Peter Vasterd - Merge Calvins' stuff +s/gye_orldat/OCIDateYYYY/g +s/mon_orldat/OCIDateMM/g +s/day_orldat/OCIDateDD/g +s/time_orldat/OCIDateTime/g +s/orldtmhh/OCITimeHH/g +s/orldtmmm/OCITimeMI/g +s/orldtmss/OCITimeSS/g +s/orldgye/OCIDateYYYY/g +s/orldmon/OCIDateMM/g +s/orlday/OCIDateDD/g +s/orldtime/OCIDateTime/g +s/orlbl/OCILobLocator/g +s/orlblen/OCILobLength/g +s/orlbmo/OCILobMode/g +s/orlboff/OCILobOffset/g +s/orlcapp/OCICollAppend/g +s/orlcase/OCICollAssignElem/g +s/orlcasg/OCICollAssign/g +s/orlccit/OCIIterCreate/g +s/orlcdit/OCIIterDelete/g +s/orlcget/OCICollGetElem/g +s/orlcicur/OCIIterGetCurrent/g +s/orlciit/OCIIterInit/g +s/orlcinxt/OCIIterNext/g +s/orlciprv/OCIIterPrev/g +s/orlcitr/OCIIter/g +s/orlcmax/OCICollMax/g +s/orlcol/OCIColl/g +s/orlcsiz/OCICollSize/g +s/orlctrm/OCICollTrim/g +s/orld2s/OCIDateToText/g +s/orldadd/OCIDateAddDays/g +s/orldadm/OCIDateAddMonths/g +s/orldat/OCIDate/g +s/orldtm/OCITime/g +s/orldbtw/OCIDateDaysBetween/g +s/orldchk/OCIDateCheck/g +s/orldcmp/OCIDateCompare/g +s/orldlst/OCIDateLastDay/g +s/orldndy/OCIDateNextDay/g +s/orlds2d/OCIDateFromText/g +s/orldsys/OCIDateSysDate/g +s/orldz2z/OCIDateZoneToZone/g +s/orllasg/OCILobAssign/g +s/orllequ/OCILobIsEqual/g +s/orllgcid/OCILobCharSet/g +s/orllgnm/OCILobFileGetName/g +s/orllgsz/OCILobLocatorSize/g +s/orllnul/OCILobIsNull/g +s/orllsnm/OCILobFileSetName/g +s/orln2i/OCINumberToInt/g +s/orln2r/OCINumberToReal/g +s/orln2s/OCINumberToText/g +s/orlnabs/OCINumberAbs/g +s/orlnacos/OCINumberArcCos/g +s/orlnadd/OCINumberAdd/g +s/orlnasg/OCINumberAssign/g +s/orlnasin/OCINumberArcSin/g +s/orlnatan/OCINumberArcTan/g +s/orlnatn2/OCINumberTanToArc/g +s/orlnbex/OCINumberExp/g +s/orlncel/OCINumberCeil/g +s/orlncmp/OCINumberCompare/g +s/orlncos/OCINumberCos/g +s/orlncsh/OCINumberHypCos/g +s/orlndiv/OCINumberDiv/g +s/orlnexp/OCINumberPower/g +s/orlnflr/OCINumberFloor/g +s/orlni2n/OCINumberFromInt/g +s/orlnini/OCINumberInit/g +s/orlnln/OCINumberLn/g +s/orlnlog/OCINumberLog/g +s/orlnmod/OCINumberMod/g +s/orlnmul/OCINumberMul/g +s/orlnneg/OCINumberNeg/g +s/orlnpwr/OCINumberIntPower/g +s/orlnr2n/OCINumberFromReal/g +s/orlnrou/OCINumberRound/g +s/orlns2n/OCINumberFromText/g +s/orlnsgn/OCINumberSign/g +s/orlnsin/OCINumberSin/g +s/orlnsnh/OCINumberHypSin/g +s/orlnsqr/OCINumberSqr/g +s/orlnsub/OCINumberSub/g +s/orlntan/OCINumberTan/g +s/orlntnh/OCINumberHypTan/g +s/orlntru/OCINumberTruncate/g +s/orlnum/OCINumber/g +s/orlnzer/OCINumberZero/g +s/orlr2h/OCIRefToHex/g +s/orlrasg/OCIRefAssign/g +s/orlraw/OCIRaw/g +s/orlrclr/OCIRefClear/g +s/orlrequ/OCIRefIsEqual/g +s/orlrh2r/OCIRefFromHex/g +s/orlrhsz/OCIRefHexSize/g +s/orlrnul/OCIRefIsNull/g +s/orltbl/OCITable/g +s/orltdel/OCITableDelete/g +s/orltexi/OCITableExists/g +s/orltfst/OCITableFirst/g +s/orltlst/OCITableLast/g +s/orltnxt/OCITableNext/g +s/orltprv/OCITablePrev/g +s/orltsiz/OCITableSize/g +s/orlvary/OCIArray/g +s/orlvass/OCIStringAssign/g +s/orlvasz/OCIStringAllocSize/g +s/orlvats/OCIStringAssignText/g +s/orlvgsp/OCIStringPtr/g +s/orlvgsz/OCIStringSize/g +s/orlvrsz/OCIStringResize/g +s/orlvstr/OCIString/g +s/orlwabr/OCIRawAssignBytes/g +s/orlwarr/OCIRawAssignRaw/g +s/orlwasz/OCIRawAllocSize/g +s/orlwgrp/OCIRawPtr/g +s/orlwgsz/OCIRawSize/g +s/orlwrsz/OCIRawResize/g +s/orlnpart/OCINumberPart/g +s/orldgye/OCIDateYYYY/g diff --git a/orl_m.sed b/orl_m.sed new file mode 100644 index 0000000..0d50202 --- /dev/null +++ b/orl_m.sed @@ -0,0 +1,28 @@ +# NAME +# orl_m.sed +# DESCRIPTION +# This sed script changes the ORLmacro names to long names +# MODIFIED +# 10/03/96 - Peter Vasterd - Creation +# 10/10/96 - Peter Vasterd - Merge Calvins stuff +# 11/09/96 - Peter Vasterd - Fix Order +s/ORLBMORO/OCI_LOBMODE_READONLY/g +s/ORLBMORW/OCI_LOBMODE_READWRITE/g +s/ORL_NUMSIZ/OCI_NUMBER_SIZE/g +s/ORLTUB/OCI_NUMBER_UNSIGNED/g +s/ORLTSB/OCI_NUMBER_SIGNED/g +s/ORLD_BDAL/OCI_DATE_DAY_BELOW_VALID/g +s/ORLD_BDA/OCI_DATE_INVALID_DAY/g +s/ORLD_BMOL/OCI_DATE_MONTH_BELOW_VALID/g +s/ORLD_BMO/OCI_DATE_INVALID_MONTH/g +s/ORLD_BYRL/OCI_DATE_YEAR_BELOW_VALID/g +s/ORLD_BYR/OCI_DATE_INVALID_YEAR/g +s/ORLD_BHRL/OCI_DATE_HOUR_BELOW_VALID/g +s/ORLD_BHR/OCI_DATE_INVALID_HOUR/g +s/ORLD_BMNL/OCI_DATE_MINUTE_BELOW_VALID/g +s/ORLD_BMN/OCI_DATE_INVALID_MINUTE/g +s/ORLD_BSCL/OCI_DATE_SECOND_BELOW_VALID/g +s/ORLD_BSC/OCI_DATE_INVALID_SECOND/g +s/ORLD_MSD/OCI_DATE_DAY_MISSING_FROM_1582/g +s/ORLD_YR0/OCI_DATE_YEAR_ZERO/g +s/ORLD_BDT/OCI_DATE_INVALID_FORMAT/g diff --git a/oro_f.sed b/oro_f.sed new file mode 100644 index 0000000..04701af --- /dev/null +++ b/oro_f.sed @@ -0,0 +1,19 @@ +# NAME +# oro_f.sed +# DESCRIPTION +# This sed script changes the ORO function and type to long names. +# MODIFIED +# 10/03/96 - Peter Vasterd - Creation +# 10/10/96 - Peter Vasterd - Merge Calvins' stuff +s/oroind/OCIInd/g +s/oroodt/OCIDuration/g +s/oroolm/OCILockOpt/g +s/oroomo/OCIMarkOpt/g +s/oroopo/OCIPinOpt/g +s/ororef/OCIRef/g +s/orooro/OCICoherency/g +s/orotc/OCITypeCode/g +s/orotec/OCITypeEncap/g +s/orotmf/OCITypeMethodFlag/g +s/orotpm/OCITypeParamMode/g +s/orotgo/OCITypeGetOpt/g diff --git a/oro_m.sed b/oro_m.sed new file mode 100644 index 0000000..8f14715 --- /dev/null +++ b/oro_m.sed @@ -0,0 +1,136 @@ +# NAME +# oro_m.sed +# DESCRIPTION +# This sed script changes the ORO macro names to long # names. +# MODIFIED +# 10/03/96 - Peter Vasterd - Creation +# 10/10/96 - Peter Vasterd - Merge Calvin's stuff +s/OROINDBNUL/OCI_IND_BADNULL/g +s/OROINDNNBL/OCI_IND_NOTNULLABLE/g +s/OROINDNNUL/OCI_IND_NOTNULL/g +s/OROINDNULL/OCI_IND_NULL/g +s/OROODTBEG/OCI_DURATION_BEGIN/g +s/OROODTCAL/OCI_DURATION_CALL/g +s/OROODTDFL/OCI_DURATION_DEFAULT/g +s/OROODTNUL/OCI_DURATION_NULL/g +s/OROODTPRE/OCI_DURATION_LAST/g +s/OROODTSES/OCI_DURATION_SESSION/g +s/OROODTSPC/OCI_DURATION_NEXT/g +s/OROODTTRA/OCI_DURATION_TRANS/g +s/OROOLMNUL/OCI_LOCK_NONE/g +s/OROOLMX/OCI_LOCK_X/g +s/OROOMODFL/OCI_MARK_DEFAULT/g +s/OROOMONON/OCI_MARK_NONE/g +s/OROOMOUPD/OCI_MARK_UPDATE/g +s/OROOPODFL/OCI_PIN_DEFAULT/g +s/OROOPOANY/OCI_PIN_ANY/g +s/OROOPOLST/OCI_PIN_LATEST/g +s/OROOROAWY/OCI_COHERENCY_ALWAYS/g +s/OROORONON/OCI_COHERENCY_NONE/g +s/OROORONUL/OCI_COHERENCY_NULL/g +s/OROTCAAT/OCI_TYPECODE_UNNAMEDADT/g +s/OROTCBFL/OCI_TYPECODE_BFILE/g +s/OROTCBLB/OCI_TYPECODE_BLOB/g +s/OROTCBYT/OCI_TYPECODE_SIGNED8/g +s/OROTCCFL/OCI_TYPECODE_CFILE/g +s/OROTCCLB/OCI_TYPECODE_CLOB/g +s/OROTCDAT/OCI_TYPECODE_DATE/g +s/OROTCDEC/OCI_TYPECODE_DECIMAL/g +s/OROTCDOM/OCI_TYPECODE_NAMEDCOLLECTION/g +s/OROTCDOU/OCI_TYPECODE_DOUBLE/g +s/OROTCFLO/OCI_TYPECODE_FLOAT/g +s/OROTCFSI/OCI_TYPECODE_CHAR/g +s/OROTCINT/OCI_TYPECODE_INTEGER/g +s/OROTCLAST/OCI_TYPECODE_LAST/g +s/OROTCLEX/OCI_TYPECODE_FIRSTCOMPLEX/g +s/OROTCLLAST/OCI_TYPECODE_LASTCOMPLEX/g +s/OROTCLON/OCI_TYPECODE_SIGNED32/g +s/OROTCMLS/OCI_TYPECODE_MLSLABEL/g +s/OROTCMST/OCI_TYPECODE_TABLE/g +s/OROTCNAT/OCI_TYPECODE_ADT/g +s/OROTCNUM/OCI_TYPECODE_NUMBER/g +s/OROTCOCT/OCI_TYPECODE_OCTET/g +s/OROTCPLAST/OCI_TYPECODE_LASTSCALAR/g +s/OROTCPRE/OCI_TYPECODE_FIRSTSCALAR/g +s/OROTCPTR/OCI_TYPECODE_PTR/g +s/OROTCRAW/OCI_TYPECODE_RAW/g +s/OROTCREA/OCI_TYPECODE_REAL/g +s/OROTCREF/OCI_TYPECODE_REF/g +s/OROTCSET/OCI_TYPECODE_SET/g +s/OROTCSHO/OCI_TYPECODE_SIGNED16/g +s/OROTCSML/OCI_TYPECODE_SMALLINT/g +s/OROTCUBY/OCI_TYPECODE_UNSIGNED8/g +s/OROTCULO/OCI_TYPECODE_UNSIGNED32/g +s/OROTCUSH/OCI_TYPECODE_UNSIGNED16/g +s/OROTCFAR/OCI_TYPECODE_FARRAY/g +s/OROTCVAR/OCI_TYPECODE_VARRAY/g +s/OROTCVSI/OCI_TYPECODE_VARCHAR2/g +s/OROTCVSO/OCI_TYPECODE_VARCHAR/g +s/OROTCS00/OCI_TYPECODE_SQL00/g +s/OROTCS01/OCI_TYPECODE_SQL01/g +s/OROTCS02/OCI_TYPECODE_SQL02/g +s/OROTCS03/OCI_TYPECODE_SQL03/g +s/OROTCP00/OCI_TYPECODE_PLSQL00/g +s/OROTCP01/OCI_TYPECODE_PLSQL01/g +s/OROTCP02/OCI_TYPECODE_PLSQL02/g +s/OROTCP03/OCI_TYPECODE_PLSQL03/g +s/OROTCP04/OCI_TYPECODE_PLSQL04/g +s/OROTCP05/OCI_TYPECODE_PLSQL05/g +s/OROTCP06/OCI_TYPECODE_PLSQL06/g +s/OROTCP07/OCI_TYPECODE_PLSQL07/g +s/OROTCP08/OCI_TYPECODE_PLSQL08/g +s/OROTCP09/OCI_TYPECODE_PLSQL09/g +s/OROTCP10/OCI_TYPECODE_PLSQL10/g +s/OROTDVAR/OCI_VARRAY_MAXSIZE/g +s/OROTDVST/OCI_STRING_MAXLEN/g +s/OROTECPUB/OCI_TYPEENCAP_PUBLIC/g +s/OROTECPVT/OCI_TYPEENCAP_PRIVATE/g +s/OROTMFCON/OCI_TYPEMETHOD_CONSTANT/g +s/OROTMFINL/OCI_TYPEMETHOD_INLINE/g +s/OROTMFCSTR/OCI_TYPEMETHOD_CONSTRUCTOR/g +s/OROTMFDSTR/OCI_TYPEMETHOD_DESTRUCTOR/g +s/OROTMFICO/OCI_METHOD_IS_CONSTANT/g +s/OROTMFICS/OCI_METHOD_IS_CONSTRUCTOR/g +s/OROTMFIDS/OCI_METHOD_IS_DESTRUCTOR/g +s/OROTMFIIN/OCI_METHOD_IS_INLINE/g +s/OROTMFIMP/OCI_METHOD_IS_MAP/g +s/OROTMFIOP/OCI_METHOD_IS_OPERATOR/g +s/OROTMFIOR/OCI_METHOD_IS_ORDER/g +s/OROTMFIRD/OCI_METHOD_IS_RNDS/g +s/OROTMFIRP/OCI_METHOD_IS_RNPS/g +s/OROTMFISL/OCI_METHOD_IS_SELFISH/g +s/OROTMFIVR/OCI_METHOD_IS_VIRTUAL/g +s/OROTMFIWD/OCI_METHOD_IS_WNDS/g +s/OROTMFIWP/OCI_METHOD_IS_WNPS/g +s/OROTMFMAP/OCI_TYPEMETHOD_MAP/g +s/OROTMFOP/OCI_TYPEMETHOD_OPERATOR/g +s/OROTMFOR/OCI_TYPEMETHOD_ORDER/g +s/OROTMFSLF/OCI_TYPEMETHOD_SELFISH/g +s/OROTMFRDS/OCI_TYPEMETHOD_RNDS/g +s/OROTMFRPS/OCI_TYPEMETHOD_RNPS/g +s/OROTMFVRT/OCI_TYPEMETHOD_VIRTUAL/g +s/OROTMFWDS/OCI_TYPEMETHOD_WNDS/g +s/OROTMFWPS/OCI_TYPEMETHOD_WNPS/g +s/OROTMFSCO/OCI_TYPEMETHOD_SET_CONSTANT/g +s/OROTMFSCS/OCI_TYPEMETHOD_SET_CONSTRUCTOR/g +s/OROTMFSDS/OCI_TYPEMETHOD_SET_DESTRUCTOR/g +s/OROTMFSIN/OCI_TYPEMETHOD_SET_INLINE/g +s/OROTMFSMP/OCI_TYPEMETHOD_SET_MAP/g +s/OROTMFSOP/OCI_TYPEMETHOD_SET_OPERATOR/g +s/OROTMFSOR/OCI_TYPEMETHOD_SET_ORDER/g +s/OROTMFSRD/OCI_TYPEMETHOD_SET_RNDS/g +s/OROTMFSRP/OCI_TYPEMETHOD_SET_RNPS/g +s/OROTMFSSL/OCI_TYPEMETHOD_SET_SELFISH/g +s/OROTMFSVR/OCI_TYPEMETHOD_SET_VIRTUAL/g +s/OROTMFSWD/OCI_TYPEMETHOD_SET_WNDS/g +s/OROTMFSWP/OCI_TYPEMETHOD_SET_WNPS/g +s/OROTNOPRE/OCI_NUMBER_DEFAULTPREC/g +s/OROTNOSCL/OCI_NUMBER_DEFAULTSCALE/g +s/OROTPMIO/OCI_TYPEPARAM_INOUT/g +s/OROTPMIN/OCI_TYPEPARAM_IN/g +s/OROTPMREF/OCI_TYPEPARAM_BYREF/g +s/OROTPMOUT/OCI_TYPEPARAM_OUT/g +s/OROTGOHDR/OCI_TYPEGET_HEADER/g +s/OROTGOALL/OCI_TYPEGET_ALL/g +s/OROCOSFN/OCI_COPY_NOREF/g + diff --git a/ort_f.sed b/ort_f.sed new file mode 100644 index 0000000..63bd6cd --- /dev/null +++ b/ort_f.sed @@ -0,0 +1,59 @@ +# NAME +# ort_f.sed +# DESCRIPTION +# This sed script changes the ORT function and type names to long names +# MODIFIED +# 10/03/96 - Peter Vasterd - Creation +# 10/10/96 - Peter Vasterd - Merge Calvins' stuff +s/ortado/OCITypeElem/g +s/ortgabi/OCITypeAttrNext/g +s/ortgabn/OCITypeAttrByName/g +s/ortganm/OCITypeElemName/g +s/ortgpnm/OCITypeElemName/g +s/ortgasqt/OCITypeElemExtTypeCode/g +s/ortgatc/OCITypeElemTypeCode/g +s/ortgcel/OCITypeCollElem/g +s/ortgcne/OCITypeCollSize/g +s/ortgcsqt/OCITypeCollExtTypeCode/g +s/ortgdttc/OCITypeCollTypeCode/g +s/ortgmbi/OCITypeMethodNext/g +s/ortgmbn/OCITypeMethodByName/g +s/ortgmen/OCITypeMethodEncap/g +s/ortgmfl/OCITypeMethodFlags/g +s/ortgmmap/OCITypeMethodMap/g +s/ortgmnm/OCITypeMethodName/g +s/ortgmno/OCITypeMethodOverload/g +s/ortgmnp/OCITypeMethodParams/g +s/ortgmor/OCITypeMethodOrder/g +s/ortgnp/OCITypeElemNumPrec/g +s/ortgns/OCITypeElemNumScale/g +s/ortgpa/OCITypeElemParameterizedType/g +s/ortgpbn/OCITypeParamByName/g +s/ortgpbp/OCITypeParamByPos/g +s/ortgpps/OCITypeParamPos/g +s/ortgpdv/OCITypeElemDefaultValue/g +s/ortgpmo/OCITypeElemParamMode/g +s/ortgptc/OCITypeElemTypeCode/g +s/ortgscform/OCITypeElemCharSetForm/g +s/ortgscid/OCITypeElemCharSetID/g +s/ortgsl/OCITypeElemLength/g +s/ortgtme/OCITypeName/g +s/ortgtna/OCITypeAttrs/g +s/ortgtnm/OCITypeMethods/g +s/ortgttc/OCITypeTypeCode/g +s/ortgtsch/OCITypeSchema/g +s/ortgtvn/OCITypeVersion/g +s/ortgpty/OCITypeElemType/g +s/ortifre/OCITypeIterFree/g +s/ortinew/OCITypeIterNew/g +s/ortiset/OCITypeIterSet/g +s/ortitr/OCITypeIter/g +s/ortmdo/OCITypeMethod/g +s/ortpdo/OCITypeElem/g +s/ortrdo/OCITypeElem/g +s/orttdo/OCIType/g +s/ortvini/OCITypeVTInit/g +s/ortvins/OCITypeVTInsert/g +s/ortvsel/OCITypeVTSelect/g +s/ortgatyp/OCITypeArrayByName/g +s/ortgaty/OCITypeElemType/g diff --git a/readpipe.c b/readpipe.c new file mode 100644 index 0000000..8eda286 --- /dev/null +++ b/readpipe.c @@ -0,0 +1,242 @@ +#ifdef RCSID +static char *RCSid = + "$Header: rdbms/demo/readpipe.c /main/9 2008/08/29 10:48:36 yitseng Exp $ "; +#endif /* RCSID */ + +/* Copyright (c) 1991, 2008, Oracle. All rights reserved. +*/ + +/* + NAME + readpipe.c - read a server named pipe + NOTES + described in ORACLE7 Server Application Developer's Guide + MODIFIED (MM/DD/YY) + yitseng 08/29/08 - XbranchMerge yitseng_bug6273715 from st_rdbms_10.2 + yitseng 09/20/07 - bug6273715 + ppallapo 02/28/06 - Bug/5068904 + mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines + bnnguyen 04/01/98 - bug487125 + dchatter 07/15/96 - hda is a ub4 array to prevent bus error + emendez 04/07/94 - merge changes from branch 1.3.710.2 + gdoherty 04/06/94 - merge changes from branch 1.3.710.1 + 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 +#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; +size_t hda[HDA_SIZE/sizeof(size_t)]; /* host area */ +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, (ub1 *)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); +} + + + diff --git a/resultcache.sql b/resultcache.sql new file mode 100644 index 0000000..3c584c5 --- /dev/null +++ b/resultcache.sql @@ -0,0 +1,169 @@ +Rem +Rem $Header: resultcache.sql 01-jun-2007.10:01:28 achaudhr Exp $ +Rem +Rem resultcache.sql +Rem +Rem Copyright (c) 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem resultcache.sql - Result Cache +Rem +Rem DESCRIPTION +Rem A demonstration of the Result Cache feature. +Rem +Rem NOTES +Rem Requires the Result Cache to be enabled. +Rem +Rem USAGE +Rem sqlplus /nolog @$ORACLE_HOME/rdbms/demo/resultcache.sql > rc.log +Rem +Rem MODIFIED (MM/DD/YY) +Rem achaudhr 05/31/07 - Split into Basic and Intemediate +Rem achaudhr 04/13/07 - Created +Rem + +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 100 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 1000 +COL PLAN_TABLE_OUTPUT FOR A100 + +--- --------------------- --- +--- Basic Demonstration --- +--- --------------------- --- + +connect scott/tiger + +--- It's generally not possible to tell if the Result Cache was used by simply +--- looking at the output of a query, so we use a function with a side-effect to +--- detect a cache miss. + +--- Function used for detecting a cache miss (i.e. when the cache isn't used) +create or replace function CacheMiss return number DETERMINISTIC is +begin + dbms_output.put_line('CACHE MISS'); + return null; +end; +/ +set serveroutput on + +--- The first execution of a query will be a cache-miss +select /*+ result_cache */ * from dept where CacheMiss is null; + +--- But the second execution answers from the cache +select /*+ result_cache */ * from dept where CacheMiss is null; + +--- A query still sees its own changes (by bypassing the cache) +update dept set dname = rpad(dname, 12, '*'); +select /*+ result_cache */ * from dept where CacheMiss is null; + +--- Committing changes invalidates the result which can subsequently be re-cached +commit; +select /*+ result_cache */ * from dept where CacheMiss is null; +select /*+ result_cache */ * from dept where CacheMiss is null; + +-- A different session also uses the same cached result +connect / as sysdba +set serveroutput on + +alter session set current_schema = scott; + +select /*+ result_cache */ * -- Comments, +from dept -- spaces, +where CACHEMISS IS NULL -- and case don't matter. +/ + +--- Restore the dept table (to original values) +connect scott/tiger +update dept set dname = rtrim(dname, '*'); +commit; + +--- ---------------------------- --- +--- Intermediate Demonstration --- +--- ---------------------------- --- + +connect scott/tiger + +--- Verify that the queries will use the cache +explain plan for +select /*+ result_cache */ * from dept; + +set echo off +@$ORACLE_HOME/rdbms/admin/utlxpls +set echo on + +explain plan for +with e as +( +select /*+ result_cache */ deptno, count(*) emp_count +from emp +group by deptno +) +select dname, emp_count +from dept d, e +where e.deptno = d.deptno; + +set echo off +@$ORACLE_HOME/rdbms/admin/utlxpls +set echo on + +--- Cache each query's result and then scan (i.e. use) the cached result once +select /*+ result_cache */ * from dept; +/ + +with e as +( +select /*+ result_cache */ deptno, count(*) emp_count +from emp +group by deptno +) +select dname, emp_count +from dept d, e +where e.deptno = d.deptno; +/ + +--- Create a caching function and call it from sql +create or replace function EMP_COUNT(dno number) return number + result_cache relies_on (emp) +is + cnt number; +begin + select count(*) into cnt from emp where deptno = dno; + return cnt; +end; +/ + +select dname, EMP_COUNT(deptno) emp_count +from dept where dname = 'SALES'; +/ + +--- Invalidate the first query by modifying dept +update dept set loc = loc; +commit; + +connect / as sysdba + +--- View memory allocation and usage statistics +set serveroutput on +execute dbms_result_cache.memory_report +column name format a62 +column scan_count format 9999 +column statistic format a35 +select name statistic, value from v$result_cache_statistics; +select type, status, scan_count, namespace, name +from v$result_cache_objects +order by type, status, creation_timestamp; + +--- Flush the cache and verify that memory was released +execute dbms_result_cache.flush +execute dbms_result_cache.memory_report + +--- Finally, recreate dependencies (post-flush) +connect scott/tiger +select /*+ result_cache */ distinct loc from emp e, dept d +where e.deptno=d.deptno and CacheMiss is null; + +exit diff --git a/rman2.sh b/rman2.sh new file mode 100644 index 0000000..51c0786 --- /dev/null +++ b/rman2.sh @@ -0,0 +1,97 @@ +#!/bin/sh +# +# $Header: rman2.sh 26-jul-99.09:32:20 mjaeger Exp $ +# +# Copyright (c) 1998, 1999, Oracle Corporation. All rights reserved. +# +# rman2.sh +# +# NAME +# rman2.sh - duplexed backup of archivelogs +# +# DESCRIPTION +# This shell script dynamically constructs an RMAN backup job and then +# executes it. It will backup the archivelogs, creating 2 copies +# of each archivelog. This is intended for 8.0.x versions of RMAN. With +# 8.1.3, the duplex feature makes this script unnecessary. +# +# NOTES +# Some customization is necessary. +# +# Set "freq" to be the frequency in hours with which you execute this +# script. If your rate of redolog generation is very high, then you +# might need to backup archivelogs every 2 hours. In this case, +# set freq=2. +# +# MODIFIED (MM/DD/YY) +# mjaeger 07/26/99 - bug 808870: OCCS: convert tabs, no long lines +# gpongrac 08/11/98 - Creation +# + +# Initialize connect string variables. Change these as necessary. + +target='target /' # default to "connect internal" +rcvcat='nocatalog' # default to nocatalog mode +#rcvcat='rcvcat rman/rman@rcat_db' + +freq=24 # The number of hours between executions of this script. + # Default to once every 24 hours (once a day). + # Change this as necessary. + +# Get the current time for constructing a fairly unique filename in /tmp: +time=`date '+%H%M%S'` + +# Construct filenames using $time for uniqueness: + +cmdfile=/tmp/rman$time.rcv +msglog=/tmp/rman$time.log + +# Get the current time-of-day in the format: +# YYYY MM DD HH24:MI:SS + +tod=`date '+%Y %m %d %H:%M:%S'` + +# +# CUSTOMIZATION: +# +# The RMAN script below should be customized as appropriate. +# Add "allocate channel" commands as needed so that the desired number of +# tape drives will be utilized. +# +# The format string can be changed if desired, but it must generate +# unique names. %u is usually good enough. +# +# The RMAN invocation should be customized with the target database +# SYS password and TNS alias. If you use a recovery catalog, replace +# "nocatalog" with "rcvcat", and follow it with the connect string +# for the recovery catalog. +# +# The "like" clause can be uncommented and edited to have RMAN backup +# only archivelogs whose filenames are LIKE the specified pattern. +# This can be used to backup only those archivelogs in a particular +# log_archive_dest. +# + +cat << EOF > $cmdfile +run { +allocate channel c1 type 'sbt_tape'; +allocate channel c2 type 'sbt_tape'; +# allocate additional channels as necessary +backup archivelog + from time="to_date('$tod', 'YYYY MM DD HH24:MI:SS')-$freq/24" + until time="to_date('$tod', 'YYYY MM DD HH24:MI:SS')" + # like 'primary_archivelog_destination_mount_point/%' + format='%u'; +backup archivelog + from time="to_date('$tod', 'YYYY MM DD HH24:MI:SS')-$freq/24" + until time="to_date('$tod', 'YYYY MM DD HH24:MI:SS')" + # like 'primary_archivelog_destination_mount_point/%' + format='%u' + delete input; +} +EOF + +rman $target $rcvcat cmdfile $cmdfile msglog $msglog + +exit # rman2.sh + diff --git a/ruldemo.sql b/ruldemo.sql new file mode 100644 index 0000000..b11bbbe --- /dev/null +++ b/ruldemo.sql @@ -0,0 +1,1034 @@ +Rem +Rem $Header: ruldemo.sql 14-dec-2006.09:36:47 ayalaman Exp $ +Rem +Rem ruldemo.sql +Rem +Rem Copyright (c) 2004, 2006, Oracle. All rights reserved. +Rem +Rem NAME +Rem ruldemo.sql - Rules Manager demo script +Rem +Rem DESCRIPTION +Rem This script demonstrates the use of Rules Manager in +Rem a few configurations. See the Application Developer's +Rem Guide - Rules Manager and Expression Filter for +Rem additional information. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem ayalaman 12/14/06 - add demo for collection events +Rem ayalaman 11/15/04 - XPath expression example and rule descriptions +Rem ayalaman 11/02/04 - replace homeland security with law enforcement +Rem ayalaman 10/07/04 - ayalaman_bug-3922526 +Rem ayalaman 09/29/04 - Created +Rem + +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 + +connect / as sysdba; +set serveroutput on; +drop user ruldemo cascade; +create user ruldemo identified by ruldemo; +grant connect, resource to ruldemo; +grant execute on dbms_lock to ruldemo; +grant create view to ruldemo; + +connect ruldemo/ruldemo; +set echo on; +set pagesize 150; +column mesg format a78; +column attime format a30; +column rlm$rulecond format a95; +column rlm$ruleid format a5; + +/***************************************************************** + The tests in this file are organized as follows: + I. Application demonstrating the various steps in a Rules + Manager application. + II. Application demonstrating the use of Table aliases and + DML (Insert) Events for rule management. + III. Application demonstrating the use of ADD_EVENT API and + Rule class results view + IV. Application demonstrating the use of collection events +******************************************************************/ +set linesize 110; +--- +--- I. Application demostrating the various steps in a Rules +--- Manager application. +--- +--- The following script uses Law Enforcement application to demonstrate +--- the use of Rules Manager. In this application, rules are defined to +--- raise security alerts, place a person on the watch list, etc based +--- on certain criteria. For this purpose, some real-world events such as +--- Bank Transactions, Transportation and Field Reports are used +--- to describe the criteria. +--- +create table messagequeue (attime timestamp, mesg varchar2(4000)); + +--- +--- 1. Create the basic types that represent the primitive event +--- structures +--- +create or replace type BankTransaction as object + (subjectId NUMBER, --- refer to entity such as personnel + --- could be SSN + tranType VARCHAR2(30), --- DEPOSIT / TRANSFER / WITHDRAW + amount NUMBER, --- + fundFrom VARCHAR2(30)); --- location from which it is transfered +/ + +create or replace type Transportation as object + (subjectId NUMBER, + vesselType VARCHAR2(30), --- TRUCK / CAR / PLANE / TRAIN + locFrom VARCHAR2(30), --- starting location + locTo VARCHAR2(30), --- ending location + startDate DATE, --- start date + endDate DATE); --- end date of +/ + +create or replace type FieldReport as object + (subjectId NUMBER, + rptType VARCHAR2(30), --- Tel call / Meeting / Bg Check + whoWith NUMBER, --- identifier of the person the subject + --- is in touch with + rptOrg VARCHAR2(30), --- Organization reporting it + rptReg VARCHAR2(30), --- Region + rptBody sys.XMLType); --- the actual report +/ + +--- +--- 2. Create a composite event type that consists of these basic types. +--- +create or replace type LawEnforcement as object + (bank BankTransaction, + transport Transportation, + fldrpt FieldReport); +/ + +--- +--- 3. Create a repository for the rules defined on the composite event +--- structure +--- +BEGIN + DBMS_RLMGR.CREATE_RULE_CLASS( + rule_class => 'LawEnforcementRC', + event_struct => 'LawEnforcement', + action_cbk => 'LawEnforcementCBK', + actprf_spec => 'actionType VARCHAR2(40), actionParam VARCHAR2(100)', + rslt_viewnm => 'MatchedCriteria', + rlcls_prop => ''); +END; +/ + +--- The above steps create a relational table, LawEnforcementRC, which acts +--- as the repository for the rules in this application. This table has +--- a set of pre-defined columns to store the Rule identifiers, Rule +--- conditions and the descriptions. In addition to these columns, this +--- rule class table is defined with two columns, actionType and +--- actionParam, as specified through the actpref_spec argument. These +--- columns capture the type of action that should be carried for each +--- rule. +desc LawEnforcementRC; + +--- The above steps also creates the skeleton for an action callback +--- procedure with the specified name. + +select text from user_source where name = 'LAWENFORCEMENTCBK' order by line; + +--- +--- 4. Implement the callback procedure to perform appropriate action +--- for each matching rule, based on the event instances that +--- matched the rule and the action preferences associated with +--- the rule. +--- +CREATE OR REPLACE PROCEDURE LAWENFORCEMENTCBK ( + bank banktransaction, + transport transportation, + fldrpt fieldreport, + rlm$rule LawEnforcementRC%ROWTYPE) IS + mesg VARCHAR2(4000); + msgl VARCHAR2(100); +begin + msgl := 'Rule '||rlm$rule.rlm$ruleid||' matched following primitive events'; + dbms_output.put_line(msgl); + mesg := msgl||chr(10); + if (bank is not null) then + msgl := '->Bank Transaction by subject ('||bank.subjectId||') of type ['||bank.tranType||']'; + dbms_output.put_line(msgl); + mesg := mesg||msgl||chr(10); + end if; + if (transport is not null) then + msgl := + '->Transportation by subject('||transport.subjectId||') use vessel ['||transport.vesselType||']'; + dbms_output.put_line(msgl); + mesg := mesg||msgl||chr(10); + end if; + if (fldrpt is not null) then + msgl := + '->Field report refer to('||fldrpt.subjectId||' and '||fldrpt.whowith||')'; + dbms_output.put_line(msgl); + mesg := mesg||msgl||chr(10); + end if; + + msgl := '=>Recommended Action : Action Type ['||rlm$rule.actionType|| + '] Action Parameter ['||rlm$rule.actionParam||']'; + + dbms_output.put_line(msgl||chr(10)); + mesg := mesg||msgl||chr(10); + insert into messagequeue values (systimestamp, mesg); +end; +/ + +show errors; + +--- +--- 5. The rules defined in the rule class can make use of user-defined +--- functions in the database schema. The following commands create +--- some dummy functions that are later used in the rule conditions. +--- + +-- +-- For the value of the region passed in, query the restricted +-- areas table and return 1 if the current region is a restricted +-- area. +CREATE OR REPLACE FUNCTION IsRestrictedArea(region VARCHAR2) + RETURN NUMBER IS +BEGIN + -- User can expand this function and implement a logic that + -- relies on other relational tables. + RETURN 1; +END; +/ + +-- +-- Check if the subject chosen is on the watch list +-- +CREATE OR REPLACE FUNCTION OnWatchList(subject NUMBER) + RETURN NUMBER IS +BEGIN + -- User can expand this function and implement a logic that + -- relies on other relational tables. + RETURN 1; +END; +/ + +-- +-- Verify if two parties are associates. Return 1 is the two +-- subjects passed in are associates according to the registry. +-- +CREATE OR REPLACE FUNCTION AreAssociates(subjectA NUMBER, + subjectB NUMBER) + RETURN NUMBER IS +BEGIN + -- User can expand this function and implement a logic that + -- relies on other relational tables. + RETURN 1; +END; +/ + +-- Add all three user-defined functions to composite event +-- "LawEnforcement", so that these functions can be used +-- in the corresponding rule conditions. +EXEC DBMS_RLMGR.ADD_FUNCTIONS('LawEnforcement', 'OnWatchList'); +EXEC DBMS_RLMGR.ADD_FUNCTIONS('LawEnforcement', 'IsRestrictedArea'); +EXEC DBMS_RLMGR.ADD_FUNCTIONS('LawEnforcement', 'AreAssociates'); + +--- +--- 6. Define the rules that suggest some actions +--- + +--- Rule : Add a person to the NYPD watch list if he recieves a money +--- transfer for more than 10000 dollars and if he rents a truck, +--- one-way to one of the restricted areas. Note that the join +--- predicate is specified at the rule class elevel. --- +INSERT INTO LawEnforcementRC (rlm$ruleid, actionType, actionParam, rlm$rulecond, + rlm$ruledesc) +VALUES ('1', 'ADD2WATCHLIST','NYPD', + ' + + + tranType = ''TRANSFER'' AND amount > 10000 AND fundFrom != ''usa'' + + + vesselType = ''TRUCK'' AND locFrom != locTo AND IsRestrictedArea(locTo)=1 + + + ', +'Add a person to the NYPD watch list if he recieves a money transfer +for more than 10000 dollars and if he rents a truck one-way to one +of the restricted areas'); + +--- +--- Rule : Add a person to the NYPD watch list if 2 out of the following 3 +--- conditions are met : +--- * The person get a money transfer for over 10000 dollars from outside USA +--- * He rented a truck, one-way, into one of the restricted areas and +--- * He had a phone conversation with a person alreadt on the watch list. +--- +--- The following rule demonstrates the use of ANY where a rule condition is +--- considered true is m out of n events are detected. --- +INSERT INTO LawEnforcementRC (rlm$ruleid, actionType, actionParam, rlm$rulecond, + rlm$ruledesc) +VALUES ('2', 'ADD2WATCHLIST','NYPD', + ' + + + tranType = ''TRANSFER'' AND amount > 10000 AND fundFrom != ''usa'' + + + vesselType = ''TRUCK'' AND locFrom != locTo AND IsRestrictedArea(locTo)=1 + + + rptType = ''TELCALL'' AND OnWatchList(whoWith) = 1 + + + ', +'Add a person to the NYPD watch list if 2 out of the 3 specified +conditions are met'); + +--- +--- Rule : Start a background check on a person if he receives a large +--- sum of money from outside USA, he rents a truck one-way into one of +--- the restricted areas and there is no field report with his background +--- information. +--- +--- The following rule demonstrates the use of negation where a rule condition +--- is considered true if some of the specified events are detected and the +--- other events are not detected --- +INSERT INTO LawEnforcementRC (rlm$ruleid, actionType, actionParam, rlm$rulecond, + rlm$ruledesc) +VALUES ('3','STARTBACKGROUNDCHECK','RENTAL_DESTINATION', + ' + + + tranType = ''TRANSFER'' AND amount > 10000 AND fundFrom != ''USA'' + + + vesselType=''TRUCK'' AND locFrom != locTo AND IsRestrictedArea(locTo)=1 + + + + rptType = ''BG Check'' + + + + ', +'Start a background check on a person if he receives a large +sum of money from outside USA, he rents a truck one-way into +one of restricted areas and there is no field report with his +background information'); + +--- Rule : If a subject received over 10000 dollars from outside US, +--- he rented a truck for one direction into a restricted area and a +--- field report saying that the subject was never arrested before was +--- not submitted within "certain" (0.001 fraction of a day; could be +--- days. But seconds are used to demonstrate the use of deadline) +--- period, add the destination of the truck to high-risk areas --- +--- +--- This rule demonstrates the use of Negation with a deadline. +--- +INSERT INTO LawEnforcementRC (rlm$ruleid, actionType, actionParam, rlm$rulecond, + rlm$ruledesc) +VALUES ('4','ADD2HIGH_RISK_AREA','RENTAL_DESTINATION', + ' + + + tranType = ''TRANSFER'' AND amount > 10000 AND fundFrom != ''usa'' + + + vesselType = ''TRUCK'' AND locFrom != locTo AND IsRestrictedArea(locTo)=1 + + + + rptType = ''BACKGROUNDCHECK'' and + extract(rptBody, ''/history/arrests[@number=0]'') is not null + + + + ', +'If a subject received over 10000 dollars from outside US, +he rented a truck for one direction into a restricted area and a +field report saying that the subject was never arrested before was +not submitted within "certain" period, add the destination of the +truck to high-risk areas'); + +commit; + +--- Browse the rules --- +select rlm$ruleid, rlm$rulecond from LawEnforcementRC order by 1; + +--- +--- 7. Process the rules for the primitive events +--- +set serveroutput on size 10000; + +BEGIN + dbms_rlmgr.process_rules ( + rule_class => 'LawEnforcementRC', + event_inst => + sys.anydata.convertobject( + fieldreport(123302122, 'TELCALL',123302123, 'NSA', 'NE', null))); +END; +/ + +--- The following event partially matches some of the rules defined above --- +BEGIN + dbms_rlmgr.process_rules ( + rule_class => 'LawEnforcementRC', + event_inst => + sys.anydata.convertobject( + banktransaction(123302122, 'TRANSFER', 100000, 'USSR'))); +END; +/ + +--- This event in combination with the other event evaluates some of the +--- rules to true and thus calls the action call-back procedure. +BEGIN + dbms_rlmgr.process_rules ( + rule_class => 'LawEnforcementRC', + event_inst => + sys.anydata.convertobject( + transportation(123302122, 'TRUCK', 'WIS', 'MD', + sysdate, sysdate + 7))); +END; +/ + +select mesg from messagequeue order by attime; + +truncate table messagequeue; + +--- Let us sleep past the deadline for rule 5. The scheduler process picks up +--- this rule and executes its action. The result is a new message in the +--- message queue. +exec dbms_lock.sleep(180); + +--- The action is executed for the rule 5 after the deadline time is elapsed. +select mesg from messagequeue; + +exec dbms_rlmgr.drop_rule_class('LawEnforcementRC'); +exec dbms_rlmgr.drop_event_struct('LawEnforcement'); + +drop type LawEnforcement; + +exec dbms_rlmgr.drop_event_struct('BankTransaction'); +drop type BankTransaction; + +exec dbms_rlmgr.drop_event_struct('Transportation'); +drop type Transportation; + +exec dbms_rlmgr.drop_event_struct('FieldReport'); +drop type fieldreport; + +/*************************************************************************/ +--- +--- II. Application demonstrating the use of Table aliases and +--- DML (Insert) Events for rule management. +--- +--- Order Management application to demonstrate the use of Table +--- Aliases and DMLEVENTS with rules. +-- +column attime format a30; +column mesg format a50; +set echo on; +set pagesize 150; +set linesize 150; + +--- +--- The following script uses Order Management application to demonstrate +--- the use of Rules Manager for the (event) data that is stored in +--- Relational tables. +--- +--- +--- Let us consider 3 relational tables that store the information +--- about the Purchase Orders, Shipping information, and Payment +--- information. +--- +create table PurchaseOrders + (orderId NUMBER, + custId NUMBER, + itemId NUMBER, + itemType VARCHAR2(30), + quantity NUMBER, + shipBy DATE); + +create table ShipmentInfo + (orderId NUMBER, + destState VARCHAR2(2), + address VARCHAR2(50), + shipTime DATE, + shipType VARCHAR2(10)); + +create table PaymentInfo + (orderId NUMBER, + payType VARCHAR2(10), -- Credit Card / Check -- + amountPaid NUMBER, + pymtTime DATE, + billState VARCHAR2(2)); + +--- +--- 1. Create the event structure. +--- The event structures that refer to existing table using +--- table alias constructs cannot be created from object types. +--- Instead, such event structures should be modeled as +--- Expression Filter attribute sets. +--- +begin + DBMS_RLMGR.CREATE_EVENT_STRUCT (event_struct => 'OrderMgmt'); + + DBMS_RLMGR.ADD_ELEMENTARY_ATTRIBUTE( + event_struct => 'OrderMgmt', + attr_name => 'po', + tab_alias => RLM$TABLE_ALIAS('PurchaseOrders')); + + DBMS_RLMGR.ADD_ELEMENTARY_ATTRIBUTE( + event_struct => 'OrderMgmt', + attr_name => 'si', + tab_alias => RLM$TABLE_ALIAS('ShipmentInfo')); + + DBMS_RLMGR.ADD_ELEMENTARY_ATTRIBUTE( + event_struct => 'OrderMgmt', + attr_name => 'py', + tab_alias => RLM$TABLE_ALIAS('PaymentInfo')); +end; +/ + +--- +--- 2. Create the rule class (repository for rules) for the +--- OrderMgmt composite event. Also specify the DMLEVENTS property +--- to process the rules for each Inserted row into the (event) data +--- tabled. +--- +BEGIN + DBMS_RLMGR.CREATE_RULE_CLASS ( + rule_class => 'OrderMgmtRC', + event_struct => 'OrderMgmt', + action_cbk => 'OrderMgmtCBK', + actprf_spec => 'actionType VARCHAR2(40), actionParam VARCHAR2(100)', + rslt_viewnm => 'MatchingOrders', + rlcls_prop => ''); +END; +/ + +desc OrderMgmtCBK; + +--- +--- 3. Implement the action callback procedure to +--- +CREATE OR REPLACE PROCEDURE OrderMgmtCBK ( + po ROWID, -- rowid from the PurchaseOrders table + si ROWID, -- rowid from the ShipmentInfo table + py ROWID, -- rowid from the PaymentInfo table + rlm$rule OrderMgmtRC%ROWTYPE) IS + ordId NUMBER; + msg VARCHAR2(2000); +begin + -- the rowid arguments represent the primitive events that are + -- rows inserted into the corresponding tables. Use the rowids + -- to fetch necessary values. + if (po is not null) then + select orderId into ordId from PurchaseOrders where rowid = po; + elsif (si is not null) then + select orderId into ordId from ShipmentInfo where rowid = si; + elsif (py is not null) then + select orderId into ordId from PaymentInfo where rowid = py; + end if; + + msg := 'Order number: '||ordId||' Matched rule: ' + ||rlm$rule.rlm$ruleid||chr(10)|| + '-> Recommended Action : '||chr(10)|| + ' Action Type ['||rlm$rule.actionType|| + ']'||chr(10)||' Action Parameter ['|| + rlm$rule.actionParam||']'; + + dbms_output.put_line (msg||chr(10)); +end; +/ + +--- +--- 4. Add User-Defined functions that may be useful in rule +--- conditions. +--- +create or replace function getCustType(custId number) + return VARCHAR2 is +begin + -- the actual function implementation can rely on other + -- relational tables to derive the customer type information + return 'GOLD'; +end; +/ + +exec DBMS_RLMGR.ADD_FUNCTIONS('OrderMgmt','getCustType'); + +--- +--- 4. Add some rules +--- +--- Rule : If the order is for more than 100 routers and the +--- payment is received as a check, contact the customer +--- to update on the status of the order. +--- Note that the join predicate across event types is specified +--- at the rule class level +--- +INSERT INTO OrderMgmtRC (rlm$ruleid, actionType, actionParam, rlm$rulecond) +VALUES (1, 'CALL_CUSTOMER','UPDATE_ORDER_STATUS', + ' + + + itemType = ''ROUTER'' and quantity > 100 + + + payType = ''CHECK'' + + + '); + +--- Rule : If the order is placed by a GOLD customer, +--- and the items are shipped before receiving a payment, +--- adjust the customer's credit. +INSERT INTO OrderMgmtRC (rlm$ruleid, actionType, actionParam, rlm$rulecond) +VALUES (2, 'UPDATE_CUST_PROFILE', 'DECR_AVAILABLE_CREDIT', + ' + + getCustType(custid) = ''GOLD'' + + + + + + '); + + +--- Rule : If the order is place by a Gold customer and the item +--- item is shipped within 1 day prior to the shipby date, +--- increment the Quality of service statistics. +--- +INSERT INTO OrderMgmtRC (rlm$ruleid, actionType, actionParam, rlm$rulecond) +VALUES (3, 'UPDATE_STATISTICS', 'INCREMENT QOS', + ' + + getCustType(custid) = ''GOLD'' + + + '); + +commit; + +set serveroutput on; + +insert into PurchaseOrders (orderId, custId, itemId, itemType, + quantity, shipBy) values +(1, 123, 234, 'ROUTER', 120, '01-OCT-2004'); + +insert into ShipmentInfo (orderId, deststate, address, shipTime, + shipType) values +(1, 'CA','1 Main street, San Jose','29-SEP-2004','1 Day Air'); + +insert into PaymentInfo (orderId, paytype, amountpaid, pymttime, + billstate) values +(1, 'CHECK', 100000, '30-SEP-2004', 'CA'); + +commit; + +--- +--- III. Application demonstrating the use of ADD_EVENT API and +--- Rule class results view +--- +--- Now let us consider a similar application without the use of +--- DMLEVENTS. This implies that the user explicitly invokes the +--- rules manager APIs to process the rules for some data stored +--- in relational tables. +--- +--- We can share the same event structure for another rule class. +--- +BEGIN + DBMS_RLMGR.CREATE_RULE_CLASS ( + rule_class => 'OrderMgmtRC2', + event_struct => 'OrderMgmt', + action_cbk => 'OrderMgmtCBK2', + actprf_spec => 'actionType VARCHAR2(40), actionParam VARCHAR2(100)', + rslt_viewnm => 'MatchingOrders2', + rlcls_prop => ''); +END; +/ + +--- Implement the action callback procedure -- +CREATE OR REPLACE PROCEDURE OrderMgmtCBK2 ( + po ROWID, -- rowid from the PurchaseOrders table + si ROWID, -- rowid from the ShipmentInfo table + py ROWID, -- rowid from the PaymentInfo table + rlm$rule OrderMgmtRC2%ROWTYPE) IS + ordId NUMBER; + msg VARCHAR2(2000); +begin + -- the rowid argument represent the primitive events that are + -- rows inseted into the corresponding tables. Use the rowids + -- to fetch necessary values. + if (po is not null) then + select orderId into ordId from PurchaseOrders where rowid = po; + elsif (si is not null) then + select orderId into ordId from ShipmentInfo where rowid = si; + elsif (py is not null) then + select orderId into ordId from PaymentInfo where rowid = py; + end if; + + msg := 'Order number: '||ordId||' Matched rule: ' + ||rlm$rule.rlm$ruleid||chr(10)|| + '-> Recommended Action : '||chr(10)|| + ' Action Type ['||rlm$rule.actionType|| + ']'||chr(10)||' Action Parameter ['|| + rlm$rule.actionParam||']'; + + dbms_output.put_line (msg||chr(10)); +end; +/ + +--- insert the same set of rules into the new rule class. +insert into OrderMgmtRC2 (select * from OrderMgmtRC); + +delete from OrderMgmtRC; + +commit; + +--- Since DML events are not configured for this rule class, +--- the application has to explicitly process rules for the +--- rows in the data table. The rowids of the rows are used +--- as references to the events. + +var datarid varchar2(40); + + +insert into PurchaseOrders (orderId, custId, itemId, itemType, + quantity, shipBy) values +(2, 123, 234, 'ROUTER', 120, '01-OCT-2004') +returning rowid into :datarid; + +BEGIN + dbms_rlmgr.process_rules (rule_class => 'OrderMgmtRC2', + event_type => 'PurchaseOrders', + event_inst => :datarid); +END; +/ + +insert into ShipmentInfo (orderId, deststate, address, shipTime, + shipType) values +(2, 'CA','1 Main street, San Jose','29-SEP-2004','1 Day Air') +returning rowid into :datarid; + +BEGIN + dbms_rlmgr.process_rules (rule_class => 'OrderMgmtRC2', + event_type => 'ShipmentInfo', + event_inst => :datarid); +END; +/ + +insert into PaymentInfo (orderId, paytype, amountpaid, pymttime, + billstate) values +(2, 'CHECK', 100000, '30-SEP-2004', 'CA') +returning rowid into :datarid; + +BEGIN + dbms_rlmgr.process_rules (rule_class => 'OrderMgmtRC2', + event_type => 'PaymentInfo', + event_inst => :datarid); +END; +/ + +-- +-- Now try the session oriented evaluation of rules where the +-- results from matching rules are available in the results view +-- to be queried. +-- +set linesize 80; +desc MatchingOrders2; + +select count(*) from MatchingOrders2; + +insert into PurchaseOrders (orderId, custId, itemId, itemType, + quantity, shipBy) values +(3, 123, 234, 'ROUTER', 120, '01-OCT-2004') +returning rowid into :datarid; + +--- Use ADD_EVENT API in the place of PROCESS_RULES --- +BEGIN + dbms_rlmgr.add_event (rule_class => 'OrderMgmtRC2', + event_type => 'PurchaseOrders', + event_inst => :datarid); +END; +/ + +insert into ShipmentInfo (orderId, deststate, address, shipTime, + shipType) values +(3, 'CA','1 Main street, San Jose','29-SEP-2004','1 Day Air') +returning rowid into :datarid; + +BEGIN + dbms_rlmgr.add_event (rule_class => 'OrderMgmtRC2', + event_type => 'ShipmentInfo', + event_inst => :datarid); +END; +/ + +insert into PaymentInfo (orderId, paytype, amountpaid, pymttime, + billstate) values +(3, 'CHECK', 100000, '30-SEP-2004', 'CA') +returning rowid into :datarid; + +BEGIN + dbms_rlmgr.add_event (rule_class => 'OrderMgmtRC2', + event_type => 'PaymentInfo', + event_inst => :datarid); +END; +/ + +--- Since the event structure is configired with table aliases, +--- the events are represented using the rowids from the +--- corresponding tables. +column rlm$ruleid format a7; +column actiontype format a25; +column actionparam format a25; +select po, si, py, rlm$ruleid, actionType, actionParam from MatchingOrders2 order by 4; + +select + (select orderId from purchaseOrders where rowid = po) as OrderId, + rlm$ruleid, actionType, actionParam from MatchingOrders2 order by 2; + +exec dbms_rlmgr.drop_rule_class('OrderMgmtRC2'); +exec dbms_rlmgr.drop_rule_class('OrderMgmtRC'); +exec dbms_rlmgr.drop_event_struct('OrderMgmt'); + +drop table PurchaseOrders; +drop table ShipmentInfo; +drop table PaymentInfo; +drop table messagequeue; + +-- +--- IV. Use of Collection events in an Order Management Application +-- + +-- +-- 1. Create the object types for the event structure. +-- +create or replace type PurchaseOrder as object + ( orderid number, + customerid number, + itemid number, + itemcount number, + amount number, + exptddate date); +/ + +create or replace type ShipItem as object + ( itemid number, + itemtype varchar2(30), + orderid number, + truckid number); +/ + +create or replace type TruckAtDock as object + ( truckid number, + loadid date, + status varchar2(30), + capacity number); +/ + +create or replace type OrderMgmt as object + ( + porder PurchaseOrder, + sitem ShipItem, + truck TruckAtDock + ); +/ + +-- +-- 2. Create a rule class for the OrderMgmt composite event and enable +-- collection for PurchaseOrder and ShipItem events. +-- +BEGIN + DBMS_RLMGR.CREATE_RULE_CLASS( + rule_class => 'OrderMgmtRC', + event_struct => 'OrderMgmt', + action_cbk => 'OrderMgmtCBK', + actprf_spec => 'actionType VARCHAR2(40), actionParam VARCHAR2(100), + poAggrRet VARCHAR2(20) default null', + rslt_viewnm => 'MatchedScenarios', + rlcls_prop => ' + + + '); +END; +/ + +desc OrderMgmtCBK; + +-- +-- 3. Implement the action callback procedure +-- + +create or replace procedure "ORDERMGMTCBK" ( + PORDER PURCHASEORDER, + PO_EVTID ROWID, + SITEM SHIPITEM, + SI_EVTID ROWID, + TRUCK TRUCKATDOCK, + rlm$rule ORDERMGMTRC%ROWTYPE) is + mesg VARCHAR2(100); + aggrval VARCHAR2(100); +begin + mesg := ' Rule "'||rlm$rule.rlm$ruleid|| + '" matched '|| + case when porder.orderid is not null then 'Purchase Order '||porder.orderid + when porder.customerid is not null then 'Customer '||porder.customerid + when sitem.truckid is not null then '||Truck '||sitem.truckid + end; + + if (porder is not null and rlm$rule.poAggrRet is not null) then + aggrval := dbms_rlmgr.get_aggregate_value ('OrderMgmtRC', po_evtid, + rlm$rule.poAggrRet); + aggrval := ' with '||rlm$rule.poAggrRet||' equal to '||aggrval; + end if; + dbms_output.put_line (mesg||aggrval); +end; +/ + +-- +-- 4. User defined functions for the rules +-- +create or replace function CustomerType (custId int) return VARCHAR2 is +begin + return 'GOLD'; +end; +/ + +exec dbms_rlmgr.add_functions('OrderMgmt','CustomerType'); + +-- +-- 5. Add rules +-- +insert into OrderMgmtRC (rlm$ruleid, actionType, actionParam, rlm$ruledesc, + rlm$rulecond) values +('High priority Order redirect', 'REDIRECT','HIGH_PRIORITY_QUEUE', + 'Route the order to a high priority queue if it is large order from a Gold Customer', +' + CustomerType(customerid) = ''GOLD'' and amount > 10000 +'); + +insert into OrderMgmtRC (rlm$ruleid, actionType, actionParam, rlm$ruledesc, + rlm$rulecond) values +('Delayed Order redirect', 'REDIRECT','HIGH_PRIORITY_QUEUE', + 'Route the order to a high priority queue if there is a potential for it to get delayed', +' + + CustomerType(customerid) = ''GOLD'' + + + + +'); + +insert into OrderMgmtRC (rlm$ruleid, actionType, actionParam, rlm$ruledesc, + rlm$rulecond) values +('Large number of orders promo', 'PROMOTION','ELITE_STATUS', + 'Offer an elite status to a customer if he submited a large number of orders, each with a minimum of 10000 dollars', + ' + + amount > 10000 + +'); + + +insert into OrderMgmtRC (rlm$ruleid, actionType, actionParam, rlm$ruledesc, + rlm$rulecond) values +('Expanding customer', 'PROMOTION', 'LARGE_ORDER', +'Offer a promotion for ordering in bulk if the average size of the last 10 orders is over 20000 dollars', +' + +'); + +insert into OrderMgmtRC (rlm$ruleid, actionType, actionParam, rlm$ruledesc, + rlm$rulecond) values +('Promo on Total size of orders in 10 days', 'PROMOTION','ELITE_STATUS', + 'Offer an elite status to a customer if he submited a large number of orders, each with a minimum of 1000 dollars, in a 30 day period', +' + + amount > 1000 + +'); + +insert into OrderMgmtRC (rlm$ruleid, actionType, actionParam, rlm$ruledesc, + rlm$rulecond) values +('Completed order', 'UPDATE_ORDER_STATUS','COMPLETE', +'Compare the number of items ordered and the items shipped to mark the order complete', +' + + + + itemtype != ''Reusable Container'' + + +'); + +insert into OrderMgmtRC (rlm$ruleid, actionType, actionParam, rlm$ruledesc, + rlm$rulecond) values +('Ready to ship', 'READY_TO_SHIP', 'LOADED_TRUCK', +'Signal readiness to ship when the truck is at least 90% full', +' + + status = ''Loading'' + + itemtype = ''Reusable Container'' + + +'); + +commit; + +-- +-- 6. Add events +-- +set serveroutput on; +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(purchaseorder(100, 300, 51, 8, 11000, '25-OCT-2006'))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(purchaseorder(101, 300, 52, 8, 111000, '25-OCT-2006'))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(purchaseorder(102, 300, 52, 8, 11000, '25-OCT-2006'))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(purchaseorder(103, 300, 54, 8, 111000, '25-OCT-2006'))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(purchaseorder(104, 300, 55, 8, 11000, '25-OCT-2006'))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(purchaseorder(105, 300, 56, 8, 111000, '25-OCT-2006'))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(purchaseorder(106, 300, 56, 8, 11000, '25-OCT-2006'))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(purchaseorder(107, 300, 57, 8, 111000, '25-OCT-2006'))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(purchaseorder(108, 300, 58, 8, 11000, '25-OCT-2006'))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(purchaseorder(109, 300, 59, 8, 111000, '25-OCT-2006'))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(purchaseorder(110, 300, 59, 8, 11000, '25-OCT-2006'))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(purchaseorder(111, 300, 59, 8, 111000, '25-OCT-2006'))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(purchaseorder(112, 300, 59, 8, 11000, '25-OCT-2006'))); + +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(TruckAtDock(900, sysdate, 'Loading', 6))); + +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(shipitem(401, 'Reusable Container', 100, 900))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(shipitem(402, 'Reusable Container', 101, 900))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(shipitem(403, 'Reusable Container', 102, 900))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(shipitem(404, 'Reusable Container', 103, 900))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(shipitem(405, 'Reusable Container', 104, 900))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(shipitem(406, 'Reusable Container', 105, 900))); +exec dbms_rlmgr.process_rules('OrderMgmtRC',sys.anydata.convertobject(shipitem(407, 'Reusable Container', 107, 900))); + +connect / as sysdba; +drop user ruldemo cascade; + +exit; diff --git a/sadv91.sql b/sadv91.sql new file mode 100644 index 0000000..ab02f14 --- /dev/null +++ b/sadv91.sql @@ -0,0 +1,246 @@ +Rem +Rem $Header: sadv91.sql 07-jun-2004.13:50:01 lburgess Exp $ +Rem +Rem sadv91.sql +Rem +Rem Copyright (c) 2000, 2004, Oracle. All rights reserved. +Rem +Rem NAME +Rem sadv91.sql - Summary Advisor demo for Oracle 9i +Rem +Rem DESCRIPTION +Rem This file demonstrates the use of the Oracle 9i Summary Advisor +Rem API calls +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem lburgess 06/07/04 - add order by clause +Rem btao 03/02/01 - Change Interfaces +Rem btao 10/31/00 - Created +Rem +Rem ==================================================================== +Rem Setup for demos +Rem ==================================================================== +connect system/manager +grant select on mview_recommendations to sh; +grant select on mview_workload to sh; +grant select on mview_filter to sh; +grant alter system to sh; +disconnect + +Rem ******************************************************************** +Rem * Demo 1: Materialized View Recommendation With User Workload * +Rem ******************************************************************** +Rem ==================================================================== +Rem Step 1. Define user workload table and add artificial workload +Rem queries, and gather stats for schema objects +Rem ==================================================================== +connect sh/sh +@sadvuwk.sql +insert into advisor_user_workload values +( + 'select sum(s.quantity_sold) + from sales s, products p + where s.prod_id = p.prod_id and + p.prod_category = ''Boys'' + group by p.prod_category + ', + 'SH', 'app1', 10, NULL, 5, NULL, NULL, NULL, NULL +) +/ +insert into advisor_user_workload values +( + 'select sum(s.amount_sold) + from sales s, products p + where s.prod_id = p.prod_id and + p.prod_category = ''Girls'' + group by p.prod_category + ', + 'SH', 'app1', 10, NULL, 6, NULL, NULL, NULL, NULL +) +/ +insert into advisor_user_workload values +( + 'select sum(quantity_sold) + from sales s, products p + where s.prod_id = p.prod_id and + p.prod_category = ''Men'' + group by p.prod_category + ', + 'SH', 'app1', 11, NULL, 3, NULL, NULL, NULL, NULL +) +/ +insert into advisor_user_workload values +( + 'select sum(quantity_sold) + from sales s, products p + where s.prod_id = p.prod_id and + p.prod_category in (''Women'', ''Men'') + group by p.prod_category + ', + 'SH', 'app1', 1, NULL, 8, NULL, NULL, NULL, NULL +) +/ +execute dbms_stats.gather_schema_stats('SH', 1); + +Rem ==================================================================== +Rem Step 2. Create a new identifier to identify a new collection in the +Rem internal repository and load the user-defined workload into Rem the workload collection +Rem ==================================================================== +variable workload_id number; +execute dbms_olap.create_id(:workload_id); +execute dbms_olap.load_workload_user(:workload_id,- + dbms_olap.workload_new,- + dbms_olap.filter_none, 'SH', 'ADVISOR_USER_WORKLOAD'); +select count(*) from system.mview_workload + where workloadid = :workload_id; + +Rem ==================================================================== +Rem Step 3. Create a new identifier to identify a new filter object. Add +Rem two filter items such that the filter can filter out +Rem workload queries with priority >= 5 and frequency <= 10 +Rem ==================================================================== +variable filter_id number; +execute dbms_olap.create_id(:filter_id); +execute dbms_olap.add_filter_item(:filter_id, 'PRIORITY',- + NULL, 5, NULL, NULL, NULL); +execute dbms_olap.add_filter_item(:filter_id, 'FREQUENCY',- + NULL, NULL, 10, NULL, NULL); +select count(*) from system.mview_filter + where filterid = :filter_id; + +Rem ==================================================================== +Rem Step 4. Recommend materialized views with part of the previous +Rem workload collection that satisfy the filter conditions. +Rem Create a new identifier to identify the recommendation +Rem output. +Rem ==================================================================== +variable run_id number; +execute dbms_olap.create_id(:run_id); +execute dbms_olap.recommend_mview_strategy(:run_id, :workload_id,- + :filter_id, 100000, 100, NULL, NULL); +select count(*) from system.mview_recommendations; + +Rem ==================================================================== +Rem Step 5. Generate HTML reports on the output +Rem Notes: The user must have the priviledge to grant directory +Rem access permission. The commented out example +Rem only applies to UNIX systems. Your specific +Rem operating system may require different path name +Rem specification. +Rem ==================================================================== +Rem execute dbms_java.grant_permission('SH',- +Rem 'java.io.FilePermission', '/tmp', 'read,write'); +Rem +Rem execute dbms_olap.generate_mview_report('/tmp/output1.html',- +Rem :run_id, dbms_olap.rpt_recommendation); + +Rem ==================================================================== +Rem Step 6. Cleanup current output, filter and workload collection +Rem from the internal repository, truncate the user workload +Rem table for new user workloads. +Rem ==================================================================== +execute dbms_olap.purge_results(:run_id); +execute dbms_olap.purge_filter(:filter_id); +execute dbms_olap.purge_workload(:workload_id); +select count(*) from system.mview_workload + where workloadid = :workload_id; +truncate table advisor_user_workload; + +drop table advisor_user_workload; +disconnect + +Rem ******************************************************************** +Rem * Demo 2: Materialized View Recommendation With SQL Cache * +Rem ******************************************************************** +connect sh/sh + +Rem ==================================================================== +Rem Step 1. Clear SQL cache and run some applications or some SQL +Rem queries, so that the Oracle SQL cache is populated with +Rem target queries. +Rem ==================================================================== +alter system flush shared_pool; +select sum(s.quantity_sold) +from sales s, products p +where s.prod_id = p.prod_id + group by p.prod_category + order by p.prod_category; + +select sum(s.amount_sold) +from sales s, products p +where s.prod_id = p.prod_id +group by p.prod_category +order by p.prod_category; + +select t.calendar_month_desc, sum(s.amount_sold) as dollars +from sales s, times t +where s.time_id = t.time_id +group by t.calendar_month_desc +order by t.calendar_month_desc; + +select t.calendar_month_desc, sum(s.amount_sold) as dollars +from sales s, times t +where s.time_id = t.time_id +group by t.calendar_month_desc +order by t.calendar_month_desc; + +Rem ==================================================================== +Rem Step 2. Create a new identifier to identify a new collection in the +Rem internal repository and grab a snapshot of the Oracle SQL +Rem cache into the new collection +Rem ==================================================================== +execute dbms_olap.create_id(:workload_id); +execute dbms_olap.load_workload_cache(:workload_id,- + dbms_olap.workload_new,- + dbms_olap.filter_none, NULL, 1); +select count(*) from system.mview_workload + where workloadid = :workload_id; + +Rem ==================================================================== +Rem Step 3. Recommend materialized views with all of the workload +Rem collection and no filtering +Rem ==================================================================== +execute dbms_olap.create_id(:run_id); +execute dbms_olap.recommend_mview_strategy(:run_id, :workload_id,- + dbms_olap.filter_none, 100000, 100, NULL, NULL); +select count(*) from system.mview_recommendations; + +Rem ==================================================================== +Rem Step 4. Generate HTML reports on the output +Rem ==================================================================== +Rem execute dbms_olap.generate_mview_report('/tmp/output2.html',- +Rem :run_id, dbms_olap.rpt_recommendation); + +Rem ==================================================================== +Rem Step 5. Evaluate materialized views +Rem ==================================================================== +execute dbms_olap.create_id(:run_id); +execute dbms_olap.evaluate_mview_strategy(- + :run_id, :workload_id, dbms_olap.filter_none); + +Rem ==================================================================== +Rem Step 6. Generate HTML reports on the output +Rem ==================================================================== +Rem execute dbms_olap.generate_mview_report('/tmp/output3.html',- +Rem :run_id, dbms_olap.rpt_usage); + +Rem ==================================================================== +Rem Step 7. Cleanup current output, and workload collection +Rem from the internal repository +Rem ==================================================================== +execute dbms_olap.purge_results(:run_id); +execute dbms_olap.purge_workload(:workload_id); +disconnect + +Rem ==================================================================== +Rem Cleanup for demos +Rem ==================================================================== +connect system/manager +revoke select on mview_recommendations from sh; +revoke select on mview_workload from sh; +revoke select on mview_filter from sh; +revoke alter system from sh; +disconnect diff --git a/sadvdemo.sql b/sadvdemo.sql new file mode 100644 index 0000000..5893726 --- /dev/null +++ b/sadvdemo.sql @@ -0,0 +1,301 @@ +rem +rem $Header: sadvdemo.sql 05-sep-00.17:17:16 sramakri Exp $ +rem +rem sadvdemo.sql +rem +rem Copyright (c) 1998, 1999,, 2000 Oracle Corporation. All rights reserved. +rem +rem NAME +rem sadvdemo.sql - Demo package used to pretty-print recommendations +rem of the Summary Advisor. +rem +rem +rem DESCRIPTION +rem The Summary Advisor is a component of the DBMS_OLAP package and +rem contains the RECOMMEND_MV and RECOMMEND_MV_W function which +rem recommend materialized views (summaries). The recommendations are +rem written to a table MVIEW$_RECOMMENDATIONS in the user's schema. +rem The function PRETTYPRINT_RECOMMENDATIONS in this package presents +rem the information from that table in a more readable format. +rem +rem +rem PACKAGE INSTALL NOTES +rem +rem o Install/load this package in the Oracle USER where you wish +rem to run the Summary Advisor +rem +rem +rem USAGE NOTES +rem +rem o Run RECOMMEND_MV or RECOMMEND_MV_W as appropriate to compute the +rem the recommendations +rem +rem o To enable outpiut from the demo package, use the SET SERVEROUTPUT +rem command as follows: +rem +rem SET SERVEROUTPUT ON SIZE 1000000 +rem +rem o Execute procedure DEMO_SUMADV.PRETTYPRINT_RECOMMENDATIONS as: +rem +rem execute DEMO_SUMADV.PRETTYPRINT_RECOMMENDATIONS; +rem +rem +rem MODIFIED (MM/DD/YY) +rem sramakri 09/05/00 - format numbers +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem sramakri 10/15/98 - Summary Advisor pretty-printer script +rem sramakri 10/15/98 - Created +rem + +rem create tables in user schema; if tables already exist +rem these create's will fail; that is okay + +create table mview$_recommendations ( + recommendation_number integer primary key, + recommended_action varchar2(6), + summary_owner varchar(30), + summary_name varchar(30), + group_by_columns varchar2(2000), + where_clause varchar2(2000), + from_clause varchar2(2000), + measures_list varchar2(2000), + storage_in_bytes number, + pct_performance_gain number, + benefit_to_cost_ratio number + ); + +create table mview$_evaluations ( + summary_owner varchar(30), + summary_name varchar(30), + rank integer, + storage_in_bytes number, + frequency number, + cumulative_benefit number, + benefit_to_cost_ratio number + ); + + +CREATE OR REPLACE PACKAGE demo_sumadv IS + + PROCEDURE prettyprint_recommendations; + PROCEDURE prettyprint_evaluations; + +END demo_sumadv; +/ + +CREATE OR REPLACE PACKAGE BODY demo_sumadv AS + + + PROCEDURE printbuff(buff in varchar2) + IS + para demo_sumadv_wrap.paragraph_tabletype; + loc_lines integer; + loc_line_length integer := 76; + j BINARY_INTEGER; + BEGIN + demo_sumadv_wrap.to_paragraph(buff, loc_line_length, para, loc_lines); + dbms_output.put_line(para(1)); + for j in 2 .. loc_lines loop + dbms_output.put_line(' ' || para(j)); + end loop; + END printbuff; + + + PROCEDURE print_new_sum_rec(group_by_columns in varchar2, + measures_list in varchar2, + from_clause in varchar2, where_clause in varchar2) + IS + buff VARCHAR2(5000); + BEGIN + buff := 'SELECT ' || group_by_columns || ', ' || measures_list; + printbuff(buff); + buff := 'FROM ' || from_clause; + printbuff(buff); + if where_clause is not null then + buff := 'WHERE ' || where_clause; + printbuff(buff); + end if; + buff := 'GROUP BY ' || group_by_columns; + printbuff(buff); + END print_new_sum_rec; + + PROCEDURE prettyprint_recommendations + IS + CURSOR c_cur IS + SELECT recommendation_number, recommended_action, + summary_owner, summary_name, group_by_columns, + measures_list, from_clause, where_clause, + storage_in_bytes, pct_performance_gain, benefit_to_cost_ratio + FROM MVIEW$_RECOMMENDATIONS + ORDER BY recommendation_number; + BEGIN + FOR c_rec IN c_cur LOOP + + dbms_output.put_line(' '); + dbms_output.put_line( + 'Recommendation Number = ' || c_rec.recommendation_number); + + IF c_rec.summary_name is null then + dbms_output.put_line('Recommended Action is CREATE new summary:'); + ELSE + dbms_output.put_line('Recommended Action is ' || + c_rec.recommended_action || ' existing summary ' || + c_rec.summary_owner || '.' || c_rec.summary_name); + END IF; + + IF c_rec.summary_name is null then + print_new_sum_rec(c_rec.group_by_columns, c_rec.measures_list, + c_rec.from_clause, c_rec.where_clause); + END IF; + + IF c_rec.storage_in_bytes is null then + dbms_output.put_line('Storage in bytes is null'); + ELSE + dbms_output.put_line( + 'Storage in bytes is ' || to_char(c_rec.storage_in_bytes, '9.99EEEE')); + END IF; + + IF c_rec.pct_performance_gain is null then + dbms_output.put_line('Percent performance gain is null'); + ELSE + dbms_output.put_line( + 'Percent performance gain is ' || + to_char(c_rec.pct_performance_gain, '9.99EEEE')); + END IF; + + IF c_rec.benefit_to_cost_ratio is null then + dbms_output.put_line('Benefit-to-cost ratio is null'); + ELSE + dbms_output.put_line( + 'Benefit-to-cost ratio is ' || + to_char(c_rec.benefit_to_cost_ratio, '9.99EEEE')); + END IF; + + + END LOOP; + END prettyprint_recommendations; + + PROCEDURE prettyprint_evaluations + IS + CURSOR c_cur IS + SELECT summary_owner, summary_name, rank, + storage_in_bytes, frequency, cumulative_benefit, benefit_to_cost_ratio + FROM MVIEW$_EVALUATIONS + ORDER BY rank; + BEGIN + FOR c_rec IN c_cur LOOP + + dbms_output.put_line(' '); + dbms_output.put_line( + 'Rank = ' || c_rec.rank || ' Summmary = ' || + c_rec.summary_owner || '.' || c_rec.summary_name); + + dbms_output.put_line( + 'Frequency is ' || c_rec.frequency); + + dbms_output.put_line('Storage_in_bytes = ' || + to_char(c_rec.storage_in_bytes, '9.99EEEE')); + dbms_output.put_line('Cumulative_benefit = ' || + to_char(c_rec.cumulative_benefit, '9.99EEEE')); + dbms_output.put_line('Benefit-to-cost ratio is ' || + to_char(c_rec.benefit_to_cost_ratio, '9.99EEEE')); + + dbms_output.put_line(' '); + + + END LOOP; + END prettyprint_evaluations; + +END demo_sumadv; + +/ + +CREATE OR REPLACE PACKAGE demo_sumadv_wrap +IS + TYPE paragraph_tabletype IS TABLE OF VARCHAR2 (80) + INDEX BY BINARY_INTEGER; + + PROCEDURE to_paragraph + (text_in IN VARCHAR2, + line_length IN INTEGER, + paragraph_out IN OUT paragraph_tabletype, + num_lines_out IN OUT INTEGER, + word_break_at_input IN VARCHAR2 := ' ', + line_break_at_in IN VARCHAR2 := NULL); +END demo_sumadv_wrap; +/ + +create or replace PACKAGE BODY demo_sumadv_wrap +IS + replace_string VARCHAR2(100) := NULL; + + word_break_at_in constant char := ' '; + + + PROCEDURE set_replace_string IS + BEGIN + replace_string := RPAD ('@', LENGTH (word_break_at_in), '@'); + END; + + PROCEDURE find_last_delim_loc (line_in IN VARCHAR2, loc_out OUT INTEGER) + IS + v_line VARCHAR2(1000) := line_in; + BEGIN + IF word_break_at_in IS NOT NULL THEN + v_line := TRANSLATE (line_in, word_break_at_in, replace_string); + END IF; + loc_out := INSTR (v_line, '@', -1); + END; + + PROCEDURE to_paragraph + (text_in IN VARCHAR2, + line_length IN INTEGER, + paragraph_out IN OUT paragraph_tabletype, + num_lines_out IN OUT INTEGER, + word_break_at_input IN VARCHAR2 := ' ', + line_break_at_in IN VARCHAR2 := NULL) + IS + len_text INTEGER := LENGTH (text_in); + line_start_loc INTEGER := 1; + line_end_loc INTEGER := 1; + last_space_loc INTEGER; + curr_line VARCHAR2(80); + BEGIN + set_replace_string; + + IF len_text IS NULL THEN + num_lines_out := 0; + ELSE + num_lines_out := 1; + LOOP + EXIT WHEN line_end_loc > len_text; + line_end_loc := LEAST (line_end_loc + line_length, len_text + 1); + + /* get the next possible line of text */ + curr_line := SUBSTR (text_in || ' ', + line_start_loc, line_length + 1); + + /* find the last space in this section of the line */ + find_last_delim_loc (curr_line, last_space_loc); + + /* When NO spaces exist, use the full current line*/ + /* otherwise, cut the line at the space. */ + IF last_space_loc > 0 THEN + line_end_loc := line_start_loc + last_space_loc; + END IF; + + /* Add this line to the paragraph */ + paragraph_out (num_lines_out) := + substr (text_in, + line_start_loc, + line_end_loc - line_start_loc); + + num_lines_out := num_lines_out + 1; + line_start_loc := line_end_loc; + END LOOP; + num_lines_out := num_lines_out - 1; + END IF; + END to_paragraph; +END demo_sumadv_wrap; +/ + diff --git a/sadvuwk.sql b/sadvuwk.sql new file mode 100644 index 0000000..fc4bca5 --- /dev/null +++ b/sadvuwk.sql @@ -0,0 +1,49 @@ +Rem +Rem $Header: template.sql 06-feb-96.13:23:14 kosinski Exp $ +Rem +Rem sadvuwk.sql +Rem +Rem Copyright (c) Oracle Corporation 2000. All Rights Reserved. +Rem +Rem NAME +Rem sadvuwk.SQL - Sample script to create a user-workload table +Rem +Rem DESCRIPTION +Rem This is a simple example of creating a user-defined workload table from +Rem which Summary Advisor can extract a workload. +Rem +Rem NOTES +Rem The indexes are optional; however, if you plan on applying workload filters +Rem to the load workload operation, then you should create indexes on the +Rem most significant filter columns fo the user workload. +Rem +Rem The QUERY and OWNER columns are the only required columns for a user-supplied +Rem workload. +Rem +Rem If the QUERY column will contain SQL statements longer than 2000 characters, +Rem then it is acceptable to create the column as a LONG datatype. +Rem +Rem MODIFIED (MM/DD/YY) +Rem gssmith 11/06/00 - Created +Rem + +CREATE TABLE advisor_user_workload + ( + query varchar2(2000), /* full sql text */ + owner varchar(30), /* user submitting the query */ + application varchar(30), /* application name */ + frequency number, /* query frequency */ + lastuse date, /* lastuse date of the query */ + priority number, /* priority of the query */ + responsetime number, /* query response time */ + resultsize number, /* result size in bytes */ + sql_hash number, /* server generated hash */ + sql_addr raw(4) /* lib-cache address */ + ); + +CREATE INDEX adv_uwk_idx_01 + ON advisor_user_workload (application,lastuse); + +CREATE INDEX adv_uwk_idx_02 + ON advisor_user_workload (owner,lastuse); + diff --git a/smdim.sql b/smdim.sql new file mode 100644 index 0000000..d22d21c --- /dev/null +++ b/smdim.sql @@ -0,0 +1,362 @@ +rem +rem $Header: smdim.sql 13-feb-02.14:20:58 twtong Exp $ +rem +rem smdim.sql +rem +rem Copyright (c) 1998, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem smdim.sql - describe dimensions +rem +rem DESCRIPTION +rem The procedures here describe dimensions in a user's schema. +rem PRINT_DIM shows information about a specified dimension; +rem PRINT_ALLDIMS shows information about all the dimensions +rem accessible to the user. +rem +rem NOTES +rem These routines are similar to the Server Manager builtin +rem "describe" command which displays information about tables +rem and packages. Hence they should be useful to DBA's using +rem a command-line interface. For developers, these routines are +rem useful because they illustrate techniques to navigate the +rem various catalog views related to dimensions. +rem +rem +rem MODIFIED (MM/DD/YY) +rem twtong 02/13/02 - add attribute_name to print_attributes +rem jraitto 04/14/00 - fix bugs 1268813, 845372 +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem sramakri 10/28/98 - make it JOIN KEY, not "JOINKEY" +rem sramakri 10/28/98 - cleanup +rem sramakri 10/28/98 - PL/SQL procedures to "describe" dimensions +rem sramakri 10/28/98 - Created +rem + +CREATE OR REPLACE PACKAGE demo_dim IS + + PROCEDURE print_dim(in_dim_name varchar2); + PROCEDURE print_alldims; + +END demo_dim; +/ + +CREATE OR REPLACE PACKAGE BODY demo_dim AS + + + PROCEDURE print_attributes(in_owner varchar2, in_dimension_name varchar2) + IS + CURSOR c_cur IS + select attribute_name, level_name, column_name + from all_dim_attributes + where + in_owner = owner and + in_dimension_name = dimension_name + order by level_name, column_name; + + child_table_owner varchar2(32); + child_table_name varchar2(32); + + BEGIN + FOR c_rec IN c_cur LOOP + dbms_output.put(' '); + dbms_output.put('ATTRIBUTE ' || c_rec.attribute_name || + ' LEVEL ' || c_rec.level_name || + ' DETERMINES '); + + select dl.detailobj_owner, dl.detailobj_name + into child_table_owner, child_table_name + from all_dim_levels dl + where in_owner = dl.owner and + in_dimension_name = dl.dimension_name and + c_rec.level_name = dl.level_name; + + dbms_output.put_line(child_table_owner || '.' || child_table_name + || '.' || c_rec.column_name); + END LOOP; + END print_attributes; + + + + + PROCEDURE get_joinkey(in_owner varchar2, in_dimension_name varchar2, + in_hierarchy_name varchar2, in_jkid integer, + jkchildcolms out varchar2, + num_jkchildcolms out integer, parent_level out varchar2) + IS + CURSOR c_cur IS + select key_position, child_join_column, level_name + from all_dim_join_key + where in_jkid = dim_key_id and + in_owner = owner and + in_dimension_name = dimension_name and + in_hierarchy_name = hierarchy_name + order by key_position; + BEGIN + num_jkchildcolms := 0; + FOR c_rec IN c_cur LOOP + + num_jkchildcolms := num_jkchildcolms + 1; + parent_level := c_rec.level_name; + + if num_jkchildcolms > 1 + then + jkchildcolms := jkchildcolms || ', ' || c_rec.child_join_column; + else + jkchildcolms := c_rec.child_join_column; + end if; + + END LOOP; + END get_joinkey; + + + + PROCEDURE print_children(in_owner varchar2, in_dimension_name varchar2, + in_hierarchy_name varchar2, children out varchar2, + num_children out integer) + IS + CURSOR c_cur IS + select dco.position, dco.child_level_name, dco.parent_level_name + from all_dim_child_of dco + where in_owner = dco.owner and + in_dimension_name = dco.dimension_name and + in_hierarchy_name = dco.hierarchy_name + order by dco.position; + BEGIN + num_children := 0; + FOR c_rec IN c_cur LOOP + + num_children := num_children + 1; + + if num_children = 1 + then + dbms_output.put_line(' ' || c_rec.child_level_name); + end if; + + children := 'CHILD OF ' || c_rec.parent_level_name; + + dbms_output.put_line(' ' || children); + + + END LOOP; + END print_children; + + + + + PROCEDURE print_hierarchies(in_owner varchar2, in_dimension_name varchar2) + IS + CURSOR c_cur IS + select hierarchy_name + from all_dim_hierarchies + where + in_owner = owner and + in_dimension_name = dimension_name + order by hierarchy_name; + + num_children integer; + children varchar2(2000); + num_jkcolms integer; + jkcolms varchar2(2000); + in_hierarchy_name varchar2(32); + child_table_owner varchar2(32); + child_table_name varchar2(32); + parent_level varchar2(32); + CURSOR c_jkcur IS + select dco.join_key_id, dco.child_level_name + from all_dim_child_of dco + where in_owner = dco.owner and + in_dimension_name = dco.dimension_name and + in_hierarchy_name = dco.hierarchy_name and + dco.join_key_id is not null + order by dco.position; + BEGIN + FOR c_rec IN c_cur LOOP + + dbms_output.put(' '); + dbms_output.put_line('HIERARCHY ' || c_rec.hierarchy_name || + ' ( '); + print_children(in_owner, in_dimension_name, c_rec.hierarchy_name, + children, num_children); + in_hierarchy_name := c_rec.hierarchy_name; + + for c_jkrec in c_jkcur loop + + select dl.detailobj_owner, dl.detailobj_name + into child_table_owner, child_table_name + from all_dim_levels dl + where in_owner = dl.owner and + in_dimension_name = dl.dimension_name and + c_jkrec.child_level_name = dl.level_name; + + get_joinkey(in_owner, in_dimension_name, in_hierarchy_name, + c_jkrec.join_key_id, + jkcolms, num_jkcolms, parent_level); + + dbms_output.put(' '); + dbms_output.put('JOIN KEY '); + + if num_jkcolms > 1 + then + dbms_output.put('('); + end if; + + dbms_output.put(child_table_owner || '.' || child_table_name + || '.' || jkcolms); + + if num_jkcolms > 1 + then + dbms_output.put(')'); + end if; + + dbms_output.put_line(' REFERENCES ' || parent_level); + + end loop; + + dbms_output.put_line(' )'); + + END LOOP; + END print_hierarchies; + + + + + + PROCEDURE get_segments(in_owner varchar2, in_dimension_name varchar2, + in_level_name varchar2, segments out varchar2, + num_segments out integer) + IS + CURSOR c_cur IS + select dlk.key_position, dlk.column_name + from all_dim_level_key dlk + where in_owner = dlk.owner and + in_dimension_name = dlk.dimension_name and + in_level_name = level_name + order by dlk.key_position; + BEGIN + num_segments := 0; + FOR c_rec IN c_cur LOOP + + num_segments := num_segments + 1; + + if num_segments > 1 + then + segments := segments || ', ' || c_rec.column_name; + else + segments := c_rec.column_name; + end if; + + END LOOP; + END get_segments; + + + + + PROCEDURE print_levels(in_owner varchar2, in_dimension_name varchar2) + IS + CURSOR c_cur IS + select level_name, detailobj_owner, detailobj_name + from all_dim_levels + where + in_owner = owner and + in_dimension_name = dimension_name + order by owner, dimension_name, level_name; + num_segments integer; + segments varchar2(2000); + BEGIN + FOR c_rec IN c_cur LOOP + + dbms_output.put(' '); + dbms_output.put('LEVEL ' || c_rec.level_name || + ' IS '); + + get_segments(in_owner, in_dimension_name, c_rec.level_name, + segments, num_segments); + + if num_segments > 1 + then + dbms_output.put('('); + end if; + + dbms_output.put(c_rec.detailobj_owner || '.' || c_rec.detailobj_name + || '.' || segments); + + if num_segments > 1 + then + dbms_output.put(')'); + end if; + + dbms_output.put_line(' '); + + END LOOP; + END print_levels; + + + + PROCEDURE print_dim(in_dim_name varchar2) + IS + CURSOR c_cur IS + select owner, dimension_name + from all_dimensions + where owner = user + and decode(substr(trim(in_dim_name),1,1),'"', + trim('"' from trim(in_dim_name)), + trim(upper(in_dim_name))) + = dimension_name + order by owner, dimension_name; + counter integer; + BEGIN + counter := 0; + FOR c_rec IN c_cur LOOP + + counter := counter + 1; + dbms_output.put(' '); + dbms_output.put_line('DIMENSION ' || c_rec.owner || '.' + || c_rec.dimension_name ); + + print_levels( c_rec.owner, c_rec.dimension_name ); + dbms_output.put_line(' '); + print_hierarchies( c_rec.owner, c_rec.dimension_name ); + dbms_output.put_line(' '); + print_attributes( c_rec.owner, c_rec.dimension_name ); + dbms_output.put_line(' '); + + END LOOP; + + if counter = 0 + then + dbms_output.put_line('No such dimension present in schema'); + end if; + + END print_dim; + + + PROCEDURE print_alldims + IS + CURSOR c_cur IS + select owner, dimension_name + from all_dimensions + where invalid = 'N' + order by owner, dimension_name; + BEGIN + FOR c_rec IN c_cur LOOP + + dbms_output.put(' '); + dbms_output.put_line('DIMENSION ' || c_rec.owner || '.' + || c_rec.dimension_name ); + + print_levels( c_rec.owner, c_rec.dimension_name ); + dbms_output.put_line(' '); + print_hierarchies( c_rec.owner, c_rec.dimension_name ); + dbms_output.put_line(' '); + print_attributes( c_rec.owner, c_rec.dimension_name ); + dbms_output.put_line(' '); + + END LOOP; + END print_alldims; + + + +END demo_dim; + +/ diff --git a/smxmv1.sql b/smxmv1.sql new file mode 100644 index 0000000..0e356c2 --- /dev/null +++ b/smxmv1.sql @@ -0,0 +1,238 @@ +Rem +Rem $Header: smxmv1.sql 03-aug-2004.12:12:07 mmoy Exp $ +Rem +Rem smxmv1.sql +Rem +Rem Copyright (c) 2001, 2004, Oracle. All rights reserved. +Rem +Rem NAME +Rem smxmv1.sql +Rem +Rem DESCRIPTION +Rem This is a demo script for explain_mview(). It creates +Rem a materialized view in SALES schema and uses explain_mview() +Rem to describe its capabilities and how to enhance it. +Rem The output of explain_mview() is stored in MV_CAPABILITIES_TABLE +Rem +Rem NOTE +Rem Please run utlxmv.sql in the admin directory to create +Rem MV_CAPABILITIES_TABLE in your schema before running this +Rem demo script +Rem +Rem MODIFIED (MM/DD/YY) +Rem mmoy 08/03/04 - Fix order by. +Rem twtong 04/02/01 - review comment +Rem twtong 03/26/01 - Created +Rem +Rem ================================================================ + +CONNECT sh/sh; +SET ECHO ON; +REM ----------------------------------------------------------- +REM use explain_mview to analyze a potential materialized view +REM ----------------------------------------------------------- + +BEGIN + DBMS_MVIEW.EXPLAIN_MVIEW + ('SELECT t.calendar_month_desc, + SUM(s.amount_sold) AS dollars + FROM sales s, times t + WHERE s.time_id = t.time_id + GROUP BY t.calendar_month_desc','ID1'); +END; +/ + +SELECT SUBSTR(capability_name,1,30) capability_name, + possible, + SUBSTR(related_text,1,15) related_text, + related_num, + msgno, + SUBSTR(msgtxt,1,110) msgtxt +FROM mv_capabilities_table +ORDER BY capability_name, seq; + +TRUNCATE TABLE mv_capabilities_table; + +REM ------------------------------------------------------------------- +REM make corrections and enhancement to increase the capabilities of +REM the potential materialized view according to messages from +REM explain_mview() +REM ------------------------------------------------------------------- + +REM ------------------------------------------------------------------- +REM create materialized view log on sales, times, and products +REM ------------------------------------------------------------------- + +CREATE MATERIALIZED VIEW LOG ON sales WITH ROWID; +CREATE MATERIALIZED VIEW LOG ON times; + +BEGIN + DBMS_MVIEW.EXPLAIN_MVIEW + ('SELECT t.calendar_month_desc, + SUM(s.amount_sold) AS dollars + FROM sales s, times t + WHERE s.time_id = t.time_id + GROUP BY t.calendar_month_desc','ID2'); +END; +/ + +SELECT SUBSTR(capability_name,1,30) capability_name, + possible, + SUBSTR(related_text,1,15) related_text, + related_num, + msgno, + SUBSTR(msgtxt,1,110) msgtxt +FROM mv_capabilities_table +ORDER BY seq; + +TRUNCATE TABLE mv_capabilities_table; + +REM ---------------------------------------------------------------- +REM make more corrections on the materialized view log suggested +REM by explain_mview() +REM ---------------------------------------------------------------- + +DROP MATERIALIZED VIEW LOG ON sales; +DROP MATERIALIZED VIEW LOG ON times; +CREATE MATERIALIZED VIEW LOG ON sales WITH ROWID (time_id, amount_sold) + INCLUDING NEW VALUES; +CREATE MATERIALIZED VIEW LOG ON times WITH ROWID (time_id, calendar_month_desc) + INCLUDING NEW VALUES; + +REM ------------------------------------------------------------------- +REM modify the select statement in the potential materialized view +REM to enhance the capabilities +REM 1) use PMARKER in the select and group by list to enable +REM PCT on sales +REM 2) add COUNT(*) and COUNT(amount) in the select list to +REM enhance fast refresh capabilities +REM ------------------------------------------------------------------- + +BEGIN + DBMS_MVIEW.EXPLAIN_MVIEW + ( 'SELECT DBMS_MVIEW.PMARKER(s.rowid), + t.calendar_month_desc, + COUNT(*) AS cnt_str, + COUNT(s.amount_sold) AS cnt_amt, + SUM(s.amount_sold) AS dollars + FROM sales s, times t + WHERE s.time_id = t.time_id + GROUP BY DBMS_MVIEW.PMARKER(s.rowid), + t.calendar_month_desc','ID3'); +END; +/ + +SELECT SUBSTR(capability_name,1,30) capability_name, + possible, + SUBSTR(related_text,1,15) related_text, + related_num, + msgno, + SUBSTR(msgtxt,1,110) msgtxt +FROM mv_capabilities_table +ORDER BY seq; + +TRUNCATE TABLE mv_capabilities_table; + +REM ------------------------------------------------------------------- +REM re-create the materialized log to include sequence# +REM ------------------------------------------------------------------- + +DROP MATERIALIZED VIEW LOG ON sales; +DROP MATERIALIZED VIEW LOG ON times; +CREATE MATERIALIZED VIEW LOG ON sales WITH ROWID, SEQUENCE (time_id, amount_sold) + INCLUDING NEW VALUES; +CREATE MATERIALIZED VIEW LOG ON times WITH ROWID, SEQUENCE (time_id, calendar_month_desc) + INCLUDING NEW VALUES; + +BEGIN + DBMS_MVIEW.EXPLAIN_MVIEW + ( 'SELECT DBMS_MVIEW.PMARKER(s.rowid), + t.calendar_month_desc, + COUNT(*) AS cnt_str, + COUNT(s.amount_sold) AS cnt_amt, + SUM(s.amount_sold) AS dollars + FROM sales s, times t + WHERE s.time_id = t.time_id + GROUP BY DBMS_MVIEW.PMARKER(s.rowid), + t.calendar_month_desc','ID4'); +END; +/ + +SELECT SUBSTR(capability_name,1,30) capability_name, + possible, + SUBSTR(related_text,1,15) related_text, + related_num, + msgno, + SUBSTR(msgtxt,1,110) msgtxt +FROM mv_capabilities_table +ORDER BY seq; + +TRUNCATE TABLE mv_capabilities_table; + +REM ------------------------------------------------------------------- +REM create the materialized view +REM ------------------------------------------------------------------- + +CREATE MATERIALIZED VIEW month_sales_mv + BUILD IMMEDIATE + REFRESH FORCE + DISABLE QUERY REWRITE + AS + SELECT DBMS_MVIEW.PMARKER(s.rowid), + t.calendar_month_desc, + COUNT(*) AS cnt_str, + COUNT(s.amount_sold) AS cnt_amt, + SUM(s.amount_sold) AS dollars + FROM sales s, times t + WHERE s.time_id = t.time_id + GROUP BY DBMS_MVIEW.PMARKER(s.rowid), + t.calendar_month_DESC; + +REM ---------------------------------------------------------------- +REM use explain_mview() on the materialized view that has just been +REM created to check if it has all the capabilities +REM ----------------------------------------------------------------- + +EXECUTE DBMS_MVIEW.EXPLAIN_MVIEW('month_sales_mv','ID5'); + +SELECT SUBSTR(capability_name,1,30) capability_name, + possible, + SUBSTR(related_text,1,15) related_text, + related_num, + msgno, + SUBSTR(msgtxt,1,110) msgtxt +FROM mv_capabilities_table +ORDER BY seq; + +TRUNCATE TABLE mv_capabilities_table; + +REM ---------------------------------------------------------------- +REM enable query rewrite on the materialized view +REM ----------------------------------------------------------------- + +ALTER materialized VIEW month_sales_mv enable query rewrite; + +EXECUTE DBMS_MVIEW.EXPLAIN_MVIEW('month_sales_mv','ID6'); + +SELECT SUBSTR(capability_name,1,30) capability_name, + possible, + SUBSTR(related_text,1,15) related_text, + related_num, + msgno, + SUBSTR(msgtxt,1,110) msgtxt +FROM mv_capabilities_table +ORDER BY seq; + +TRUNCATE TABLE mv_capabilities_table; + +REM -------------------------------- +REM Clean up +REM -------------------------------- + +DROP MATERIALIZED VIEW month_sales_mv; +DROP MATERIALIZED VIEW LOG ON sales; +DROP MATERIALIZED VIEW LOG ON times; +DISCONNECT + + + diff --git a/smxmv2.sql b/smxmv2.sql new file mode 100644 index 0000000..62de43e --- /dev/null +++ b/smxmv2.sql @@ -0,0 +1,219 @@ +Rem +Rem $Header: smxmv2.sql 02-apr-2001.15:00:24 twtong Exp $ +Rem +Rem smxmv2.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem smxmv2.sql +Rem +Rem DESCRIPTION +Rem This is a demo script for explain_mview(). It uses +Rem explain_mview() on a potential materialized view and +Rem display its capabilities and how to enhance it. The +Rem materialized view is not created by explain_mview(). +Rem Only the select statement for the potential materialized +Rem view is used by explain_mview to analyze its capabilities +Rem The output is stored in a VARRAY +Rem +Rem MODIFIED (MM/DD/YY) +Rem twtong 04/02/01 - review comment +Rem twtong 03/26/01 - Created +Rem +REM ================================================================ + +CONNECT sh/sh; +SET ECHO ON +SET SERVEROUTPUT ON + +DECLARE + XMV_Array SYS.ExplainMVArrayType := SYS.ExplainMVArrayType(); + no_of_msgs NUMBER; + i NUMBER; +BEGIN + DBMS_OUTPUT.enable(32512); + dbms_mview.explain_mview ('SELECT t.week_ending_day, p.prod_subcategory, s.channel_id, + s.promo_id, sum(s.amount_sold) AS dollars + FROM sales s, times t, products p + WHERE s.time_id = t.time_id AND + s.prod_id = p.prod_id + GROUP BY t.week_ending_day, p.prod_subcategory, + s.channel_id, s.promo_id', + XMV_Array); + no_of_msgs := XMV_Array.count; + FOR i IN 1..no_of_msgs + LOOP + DBMS_OUTPUT.PUT_LINE(' CAPABILITY : ' || XMV_Array(i).capability_name); + DBMS_OUTPUT.PUT_LINE(' POSSIBLE : ' || XMV_Array(i).possible); + DBMS_OUTPUT.PUT_LINE(' REL_TEXT : ' || XMV_Array(i).related_text); + DBMS_OUTPUT.PUT_LINE(' REL_NUM : ' || XMV_Array(i).related_num); + DBMS_OUTPUT.PUT_LINE(' MSGNO : ' || XMV_Array(i).msgno); + DBMS_OUTPUT.PUT_LINE(' MSGTXT : ' || XMV_Array(i).msgtxt); + DBMS_OUTPUT.PUT_LINE(' '); + END LOOP; +END; +/ + +REM ------------------------------------------------------------------- +REM make corrections and enhancement to increase the capabilities of +REM the potential materialized view according to messages from +REM explain_mview() +REM ------------------------------------------------------------------- + +REM ------------------------------------------------------------------- +REM create materialized view log on sales, times, and products +REM ------------------------------------------------------------------- + +CREATE MATERIALIZED VIEW LOG ON sales WITH ROWID; +CREATE MATERIALIZED VIEW LOG ON times WITH ROWID; +CREATE MATERIALIZED VIEW LOG ON products WITH ROWID; + +REM ------------------------------------------------------------------- +REM modify the select statement to enhance the capabilities +REM 1) use PMARKER in the select and group by list to enable +REM PCT on sales +REM 2) add COUNT(*) and COUNT(amount) in the select list to +REM enhance fast refresh capabilities +REM ------------------------------------------------------------------- + +DECLARE + XMV_Array SYS.ExplainMVArrayType := SYS.ExplainMVArrayType(); + no_of_msgs NUMBER; + i NUMBER; +BEGIN + DBMS_OUTPUT.enable(32512); + dbms_mview.explain_mview ('SELECT DBMS_MVIEW.PMARKER(s.rowid), t.week_ending_day, + p.prod_subcategory, s.channel_id, s.promo_id, + COUNT(*) AS cnt_str, COUNT(s.amount_sold) AS cnt_amt, + SUM(s.amount_sold) AS dollars + FROM sales s, times t, products p + WHERE s.time_id = t.time_id AND + s.prod_id = p.prod_id + GROUP BY DBMS_MVIEW.PMARKER(s.rowid), + t.week_ending_day, p.prod_subcategory, + s.channel_id, s.promo_id', + XMV_Array); + no_of_msgs := XMV_Array.count; + FOR i IN 1..no_of_msgs + LOOP + DBMS_OUTPUT.PUT_LINE(' CAPABILITY : ' || XMV_Array(i).capability_name); + DBMS_OUTPUT.PUT_LINE(' POSSIBLE : ' || XMV_Array(i).possible); + DBMS_OUTPUT.PUT_LINE(' REL_TEXT : ' || XMV_Array(i).related_text); + DBMS_OUTPUT.PUT_LINE(' REL_NUM : ' || XMV_Array(i).related_num); + DBMS_OUTPUT.PUT_LINE(' MSGNO : ' || XMV_Array(i).msgno); + DBMS_OUTPUT.PUT_LINE(' MSGTXT : ' || XMV_Array(i).msgtxt); + DBMS_OUTPUT.PUT_LINE(' '); + END LOOP; +END; +/ + +REM ---------------------------------------------------------------- +REM make more corrections on the materialized view log suggested +REM by explain_mview() to enable all fast refresh capabilities +REM ---------------------------------------------------------------- + +DROP MATERIALIZED VIEW LOG ON sales; +CREATE MATERIALIZED VIEW LOG ON sales WITH ROWID, SEQUENCE + (time_id, prod_id, channel_id, promo_id, amount_sold) INCLUDING NEW VALUES; + +DROP MATERIALIZED VIEW LOG ON times; +CREATE MATERIALIZED VIEW LOG ON times WITH ROWID, SEQUENCE + (time_id, week_ending_day) INCLUDING NEW VALUES; + +DROP MATERIALIZED VIEW LOG ON products; +CREATE MATERIALIZED VIEW LOG ON products WITH ROWID, SEQUENCE + (prod_id, prod_subcategory) INCLUDING NEW VALUES; + +REM ---------------------------------------------------------------- +REM retry explain_mview() to see if the potential materialized view +REM has all the capabilities +REM ---------------------------------------------------------------- + +DECLARE + XMV_Array SYS.ExplainMVArrayType := SYS.ExplainMVArrayType(); + no_of_msgs NUMBER; + i NUMBER; +BEGIN + DBMS_OUTPUT.enable(32512); + dbms_mview.explain_mview ('SELECT DBMS_MVIEW.PMARKER(s.rowid), t.week_ending_day, + p.prod_subcategory, s.channel_id, s.promo_id, + COUNT(*) AS cnt_str, COUNT(s.amount_sold) AS cnt_amt, + SUM(s.amount_sold) AS dollars + FROM sales s, times t, products p + WHERE s.time_id = t.time_id AND + s.prod_id = p.prod_id + GROUP BY DBMS_MVIEW.PMARKER(s.rowid), + t.week_ending_day, p.prod_subcategory, + s.channel_id, s.promo_id', + XMV_Array); + no_of_msgs := XMV_Array.count; + FOR i IN 1..no_of_msgs + LOOP + DBMS_OUTPUT.PUT_LINE(' CAPABILITY : ' || XMV_Array(i).capability_name); + DBMS_OUTPUT.PUT_LINE(' POSSIBLE : ' || XMV_Array(i).possible); + DBMS_OUTPUT.PUT_LINE(' REL_TEXT : ' || XMV_Array(i).related_text); + DBMS_OUTPUT.PUT_LINE(' REL_NUM : ' || XMV_Array(i).related_num); + DBMS_OUTPUT.PUT_LINE(' MSGNO : ' || XMV_Array(i).msgno); + DBMS_OUTPUT.PUT_LINE(' MSGTXT : ' || XMV_Array(i).msgtxt); + DBMS_OUTPUT.PUT_LINE(' '); + END LOOP; +END; +/ + +REM ---------------------------------------------------------------- +REM create the materialized view +REM ---------------------------------------------------------------- + +CREATE MATERIALIZED VIEW week_sales_mv +BUILD IMMEDIATE +REFRESH FORCE +ENABLE QUERY REWRITE +AS +SELECT DBMS_MVIEW.PMARKER(s.rowid), t.week_ending_day, + p.prod_subcategory, s.channel_id, s.promo_id, + COUNT(*) AS cnt_str, COUNT(s.amount_sold) AS cnt_amt, + SUM(s.amount_sold) AS dollars +FROM sales s, times t, products p +WHERE s.time_id = t.time_id AND + s.prod_id = p.prod_id +GROUP BY DBMS_MVIEW.PMARKER(s.rowid), + t.week_ending_day, p.prod_subcategory, + s.channel_id, s.promo_id; + +REM ---------------------------------------------------------------- +REM use explain_mview() on the materialized view that has just +REM been created +REM ---------------------------------------------------------------- + +DECLARE + XMV_Array SYS.ExplainMVArrayType := SYS.ExplainMVArrayType(); + no_of_msgs NUMBER; + i NUMBER; +BEGIN + DBMS_OUTPUT.enable(32512); + dbms_mview.explain_mview ('week_sales_mv', XMV_Array); + no_of_msgs := XMV_Array.count; + FOR i IN 1..no_of_msgs + LOOP + DBMS_OUTPUT.PUT_LINE(' CAPABILITY : ' || XMV_Array(i).capability_name); + DBMS_OUTPUT.PUT_LINE(' POSSIBLE : ' || XMV_Array(i).possible); + DBMS_OUTPUT.PUT_LINE(' REL_TEXT : ' || XMV_Array(i).related_text); + DBMS_OUTPUT.PUT_LINE(' REL_NUM : ' || XMV_Array(i).related_num); + DBMS_OUTPUT.PUT_LINE(' MSGNO : ' || XMV_Array(i).msgno); + DBMS_OUTPUT.PUT_LINE(' MSGTXT : ' || XMV_Array(i).msgtxt); + DBMS_OUTPUT.PUT_LINE(' '); + END LOOP; +END; +/ + +REM ----------------------------------------------------------- +REM clean up +REM ----------------------------------------------------------- + +DROP MATERIALIZED VIEW LOG ON sales; +DROP MATERIALIZED VIEW LOG ON products; +DROP MATERIALIZED VIEW LOG ON times; +DISCONNECT; + + diff --git a/smxrw.sql b/smxrw.sql new file mode 100644 index 0000000..bb4ff01 --- /dev/null +++ b/smxrw.sql @@ -0,0 +1,1116 @@ +Rem +Rem $Header: smxrw.sql 03-apr-2008.20:53:59 mmoy Exp $ +Rem +Rem smxrw.sql +Rem +Rem Copyright (c) 2001, 2008, Oracle. All rights reserved. +Rem +Rem NAME +Rem smxrw.sql +Rem +Rem DESCRIPTION +Rem This is a demo script for DBMS_MVIEW.EXPLAIN_REWRITE(). +Rem We create a materialized view in SALES schema and +Rem use EXPLAIN_REWRITE() to find out why query rewrite +Rem failed for some queries. The output of EXPLAIN_REWRITE() +Rem can go into a VARRAY or REWRITE_TABLE. +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem mmoy 04/03/08 - Fix sys password. +Rem gvincent 11/02/06 - downcase connects for secure verifiers +Rem mthiyaga 03/28/05 - Add examples using XRW utility +Rem mthiyaga 04/09/01 - Merged mthiyaga_xrw_demo +Rem mthiyaga 04/06/01 - Created +Rem +Rem =============================================================== +Rem + +connect sh/sh; + +SET ECHO ON; + +DROP MATERIALIZED VIEW month_sales_mv; + +CREATE MATERIALIZED VIEW month_sales_mv + ENABLE QUERY REWRITE + AS + SELECT t.calendar_month_number, + SUM(s.amount_sold) AS sum_dollars + FROM sales s, times t + WHERE s.time_id = t.time_id + GROUP BY t.calendar_month_number; + +REM Create REWRITE_TABLE for the output + +DROP TABLE REWRITE_TABLE; + +REM Create REWRITE_TABLE. Note the script to create the REWRITE_TABLE, utlxrw.sql, can +REM be found in the /rdbms/admin directory. + +@utlxrw.sql; + + +REM Enable query rewrite +ALTER SESSION SET QUERY_REWRITE_ENABLED = TRUE; + +REM Stale tolerated mode +ALTER SESSION SET QUERY_REWRITE_INTEGRITY = STALE_TOLERATED; + +DELETE FROM REWRITE_TABLE; + +REM ----------------------------------------------------------------------------- +REM Example 1: Output goes into REWRITE_TABLE +REM ----------------------------------------------------------------------------- + +SET SERVEROUTPUT ON; +DECLARE + querytxt VARCHAR2(1000) := 'SELECT t.calendar_month_number, SUM(s.amount_sold) AS sum_dollars + FROM sales s, times t + WHERE s.time_id = t.time_id AND + t.calendar_month_number = 5 + GROUP BY t.calendar_month_number'; +BEGIN + dbms_mview.Explain_Rewrite(querytxt, 'MONTH_SALES_MV'); +END; +/ + +REM Check the results in REWRITE_TABLE + +SELECT * FROM REWRITE_TABLE; + +REM ----------------------------------------------------------------------------- +REM Example 2: Query doesn't have the join in MONTH_SALES_MV. +REM ----------------------------------------------------------------------------- + + +DELETE FROM REWRITE_TABLE; + +EXECUTE dbms_mview.Explain_Rewrite('SELECT t.calendar_month_number, SUM(s.amount_sold) AS sum_dollars FROM sales s, times t GROUP BY t.calendar_month_number', 'MONTH_SALES_MV'); + +SELECT * FROM REWRITE_TABLE; + + +REM ----------------------------------------------------------------------------- +REM Example 3: In this example, we run explain_rewrite on two different queries. +REM Their outputs are distinguished by using two different statement +REM ids (query_1 and query_2). +REM ----------------------------------------------------------------------------- + +DELETE FROM REWRITE_TABLE; + +SET SERVEROUTPUT ON; +DECLARE + querytxt1 VARCHAR2(1000) := 'SELECT t.calendar_month_number, SUM(s.amount_sold) AS sum_dollars + FROM sales s, times t + WHERE s.time_id = t.time_id AND + t.calendar_month_number = 5 + GROUP BY t.calendar_month_number'; + querytxt2 VARCHAR2(1000) := 'SELECT t.calendar_month_number, SUM(s.amount_sold) AS sum_dollars + FROM sales s, times t + WHERE s.time_id = t.time_id AND + t.calendar_month_number = 10 + GROUP BY t.calendar_month_number'; + +BEGIN + dbms_mview.Explain_Rewrite(querytxt1, 'MONTH_SALES_MV', 'query_1'); + dbms_mview.Explain_Rewrite(querytxt2, 'MONTH_SALES_MV', 'query_2'); +END; +/ + +SELECT statement_id, message FROM REWRITE_TABLE; + + +REM ----------------------------------------------------------------------------- +REM Test 4: Query txt is the only argument passed to EXPLAIN_REWRITE. Output +REM goes to REWRITE_TABLE. Note that since there is no materialized view +REM specified in the argument list, EXPLAIN_REWRITE will output +REM messages related to all the MV's considered by query rewrite. +REM ----------------------------------------------------------------------------- + + +DELETE FROM REWRITE_TABLE; + +SET SERVEROUTPUT ON; +DECLARE + querytxt VARCHAR2(1000) := 'SELECT t.calendar_month_number, SUM(s.amount_sold) AS sum_dollars + FROM sales s, times t + WHERE t.calendar_month_number = 5 + GROUP BY t.calendar_month_number'; +BEGIN + dbms_mview.Explain_Rewrite(querytxt); +END; +/ + +-- Check the results in REWRITE_TABLE + +SELECT * FROM REWRITE_TABLE; + + + +REM ----------------------------------------------------------------------------- +REM Test 5: Output goes into a VARRAY. Note that we need to turn on SERVEROUTPUT +REM in order to see the output below. +REM ----------------------------------------------------------------------------- + +SET SERVEROUTPUT ON; +DECLARE + Rewrite_Array SYS.RewriteArrayType := SYS.RewriteArrayType(); + querytxt VARCHAR2(1000) := 'SELECT t.calendar_month_number, SUM(s.amount_sold) AS sum_dollars + FROM sales s, times t + WHERE s.time_id = t.time_id AND + t.calendar_month_number = 5 + GROUP BY t.calendar_month_number'; + no_of_msgs NUMBER; + i NUMBER; +BEGIN + dbms_mview.Explain_Rewrite(querytxt, 'MONTH_SALES_MV', Rewrite_Array); + no_of_msgs := rewrite_array.count; + FOR i IN 1..no_of_msgs + LOOP + DBMS_OUTPUT.PUT_LINE('>> MV_NAME : ' || Rewrite_Array(i).mv_name); + DBMS_OUTPUT.PUT_LINE('>> BEFORE VM: ' || Rewrite_Array(i).pass); + DBMS_OUTPUT.PUT_LINE('>> QUERY : ' || Rewrite_Array(i).query_text); + DBMS_OUTPUT.PUT_LINE('>> MESSAGE : ' || Rewrite_Array(i).message); + END LOOP; +END; +/ + + + +REM ----------------------------------------------------------------------------- +REM Test 6: Query rewrite is disabled +REM ----------------------------------------------------------------------------- + +-- Disable query rewrite and try the query +ALTER SESSION SET QUERY_REWRITE_ENABLED = FALSE; + +SET SERVEROUTPUT ON; +DECLARE + Rewrite_Array SYS.RewriteArrayType := SYS.RewriteArrayType(); + querytxt VARCHAR2(1000) := 'SELECT t.calendar_month_number, SUM(s.amount_sold) AS sum_dollars + FROM sales s, times t + WHERE s.time_id = t.time_id AND + t.calendar_month_number = 5 + GROUP BY t.calendar_month_number'; + no_of_msgs NUMBER; + i NUMBER; +BEGIN + dbms_mview.Explain_Rewrite(querytxt, 'MONTH_SALES_MV', Rewrite_Array); + no_of_msgs := rewrite_array.count; + FOR i IN 1..no_of_msgs + LOOP + DBMS_OUTPUT.PUT_LINE('>> MV_NAME : ' || Rewrite_Array(i).mv_name); + DBMS_OUTPUT.PUT_LINE('>> BEFORE VM: ' || Rewrite_Array(i).pass); + DBMS_OUTPUT.PUT_LINE('>> QUERY : ' || Rewrite_Array(i).query_text); + DBMS_OUTPUT.PUT_LINE('>> MESSAGE : ' || Rewrite_Array(i).message); + END LOOP; +END; +/ + +REM ----------------------------------------------------------------------------- +REM Test 7: Query rewrite is enabled +REM ----------------------------------------------------------------------------- + +REM Enable query rewrite and try the query again +ALTER SESSION SET QUERY_REWRITE_ENABLED = TRUE; + +SET SERVEROUTPUT ON; +DECLARE + Rewrite_Array SYS.RewriteArrayType := SYS.RewriteArrayType(); + querytxt VARCHAR2(1000) := 'SELECT t.calendar_month_number, SUM(s.amount_sold) AS sum_dollars + FROM sales s, times t + WHERE s.time_id = t.time_id AND + t.calendar_month_number = 5 + GROUP BY t.calendar_month_number'; + no_of_msgs NUMBER; + i NUMBER; +BEGIN + dbms_mview.Explain_Rewrite(querytxt, 'MONTH_SALES_MV', Rewrite_Array); + no_of_msgs := rewrite_array.count; + FOR i IN 1..no_of_msgs + LOOP + DBMS_OUTPUT.PUT_LINE('>> MV_NAME : ' || Rewrite_Array(i).mv_name); + DBMS_OUTPUT.PUT_LINE('>> BEFORE VM: ' || Rewrite_Array(i).pass); + DBMS_OUTPUT.PUT_LINE('>> QUERY : ' || Rewrite_Array(i).query_text); + DBMS_OUTPUT.PUT_LINE('>> MESSAGE : ' || Rewrite_Array(i).message); + END LOOP; +END; +/ + +REM ----------------------------------------------------------------------------- +REM Clean up +REM ----------------------------------------------------------------------------- + +DROP MATERIALIZED VIEW MONTH_SALES_MV; + +--------------------------------------------------------------------------------- +--- Following EXPLAIN_REWRITE() examples use a utility called SYS.XRW. This +--- utility helps the user to easily select the desired output fields from +--- EXPLAIN_REWRITE(). Since the output of EXPLAIN_REWRITE() consists of +--- many fields, this utility can be very helpful to the user. +--------------------------------------------------------------------------------- + +CONNECT sys/knl_test7 as sysdba; + +SET ECHO OFF; +--- Load the XRW utility +--- +@xrwutl; + +DROP user xrwdemo cascade; +CREATE user xrwdemo identified by xrwdemo; +GRANT connect, resource, dba to xrwdemo; +GRANT CREATE MATERIALIZED VIEW TO xrwdemo; +GRANT global query rewrite TO xrwdemo; + +CONNECT xrwdemo/xrwdemo; + +DROP TABLE FT; +CREATE TABLE FT (a1 INT, b1 INT, sales INT); + +DROP MATERIALIZED VIEW MV1; + +CREATE MATERIALIZED VIEW MV1 +ENABLE QUERY REWRITE AS +SELECT a1, b1, sum(sales) sum_sales +FROM FT +GROUP BY a1, b1; + + +-- Following query rewrites. Note the rewritten query text and query block number +-- +set serveroutput on size 999999 +DECLARE + querytxt VARCHAR2(1500) := 'SELECT a1, b1, SUM(sales) FROM FT GROUP BY a1, b1'; +BEGIN + SYS.XRW('', 'COSTS, QUERY_TXT, PASS, REWRITTEN_TXT, QUERY_BLOCK_NO', querytxt); +END; +/ + +DROP MATERIALIZED VIEW MV1; + +DROP TABLE FT; +CREATE TABLE FT (a1 INT, b1 INT, sales INT); + + +CREATE MATERIALIZED VIEW MV1 AS +SELECT a1, b1, sum(sales) sum_sales +FROM FT +GROUP BY a1, b1; + + +--- Rewrite is disabled for MV1. This query doesn't rewrite +set serveroutput on size 999999 +DECLARE + querytxt VARCHAR2(1500) := 'SELECT a1, b1, SUM(sales) FROM FT GROUP BY a1, b1'; +BEGIN + SYS.XRW('', 'QUERY_TXT, REWRITTEN_TXT', querytxt); +END; +/ + +--- Enable rewrite for MV1. It should rewrite now. + +DROP MATERIALIZED VIEW MV1; + +CREATE MATERIALIZED VIEW MV1 +ENABLE QUERY REWRITE AS +SELECT a1, b1, sum(sales) sum_sales +FROM FT +GROUP BY a1, b1; + +DECLARE + querytxt VARCHAR2(1500) := 'SELECT a1, b1, SUM(sales) FROM FT GROUP BY a1, b1'; +BEGIN + SYS.XRW('', 'QUERY_TXT, REWRITTEN_TXT', querytxt); +END; +/ + + +DROP TABLE FT; +CREATE TABLE FT (a1 INT, b1 INT, sales INT); + +DROP MATERIALIZED VIEW MV1; + +CREATE MATERIALIZED VIEW MV1 +ENABLE QUERY REWRITE AS +SELECT a1, b1, sum(sales) sum_sales +FROM FT +GROUP BY a1, b1; + +INSERT INTO FT VALUES (5, 5, 500); + + +-- Following query doesn't rewrite in ENFORCED mode +-- +set serveroutput on size 999999 +DECLARE + querytxt VARCHAR2(1500) := 'SELECT a1, b1, SUM(sales) FROM FT GROUP BY a1, b1'; +BEGIN + SYS.XRW('', 'QUERY_TXT, REWRITTEN_TXT', querytxt); +END; +/ + +drop table a; +drop table b; +drop table c; +drop table d; + +create table A(a1 int, a2 int, a3 int); +create table B(b1 int, b2 int, b3 int); +create table C(c1 int, c2 int, c3 int); +create table D(d1 int, d2 int, d3 int); + +ALTER TABLE b ADD CONSTRAINT pk_b PRIMARY KEY (b1); +ALTER TABLE C ADD CONSTRAINT PK_C PRIMARY KEY (c1); + +-- Make join between A and B lossless +ALTER TABLE A ADD CONSTRAINT fk_a FOREIGN KEY(a1) REFERENCES b(b1); +ALTER TABLE A MODIFY a1 NOT NULL; + +-- Make join between B and C lossless +ALTER TABLE B ADD CONSTRAINT fk_b FOREIGN KEY(b2) REFERENCES c(c1); +ALTER TABLE B MODIFY b2 NOT NULL; + +drop materialized view mv1; + +-- MV1: A--->B--->C +-- | +-- D + +create materialized view mv1 +enable query rewrite as +select a.a1, b.b1, sum(a.a3) as sum_a +from a, b, c, d +where a.a1 = b.b1 + and a.a2 = d.d2 + and b.b2 = c.c1 +group by a.a1, b.b1; + + +-- Query doesn't rewrite due to anchor table in the MV +-- +set serveroutput on; +DECLARE + querytxt VARCHAR2(1500) := 'select a.a1, b.b1, sum(a.a3) +from a, b, c +where a.a1 = b.b1 + and b.b2 = c.c1 +group by a.a1, b.b1'; +BEGIN + SYS.XRW('', '', querytxt); +END; +/ + +drop table a; +drop table b; +drop table c; + +create table A(a1 int, a2 int, a3 int); +create table B(b1 int, b2 int, b3 int); +create table C(c1 int, c2 int, c3 int); + +ALTER TABLE b ADD CONSTRAINT pk_b PRIMARY KEY (b1); + +-- Make join between A and B lossless +ALTER TABLE A ADD CONSTRAINT fk_a FOREIGN KEY(a1) REFERENCES b(b1); +ALTER TABLE A MODIFY a1 NOT NULL; + +drop materialized view mv1; + +-- MV1: A--->B +-- | +-- C + +create materialized view mv1 +enable query rewrite as +select a.a1, b.b1, c.c1, sum(a.a3) as sum_a +from a, b, c +where a.a1 = c.c1 and a.a1 = b.b1 +group by a1, b1, c1; + +-- should NOT rewrite as the MV delta has a lossy join + +set serveroutput on +DECLARE + querytxt VARCHAR2(1500) := 'select a.a1, b.b1, sum(a.a3) +from a, b +where a.a1 = b.b1 +group by a.a1, b.b1'; +BEGIN + SYS.XRW('', '', querytxt); +END; +/ + +drop table a; +drop table b; +drop table c; +drop table d; + +create table A(a1 int, a2 int, a3 int); +create table B(b1 int, b2 int, b3 int); +create table C(c1 int, c2 int, c3 int); +create table D(d1 int, d2 int, d3 int); + +ALTER TABLE b ADD CONSTRAINT pk_b PRIMARY KEY (b1); +ALTER TABLE C ADD CONSTRAINT PK_C PRIMARY KEY (c1); + +-- Make join between A and B lossless +ALTER TABLE A ADD CONSTRAINT fk_a FOREIGN KEY(a1) REFERENCES b(b1); +ALTER TABLE A MODIFY a1 NOT NULL; + +-- Make join between B and C lossless +ALTER TABLE B ADD CONSTRAINT fk_b FOREIGN KEY(b2) REFERENCES c(c1); +ALTER TABLE B MODIFY b2 NOT NULL; + +drop materialized view mv1; + +-- MV1: A--->B--->C +-- | +-- D + +drop materialized view mv1; + +create materialized view mv1 +enable query rewrite as +select a.a1, b.b1, sum(a.a3) as sum_a +from a, b, c, d +where a.a1 = b.b1 + and a.a2 = d.d2 + and b.b2 = c.c1 +group by a.a1, b.b1; + + +-- Doesn't rewrite due to join back failures +-- +set serveroutput on +DECLARE + querytxt VARCHAR2(1500) := 'select a.a1, b.b1, sum(a.a3) +from a, b, c, d +where a.a1 = b.b1 + and a.a2 = d.d2 + and b.b2 = c.c1 + and b.b3 = c.c2 +group by a.a1, b.b1'; +BEGIN + SYS.XRW('', '', querytxt); +END; +/ + +drop table a; +drop table b; +drop table c; +drop table d; + +create table A(a1 int, a2 int, a3 int); +create table B(b1 int, b2 int, b3 int); +create table C(c1 int, c2 int, c3 int); +create table D(d1 int, d2 int, d3 int); + +ALTER TABLE b ADD CONSTRAINT pk_b PRIMARY KEY (b1); +ALTER TABLE C ADD CONSTRAINT PK_C PRIMARY KEY (c1); + +-- Make join between A and B lossless +ALTER TABLE A ADD CONSTRAINT fk_a FOREIGN KEY(a1) REFERENCES b(b1); +ALTER TABLE A MODIFY a1 NOT NULL; + +-- Make join between B and C lossless +ALTER TABLE B ADD CONSTRAINT fk_b FOREIGN KEY(b2) REFERENCES c(c1); +ALTER TABLE B MODIFY b2 NOT NULL; + +drop materialized view mv1; + +-- MV1: A--->B--->C +-- | +-- D + +drop materialized view mv1; + +create materialized view mv1 +enable query rewrite as +select a.a1, b.b1, sum(a.a3) as sum_a +from a, b, c, d +where a.a1 = b.b1 + and a.a2 = d.d2 + and b.b2 = c.c1 + and b.b2 = c.c2 +group by a.a1, b.b1; + + +-- Does not rewrite due to a lossy join in the MV +-- +set serveroutput on +DECLARE + querytxt VARCHAR2(1500) := 'select a.a1, b.b1, sum(a.a3) +from a, b, c, d +where a.a1 = b.b1 + and a.a2 = d.d2 + and b.b2 = c.c1 + and b.b3 = c.c2 +group by a.a1, b.b1'; +BEGIN + SYS.XRW('', '', querytxt); +END; +/ + + + + +DROP TABLE FT1; +DROP MATERIALIZED VIEW NESTED_MV1; +DROP MATERIALIZED VIEW NESTED_MV2; +DROP MATERIALIZED VIEW NESTED_MV3; +DROP MATERIALIZED VIEW NESTED_MV4; +DROP MATERIALIZED VIEW NESTED_MV5; + +REM create a fact table, FT1, for nested MAV tests + +CREATE TABLE FT1 (akey INT, bkey INT, ckey INT, dkey INT, ekey INT, sales INT); + +REM CREATE NESTED_MV1 on fact + +CREATE MATERIALIZED VIEW NESTED_MV1 +ENABLE QUERY REWRITE +AS + SELECT akey, bkey, ckey, dkey, ekey, sum(sales) sum_sales + FROM FT1 + GROUP BY akey, bkey, ckey, dkey, ekey; + +REM create NESTED_MV2 on NESTED_MV1 + +CREATE MATERIALIZED VIEW NESTED_MV2 +AS + SELECT akey, bkey, ckey, dkey, sum(sum_sales) sum_sales2 + FROM NESTED_MV1 + GROUP BY akey, bkey, ckey, dkey; + +REM create NESTED_MV3 on NESTED_MV2 + +CREATE MATERIALIZED VIEW NESTED_MV3 +ENABLE QUERY REWRITE +AS + SELECT akey, bkey, ckey, sum(sum_sales2) sum_sales3 + FROM NESTED_MV2 + GROUP BY akey, bkey, ckey; + +REM create NESTED_MV4 on NESTED_MV3 + +CREATE MATERIALIZED VIEW NESTED_MV4 +ENABLE QUERY REWRITE +AS + SELECT akey, bkey, sum(sum_sales3) sum_sales4 + FROM NESTED_MV3 + GROUP BY akey, bkey; + +REM create NESTED_MV5 on NESTED_MV4 + +CREATE MATERIALIZED VIEW NESTED_MV5 +ENABLE QUERY REWRITE +AS + SELECT akey, sum(sum_sales4) sum_sales5 + FROM NESTED_MV4 + GROUP BY akey; + + +-- Doesn't Rewrite with NESTED_MV5 as NESTED_MV2 is not enabled yet + +set serveroutput on; + +DECLARE + querytxt VARCHAR2(100) := 'SELECT akey, sum(sales) FROM FT1 GROUP BY akey'; +BEGIN + SYS.XRW('', 'REWRITTEN_TXT', querytxt); +END; +/ + +alter materialized view nested_mv2 enable query rewrite; + + +--Rewrites with NESTED_MV5 now + +set serveroutput on; + +DECLARE + querytxt VARCHAR2(100) := 'SELECT akey, sum(sales) FROM FT1 GROUP BY akey'; +BEGIN + SYS.XRW('', 'REWRITTEN_TXT', querytxt); +END; +/ + + +DROP TABLE FT; +CREATE TABLE FT (f1 INT, f2 INT, s INT); + +DROP TABLE A; +CREATE TABLE A(a1 int, a2 int); + +DROP TABLE B; +CREATE TABLE B(b1 int); + +ALTER TABLE A ADD CONSTRAINT pk_a PRIMARY KEY (a1); +ALTER TABLE B ADD CONSTRAINT pk_b PRIMARY KEY (b1); + +ALTER TABLE FT ADD CONSTRAINT fk_ft_a FOREIGN KEY (f1) REFERENCES A(a1); +ALTER TABLE FT MODIFY (f1 NOT NULL) ; +ALTER TABLE FT ADD CONSTRAINT fk_ft_b FOREIGN KEY (f2) REFERENCES B(b1); +ALTER TABLE FT MODIFY (f2 NOT NULL); + +DROP MATERIALIZED VIEW MV1; + +CREATE MATERIALIZED VIEW MV1 +ENABLE QUERY REWRITE AS +SELECT f1, a1, sum(s) sum_s +FROM FT, A +WHERE FT.f1 = A.a1 +GROUP BY f1, a1; + +DROP MATERIALIZED VIEW MV2; + +CREATE MATERIALIZED VIEW MV2 +ENABLE QUERY REWRITE AS +SELECT f1, a1, b1, sum(s) sum_s +FROM FT, A, B +WHERE FT.f1 = A.a1 AND FT.f2 = B.b1 +GROUP BY f1, a1, b1; + +set serveroutput on; +DECLARE + querytxt VARCHAR2(100) := 'SELECT a1, SUM(s) +FROM FT, A +WHERE FT.f1 = A.a1 +GROUP BY a1'; +BEGIN + SYS.XRW('', 'QUERY_TXT, REWRITTEN_TXT, COSTS', querytxt); +END; +/ + + +drop table a; +create table a(a1 int, s int); + +drop materialized view mv1; +create materialized view mv1 +enable query rewrite as +select a1, sum(s) sum_s +from a +WHERE a1 < 50 +group by a1; + +drop materialized view mv2; +create materialized view mv2 +enable query rewrite as +select a1, sum(s) sum_s +from a +WHERE a1 >= 50 +group by a1; + + +-- query doesn't rewrite as cost is more expensive than the +-- unrewritten query. +-- +set serveroutput on +DECLARE + querytxt VARCHAR2(1500) := 'select a1, sum(s) sum_s from a group by a1'; +BEGIN + SYS.XRW('', 'QUERY_TXT, REWRITTEN_TXT, COSTS, QUERY_BLOCK_NO', querytxt); +END; +/ + + +--- Create MV3 such that it doesn't have SUM(s) in it. +-- +drop materialized view mv3; +create materialized view mv3 +enable query rewrite as +select a1, count(s) count_s +from a +WHERE a1 >= 50 +group by a1; + +-- rewrites with mv1 and mv2. +-- +set serveroutput on +DECLARE + querytxt VARCHAR2(1500) := 'select a1, sum(s) sum_s from a group by a1'; +BEGIN + SYS.XRW('MV3', 'QUERY_TXT, REWRITTEN_TXT, COSTS, QUERY_BLOCK_NO', querytxt); +END; +/ + + + +DROP TABLE A cascade constraints; +create table a(a1 int, a2 int, a3 int, s int); + +drop materialized view mv1; +create materialized view mv1 +enable query rewrite as +select a1, sum(s) +from a +group by a1; + + +-- query has an inline view which can be rewritten with MV1. Outer query +-- cannot be rewritten. Note the rewritten query and the query block numbers +-- + +set serveroutput on +DECLARE + querytxt VARCHAR2(1500) := 'select a_1, sum_s from (select a1 a_1, sum(s) sum_s from a group by a1) iv1'; +BEGIN + SYS.XRW('', 'COSTS, QUERY_TXT, PASS, REWRITTEN_TXT, QUERY_BLOCK_NO', + querytxt); +END; +/ + + + +DROP TABLE A cascade constraints; +create table a(a1 int, a2 int, a3 int, s int); + +DROP TABLE B cascade constraints; +create table b(b1 int, b2 int, b3 int, t int); + +drop materialized view mv1; +create materialized view mv1 +enable query rewrite as +select a1, b1, sum(s) +from a, b +group by a1, b1; + + +-- Note the query block numbers for the rewritten inline views. Inline view +-- IV1 gets rewritten using exact text match +-- + +set serveroutput on +DECLARE + querytxt VARCHAR2(1500) := 'select a_1, x_1, sum_s from (select a1 a_1, b1 b_1, sum(s) sum_s from a, b group by a1, b1) iv1, (select sum(s) sum_ss, a1 x_1 from a group by a1) iv2'; +BEGIN + SYS.XRW('', 'REWRITTEN_TXT, QUERY_BLOCK_NO', + querytxt); +END; +/ + + +-- Note the query block numbers for the rewritten inline views. Inline view +-- IV1 gets rewritten using exact text match and inline view IV3 gets +-- rewritten using general rewrite +-- + +set serveroutput on +DECLARE + querytxt VARCHAR2(1500) := 'select a_1, x_1, sum_s from (select a1 a_1, b1 b_1, sum(s) sum_s from a, b group by a1, b1) iv1, (select sum(s) sum_ss, a1 x_1 from a group by a1) iv2, (select a1 a_11, b1 b_11, sum(s) sum_sss from b, a group by b1, a1) iv3'; +BEGIN + SYS.XRW('', 'REWRITTEN_TXT, QUERY_BLOCK_NO', + querytxt); +END; +/ + + +DROP TABLE A CASCADE CONSTRAINTS; +DROP TABLE "A_small" CASCADE CONSTRAINTS; +DROP TABLE "A_SMALL" CASCADE CONSTRAINTS; +DROP TABLE B CASCADE CONSTRAINTS; +DROP TABLE C CASCADE CONSTRAINTS; +DROP TABLE D CASCADE CONSTRAINTS; + +CREATE TABLE A (a1 INTEGER, a2 INTEGER constraint nn_a2 not null, + a3 INTEGER, a4 INTEGER, a5 INTEGER); +CREATE TABLE "A_small" (a1 INTEGER, a2 INTEGER constraint small1_a2 not null, + a3 INTEGER, a4 INTEGER, a5 INTEGER, a6 varchar(30)); +CREATE TABLE "A_SMALL" (a1 INTEGER, a2 INTEGER constraint small2_a2 not null, + a3 INTEGER, a4 INTEGER, a5 INTEGER, a6 varchar(30)); +CREATE TABLE B (b1 INTEGER, b2 INTEGER, y INTEGER constraint nn_y not null, + g INTEGER, + h INTEGER); +CREATE TABLE C (c1 INTEGER, c2 INTEGER, c3 INTEGER, + c4 INTEGER); +CREATE TABLE D (d1 INTEGER, d2 INTEGER, d3 INTEGER, + d4 INTEGER); + +DROP MATERIALIZED VIEW inline_mv1; + +CREATE MATERIALIZED VIEW inline_mv1 +ENABLE QUERY REWRITE AS +SELECT A.a1, A.a2, SUM(V1.a3) as sum_s +FROM A, (SELECT * FROM A) V1 +WHERE A.a1 = V1.a1 +GROUP BY A.a1, A.a2; + + +DROP MATERIALIZED VIEW inline_mv3; + +CREATE MATERIALIZED VIEW inline_mv3 +ENABLE QUERY REWRITE AS +SELECT A.a1, A.a2, B.b1, SUM(V1.a3) as sum_s1, SUM(V2.b2) as sum_s2 +FROM A, B, (SELECT * FROM A) V1, (SELECT * FROM B) V2 +WHERE A.a1 = V1.a1 AND + A.a2 = B.b2 +GROUP BY A.a1, A.a2, B.b1; + + +DROP MATERIALIZED VIEW inline_mv4; + +--- MV has multiple inline views +CREATE MATERIALIZED VIEW inline_mv4 +ENABLE QUERY REWRITE AS +SELECT A.a1, A.a2, B.b1, SUM(V1.a3) as sum_s1, SUM(V2.b2) as sum_s2 +FROM A, B, (SELECT * FROM A) V1, (SELECT * FROM B) V2 +GROUP BY A.a1, A.a2, B.b1; + + +DROP MATERIALIZED VIEW inline_mv5; + +--- MV has multiple inline views +CREATE MATERIALIZED VIEW inline_mv5 +ENABLE QUERY REWRITE AS +SELECT A.a1, A.a2, B.b1, SUM(V1.a3) as sum_s1, SUM(V2.b2) as sum_s2 +FROM A, B, (SELECT * FROM A) V1, (SELECT * FROM B) V2 +WHERE (A.a1 = V1.a1) AND (B.b1 = V2.b2) +GROUP BY A.a1, A.a2, B.b1; + + +DROP MATERIALIZED VIEW INLINE_MV6; + +--- MV has multiple inline views, with joins +CREATE MATERIALIZED VIEW inline_mv6 +ENABLE QUERY REWRITE AS +SELECT A.a1, sum(V2.sum_v1) sum_v2 FROM +A, (SELECT A.a1, A.a2, SUM(V1.a3) as sum_v1 + FROM A, (SELECT * FROM A) V1 + GROUP BY A.a1, A.a2) V2 +WHERE (A.a2 = V2.a2) +GROUP BY A.a1; + + +DROP MATERIALIZED VIEW INLINE_MV7; + +--- MV has multiple inline views, with joins between views +CREATE MATERIALIZED VIEW inline_mv7 +ENABLE QUERY REWRITE AS +SELECT A.a1, sum(V2.sum_v1) sum_v2 FROM +A, (SELECT A.a1, A.a2, SUM(V1.a3) as sum_v1 + FROM A, (SELECT * FROM A) V1 + GROUP BY A.a1, A.a2) V2, + (SELECT B.b1, B.b2 FROM B) V3 +WHERE (V2.a1 = V3.b1) +GROUP BY A.a1; + + +DROP MATERIALIZED VIEW INLINE_MV8; + +--- MV has multiple inline views, with joins between views +CREATE MATERIALIZED VIEW inline_mv8 +ENABLE QUERY REWRITE AS +SELECT A.a1, sum(V2.sum_v1) sum_v2 FROM +A, (SELECT A.a1, A.a2, SUM(V1.a3) as sum_v1 + FROM A, (SELECT * FROM A) V1 + GROUP BY A.a1, A.a2) V2, + (SELECT B.b1, B.b2 FROM B) V3 +WHERE (V2.a1 = V3.b1) +GROUP BY A.a1; + + +DROP MATERIALIZED VIEW INLINE_MV9; + +--- MV has multiple inline views, but no joins +CREATE MATERIALIZED VIEW inline_mv9 +ENABLE QUERY REWRITE AS +SELECT A.a1, B.b1, v1.a2, SUM(V1.a3) as sum_s1 +FROM A, B, (SELECT * FROM A) V1, (SELECT * FROM B) V2 +WHERE A.a1 = V1.a1 AND + A.a2 = B.b2 +GROUP BY A.a1, B.b1, V1.a2; + + +DROP MATERIALIZED VIEW INLINE_MV10; + +CREATE MATERIALIZED VIEW inline_mv10 +ENABLE QUERY REWRITE AS +SELECT A.a1, B.b1, v3.a2, SUM(V3.a3) as sum_s1 +FROM A, B, (SELECT * FROM (SELECT * FROM A) V1) V3, (SELECT * FROM B) V2 +WHERE A.a1 = V3.a1 AND + A.a2 = B.b2 +GROUP BY A.a1, B.b1, V3.a2; + + +DROP MATERIALIZED VIEW INLINE_MV11; + +CREATE MATERIALIZED VIEW inline_mv11 +ENABLE QUERY REWRITE +AS +SELECT A.a1, B.b1, SUM(A.a1) as sum_a1, COUNT(A.a1) as cnt_a1 +FROM A, B, (SELECT a1, a2, SUM(a1) FROM A GROUP BY a1, a2) V1 +WHERE A.a1 = V1.a1 +GROUP BY A.a1, B.b1; + +DROP MATERIALIZED VIEW INLINE_MV_CASE1; +CREATE MATERIALIZED VIEW inline_mv_case1 +ENABLE QUERY REWRITE +AS +SELECT A.a1, A.a2, SUM(V1.a3) as sum_s +FROM A, (SeLeCT /*doen't matter ''""' comments */ + * FroM "A_small") V1 +WHERE A.a1 = V1.a1 +GROUP BY A.a1, A.a2; + +DROP MATERIALIZED VIEW INLINE_MV_CASE2; +CREATE MATERIALIZED VIEW inline_mv_case2 +ENABLE QUERY REWRITE +AS +SELECT A.a1, A.a2, SUM(V1.a3) as sum_s +FROM A, (SeLeCT * fROm "A_SMALL") V1 +WHERE A.a1 = V1.a1 +GROUP BY A.a1, A.a2; + +DROP MATERIALIZED VIEW INLINE_MV_CASE3; +CREATE MATERIALIZED VIEW inline_mv_case3 +ENABLE QUERY REWRITE +AS +SELECT A.a1, A.a2, SUM(V1.a3) as sum_s +FROM A, (SeLeCT * FroM "A_small" + where a6='small') V1 +WHERE A.a1 = V1.a1 +GROUP BY A.a1, A.a2; + + +-- +-- Rewrites with inline_mv_case2 +-- +set serveroutput on; +DECLARE + querytxt VARCHAR2(200) := 'SELECT A.a2, A.a1, SUM(V1.a3) FROM A, (SELECT * FROM A_small) V1 +WHERE V1.a1 = A.a1 +GROUP BY A.a2, A.a1'; +BEGIN + SYS.XRW('', 'QUERY_TXT, REWRITTEN_TXT, QUERY_BLOCK_NO, COSTS', querytxt); +END; +/ + + +-- +-- Rewrites with inline_mv_case3 +-- +set serveroutput on; +DECLARE + querytxt VARCHAR2(200) := 'SELECT A.a2, A.a1, SUM(V1.a3) as sum_s +FROM A, (SeLeCT * FroM "A_small" + where a6=''small'') V1 +WHERE A.a1 = V1.a1 +GROUP BY A.a1, A.a2'; +BEGIN + SYS.XRW('', 'QUERY_TXT, REWRITTEN_TXT, QUERY_BLOCK_NO, COSTS', querytxt); +END; +/ + + +-- +-- Rewrites using exact text match +-- +set serveroutput on; +DECLARE + querytxt VARCHAR2(200) := 'SELECT A.a1, A.a2, SUM(V1.a3) FROM A, (SELECT * FROM A) V1 +WHERE A.a1 = V1.a1 +GROUP BY A.a1, A.a2'; +BEGIN + SYS.XRW('', 'QUERY_TXT, REWRITTEN_TXT, QUERY_BLOCK_NO, COSTS', querytxt); +END; +/ + +-- +-- No full or partial text match possible. Rewrites with general rewrite +-- +set serveroutput on; +DECLARE + querytxt VARCHAR2(200) := 'SELECT A.a1, B.b1, SUM(V1.a3) as sum_s1, SUM(V2.b2) as sum_s2 +FROM A, B, (SELECT * FROM A) V1, (SELECT * FROM B) V2 +WHERE V1.a1 = A.a1 AND + B.b2 = A.a2 +GROUP BY A.a1, B.b1'; +BEGIN + SYS.XRW('', 'QUERY_TXT, REWRITTEN_TXT, QUERY_BLOCK_NO, COSTS', querytxt); +END; +/ + + +-- Query has multiple inline views. +-- +set serveroutput on; +DECLARE + querytxt VARCHAR2(200) := 'SELECT A.a1, A.a2, B.b1, SUM(V1.a3) as sum_s1, SUM(V2.b2) as sum_s2 +FROM A, B, (SELECT * FROM A) V1, (SELECT * FROM B) V2 +WHERE (A.a1 = V1.a1) AND (B.b1 = V2.b2) +GROUP BY A.a1, A.a2, B.b1'; +BEGIN + SYS.XRW('', 'QUERY_TXT, REWRITTEN_TXT, QUERY_BLOCK_NO, COSTS', querytxt); +END; +/ + +set serveroutput on; +DECLARE + querytxt VARCHAR2(200) := 'SELECT A.a1, B.b1, A.a2, SUM(V1.a3) as sum_s1, SUM(V2.b2) as sum_s2 +FROM A, B, (SELECT * FROM A) V1, (SELECT * FROM B) V2 +group BY A.a1, B.b1, A.a2'; +BEGIN + SYS.XRW('', 'QUERY_TXT, REWRITTEN_TXT, QUERY_BLOCK_NO, COSTS', querytxt); +END; +/ + +-- +-- rewrites with multiple nested inline views +-- +set serveroutput on; +DECLARE + querytxt VARCHAR2(200) := 'SELECT A.a1, sum(V2.sum_v1) sum_v2 FROM +A, (SELECT A.a1, A.a2, SUM(V1.a3) as sum_v1 + FROM A, (SELECT * FROM A) V1 + GROUP BY A.a1, A.a2) V2 +WHERE (V2.a2 = A.a2) +GROUP BY A.a1'; +BEGIN + SYS.XRW('', 'QUERY_TXT, REWRITTEN_TXT, QUERY_BLOCK_NO, COSTS', querytxt); +END; +/ + + +-- +--- Different aliases used in query for inline views. Should rewrite with +--- inline_mv10 +-- +set serveroutput on; +DECLARE + querytxt VARCHAR2(200) := 'SELECT A.a1, VX.a2, SUM(VX.a3) as sum_s1 +FROM A, B, (SELECT * FROM (SELECT * FROM A) V1) VX, (SELECT * FROM B) VY +WHERE A.a1 = VX.a1 AND + B.b2 = A.a2 +GROUP BY A.a1, VX.a2'; +BEGIN + SYS.XRW('', 'QUERY_TXT, REWRITTEN_TXT, QUERY_BLOCK_NO, COSTS', querytxt); +END; +/ + + +--- rewrites with inline_mv11 +-- +set serveroutput on; +DECLARE + querytxt VARCHAR2(200) := 'SELECT A.a1, AVG(A.a1) as avg_a1 +FROM A, B, (SELECT a1, a2, SUM(a1) FROM A GROUP BY a1, a2) V1 +WHERE V1.a1 = A.a1 +GROUP BY A.a1'; +BEGIN + SYS.XRW('', 'QUERY_TXT, REWRITTEN_TXT, QUERY_BLOCK_NO, COSTS', querytxt); +END; +/ + +connect sys/knl_test7 as sysdba; + +drop public synonym XRW; + +drop user xrwdemo cascade; + + +DISCONNECT; + + diff --git a/strmatREADME.txt b/strmatREADME.txt new file mode 100644 index 0000000..5904c07 --- /dev/null +++ b/strmatREADME.txt @@ -0,0 +1,79 @@ + +asynchronous trigger is composed of two parts. + +* strmats.sql sets up dictionary tables, types, and a package to implement + asynchronous trigger using streams. + +* strmatu.sql is an example that creates two row triggers and a table + trigger on table u1.accounts, recording any changes to user Alice's + balance. + +* archiving must be enabled in the database. + + Unlike traditional triggers, asynchronous triggers are created and dropped + by a PL/SQL API. The when clause and trigger body syntax are mostly the same, + with following exceptions: + + * value of the changed row will be referenced as old, new instead of + :old, :new. + + * attribute function inserting, updating, deleting will NOT work in + asynchronous triggers. Instead one should use + + bitand(dml_events, async_trig_pkg.on_insert) = async_trig_pkg.on_insert + bitand(dml_events, async_trig_pkg.on_update) = async_trig_pkg.on_update + bitand(dml_events, async_trig_pkg.on_delete) = async_trig_pkg.on_delete + + to identify inserting, updating, deleting events respectively. + + Package async_trig_pkg contains the following procedures: + + * set_up_streams() which sets up capture and apply for asynchronous triggers + * clean_up_streams() which cleans up streams capture apply, queue, etc. + * create_trigger() which creates an asynchronous trigger + * drop_trigger() which drops an asynchronous trigger + + LIMITATIONS: + + This package is just a prototype and has the following limitations. + + * Name canonicalization. It is assumed that all names passed to + async_trig_pkg APIs are ALREADY canonicalized. + + * Datatype support. The column type of the table on which asynchoronous + triggers are defined are limited to the following data types: + + NUMBER, FLOAT, VARCHAR2, RAW, DATE, TIMESTAMP. + + * ALTERATION. To alter a trigger one needs to drop and recreate it. + Same is the streams set up. + + * ERROR HANDLING. Because we are not inside the kernel, DDL operations + (set_up_streams, create_trigger etc.) are not strictly atomic. If an + operation raised an error for some reason, the asynchronous trigger + dictionary data might be left in an inconsistent state. In this case, + ORA-20001 (streams already exists) or ORA-20009 (trigger already + exists) will be raised when you retry the operation. + + drop_trigger operation can clean up the state of a failed create_trigger. + clean_up_streams can clean up the state of a failed set_up_streams. + + * SUPPLIMENTAL LOGGING. To be able to see unchanged column values in + an update asynchronous trigger, supplemental logging needed to be + turned on for that table. The asynchronous trigger script will not + turn on supplemental logging by default, because it can affect the + performance of the user DML txn. + + Most of the limitations could be amended given some more time. If any + of the above is not acceptable, please let me know. + + INSTRUCTIONS: + + -- create streams by calling set_up_streams() + -- create trigger on table of interest using create_trigger() + -- check that trigger is fired on DMLs of the table + -- drop unwanted triggers by drop_trigger() + -- clean_up_streams() will drop all asynchronous triggers, drop capture, + apply, queue, etc. + -- check async_trigger_usecase.sql for an example + -- report bugs and problems to wei.wang@oracle.com diff --git a/strmatp.sql b/strmatp.sql new file mode 100644 index 0000000..acfb993 --- /dev/null +++ b/strmatp.sql @@ -0,0 +1,753 @@ +create or replace package async_trig_pkg AUTHID CURRENT_USER AS + + on_insert constant binary_integer := 1; + on_update constant binary_integer := 2; + on_delete constant binary_integer := 4; + + /* set up catpure and apply parameters */ + procedure set_up_streams(capture_name IN varchar2, + apply_name IN varchar2); + + /* clean up capture and apply */ + procedure clean_up_streams; + + /* + * After trigger creation, the following procedure will be created for + * row triggers: + * procedure (lcr IN lcr$_row_record, + * dml_events IN binary_integer) IS + * old %rowtype; + * new %rowtype; + * BEGIN + * ... -- populate old and new values using lcr + * IF () THEN + * + * END IF; + * END; + * + * The IF ... THEN caluse will be omitted if when_clause is NULL. + * for table triggers, the following procedure will be created: + * + * procedure (dml_events IN binary_integer) IS + * BEGIN + * + * END; + * + * Table triggers will be called once per txn. + */ + + procedure create_trigger(trigger_owner IN varchar2, + trigger_name IN varchar2, + table_owner IN varchar2, + table_name IN varchar2, + dml_events IN binary_integer, + for_each_row IN boolean DEFAULT TRUE, + when_clause IN varchar2 DEFAULT NULL, + action IN varchar2); + + /* drop the asynchronous trigger */ + procedure drop_trigger(owner IN varchar2, + trigger_name IN varchar2); +end; +/ +show errors +/ +grant execute on async_trig_pkg to public +/ +create or replace public synonym async_trig_pkg for trgadm.async_trig_pkg +/ + +create or replace package async_trig_internal AS + + tabdml table_dml_list := table_dml_list(); + + procedure set_up_streams(capture_name IN varchar2, + apply_name IN varchar2); + + procedure clean_up_streams; + + + procedure create_trigger(trig_owner IN varchar2, + trig_name IN varchar2, + tab_owner IN varchar2, + tab_name IN varchar2, + dml_events IN binary_integer, + for_each_row IN boolean DEFAULT TRUE, + when_clause IN varchar2 DEFAULT NULL, + action IN varchar2); + + + procedure drop_trigger(trig_owner IN varchar2, + trig_name IN varchar2); + + procedure dml_handler(in_any IN ANYDATA); + + procedure commit_handler(scn IN number); + +end; +/ +show errors +/ + +create or replace package body async_trig_pkg as + procedure set_up_streams(capture_name IN varchar2, + apply_name IN varchar2) IS + cnt binary_integer; + BEGIN + select count(role) into cnt from session_roles where role = 'DBA'; + IF cnt > 0 THEN + async_trig_internal.set_up_streams(capture_name, apply_name); + + dbms_rule_adm.create_rule_set( + rule_set_name => 'TRGADM.ASYNC_TRIG_ARS', + evaluation_context => 'sys.streams$_evaluation_context'); + + dbms_capture_adm.create_capture(queue_name => 'TRGADM.ASYNC_TRIG_Q', + capture_name => capture_name); + + dbms_apply_adm.create_apply(queue_name => 'TRGADM.ASYNC_TRIG_Q', + apply_name => apply_name, + rule_set_name => 'TRGADM.ASYNC_TRIG_ARS', + apply_captured => TRUE); + dbms_apply_adm.set_parameter(apply_name, 'COMMIT_SERIALIZATION', 'FULL'); + ELSE + raise_application_error(-20002, + 'DBA role is required to set up asynchronous trigger streams'); + END IF; + END; + + procedure clean_up_streams IS + cnt binary_integer; + BEGIN + select count(role) into cnt from session_roles where role = 'DBA'; + IF cnt > 0 THEN + async_trig_internal.clean_up_streams; + ELSE + raise_application_error(-20003, + 'DBA role is required to clean up asynchronous trigger streams'); + END IF; + END; + + procedure create_trigger(trigger_owner IN varchar2, + trigger_name IN varchar2, + table_owner IN varchar2, + table_name IN varchar2, + dml_events IN binary_integer, + for_each_row IN boolean DEFAULT TRUE, + when_clause IN varchar2 DEFAULT NULL, + action IN varchar2) IS + cnt binary_integer; + trig_owner VARCHAR2(30); + tab_owner VARCHAR2(30); + tab_name VARCHAR2(30); + cur_user VARCHAR2(30); + BEGIN + + trig_owner := NVL(trigger_owner, USERENV('SCHEMAID')); + tab_owner := NVL(table_owner, USERENV('SCHEMAID')); + tab_name := table_name; + + -- check the existence of the underlying table + select count(1) into cnt from all_tables + where owner = tab_owner and table_name = tab_name; + + IF cnt = 0 THEN + raise_application_error(-20007, + 'Table "' || tab_owner || '"."' || tab_name || + ' does not exist'); + END IF; + + select username into cur_user from user_users; + + -- check current user's privilege to create the trigger + IF trig_owner = cur_user THEN + select count(privilege) into cnt from session_privs + where privilege = 'CREATE TRIGGER'; + ELSE + select count(privilege) into cnt from session_privs + where privilege = 'CREATE ANY TRIGGER'; + END IF; + + IF cnt > 0 THEN + async_trig_internal.create_trigger(trig_owner, trigger_name, + tab_owner, tab_name, + dml_events, for_each_row, when_clause, action); + ELSE + raise_application_error(-20004, + 'Insufficient privilege to create trigger "' || trigger_owner || + '"."' || trigger_name || '"'); + END IF; + END; + + + procedure drop_trigger(owner IN varchar2, + trigger_name IN varchar2) IS + cnt binary_integer; + cur_user VARCHAR2(30); + BEGIN + select username into cur_user from user_users; + + IF owner = cur_user THEN + cnt := 1; + ELSE + select count(privilege) into cnt from session_privs + where privilege = 'DROP ANY TRIGGER'; + END IF; + + IF cnt > 0 THEN + async_trig_internal.drop_trigger(owner, trigger_name); + ELSE + raise_application_error(-20005, + 'Insufficient privilege to drop trigger "' || owner || '"."' || + trigger_name); + END IF; + END; +end async_trig_pkg; +/ + +show errors +/ + +create or replace package body async_trig_internal as + + CRLF CONSTANT VARCHAR2(4) := ' +'; + on_insert constant binary_integer := async_trig_pkg.on_insert; + on_update constant binary_integer := async_trig_pkg.on_update; + on_delete constant binary_integer := async_trig_pkg.on_delete; + + procedure set_up_streams(capture_name IN varchar2, + apply_name IN varchar2) IS + cnt NUMBER; + BEGIN + select count(1) into cnt FROM props$; + IF cnt > 0 THEN + raise_application_error(-20001, + 'asynchronous trigger streams already exists.'); + END IF; + insert into props$ values (capture_name, apply_name, 'NOT STARTED'); + commit; + + dbms_streams_adm.set_up_queue( + queue_table => 'TRGADM.ASYNC_TRIG_QT', + queue_name => 'TRGADM.ASYNC_TRIG_Q'); + + END set_up_streams; + + PROCEDURE clean_up_streams IS + db varchar2(128); + capture_name VARCHAR2(30); + apply_name VARCHAR2(30); + apply_status VARCHAR2(30); + cursor tab_c is select unique table_owner, table_name + from async_trigger$; + cursor trig_c is select trigger_owner, trigger_name from async_trigger$; + owner_name VARCHAR2(65); + proc_does_not_exist EXCEPTION; + PRAGMA EXCEPTION_INIT(proc_does_not_exist, -26701); + + BEGIN + select global_name into db from global_name; + select trigger_capture, trigger_apply, trigger_apply_status into + capture_name, apply_name, apply_status from props$; + + IF apply_status = 'STARTED' THEN + -- stop capture and apply + dbms_capture_adm.stop_capture(capture_name); + dbms_apply_adm.stop_apply(apply_name); + + for t_rec in tab_c loop + owner_name := '"' || t_rec.table_owner || '"."' || t_rec.table_name || + '"'; + + -- remove dml handlers + dbms_apply_adm.set_dml_handler( + object_name => owner_name, + object_type => 'TABLE', + operation_name => 'INSERT', + error_handler => false, + user_procedure => NULL, + apply_database_link => NULL, + apply_name => apply_name); + + dbms_apply_adm.set_dml_handler( + object_name => owner_name, + object_type => 'TABLE', + operation_name => 'UPDATE', + error_handler => false, + user_procedure => NULL, + apply_database_link => NULL, + apply_name => apply_name); + + dbms_apply_adm.set_dml_handler( + object_name => owner_name, + object_type => 'TABLE', + operation_name => 'DELETE', + error_handler => false, + user_procedure => NULL, + apply_database_link => NULL, + apply_name => apply_name); + + dbms_apply_adm.set_table_instantiation_scn( + source_object_name => owner_name, + source_database_name => db, + instantiation_scn => null); + end loop; + + -- remove capture and apply + BEGIN + dbms_apply_adm.drop_apply(apply_name, true); + dbms_capture_adm.drop_capture(capture_name, true); + EXCEPTION + WHEN proc_does_not_exist THEN + NULL; + WHEN others THEN + RAISE; + END; + + END IF; + + FOR g_rec in trig_c LOOP + execute immediate 'drop procedure "' || g_rec.trigger_owner || '"."' || + g_rec.trigger_name || '"'; + END LOOP; + + DELETE FROM async_trigger$; + DELETE FROM async_trigger_rule$; + DELETE FROM props$; + commit; + -- remove the queue ASYNC_TRIG_Q + dbms_streams_adm.remove_queue('ASYNC_TRIG_Q'); + + END clean_up_streams; + + -- for simplicity, all the necessary error condition checks and security + -- checks are omitted. + + PROCEDURE create_trigger(trig_owner IN varchar2, + trig_name IN varchar2, + tab_owner IN varchar2, + tab_name IN varchar2, + dml_events IN binary_integer, + for_each_row IN boolean DEFAULT TRUE, + when_clause IN varchar2 DEFAULT NULL, + action IN varchar2) IS + capture_name VARCHAR2(30); + apply_name VARCHAR2(30); + apply_status VARCHAR2(30); + stmt_buf VARCHAR2(20000); + flags NUMBER; + inst_scn number; + db varchar2(128); + cnt binary_integer; + full_name VARCHAR2(65); + dml_rule_c VARCHAR2(65); + ddl_rule_c VARCHAR2(65); + dml_rule_a VARCHAR2(65); + ddl_rule_a VARCHAR2(65); + + cursor col_c(tab_owner varchar2, tab_name varchar2) + IS select column_name, data_type from dba_tab_columns + where owner = tab_owner and table_name = tab_name; + BEGIN + + -- check whether trigger already exists + SELECT count(1) INTO cnt FROM async_trigger$ + WHERE trigger_owner = trig_owner and trigger_name = trig_name; + + IF cnt > 0 THEN + raise_application_error(-20009, + 'trigger ' || trig_owner || '.' || trig_name || 'already exists'); + END IF; + + full_name := '"' || tab_owner || '"."' || tab_name || '"'; + stmt_buf := 'CREATE PROCEDURE "' || trig_owner || '"."' || + trig_name; + + IF (not for_each_row) and when_clause IS NOT NULL THEN + raise_application_error(-20006, + 'table triggers cannot specify WHEN clause'); + END IF; + + IF for_each_row THEN + + stmt_buf := stmt_buf || + '" (lcr IN sys.lcr$_row_record, dml_events IN binary_integer) ' + || 'IS' || CRLF || ' old ' || full_name || '%rowtype; ' + || CRLF || ' new ' || full_name || '%rowtype; ' || CRLF || + ' rc NUMBER; ' || CRLF || + ' col_val SYS.ANYDATA; ' || CRLF || 'BEGIN' || CRLF ; + + -- now computes the old and new values for row triggers + stmt_buf := stmt_buf || + ' IF lcr.get_command_type() = ''INSERT'' THEN' || CRLF || + ' old := NULL; ' || CRLF || ' ELSE' || CRLF; + + FOR c_rec IN col_c(tab_owner, tab_name) LOOP + stmt_buf := stmt_buf || + ' col_val := lcr.get_value(''OLD'', ''' || + c_rec.column_name || ''');' || CRLF || + ' IF col_val IS NULL THEN ' || CRLF || + ' old.' || c_rec.column_name || ':= NULL; ' || CRLF || + ' ELSE ' || CRLF; + + IF c_rec.data_type = 'NUMBER' or c_rec.data_type = 'FLOAT' THEN + stmt_buf := stmt_buf || ' rc:= col_val.GETNUMBER(old.' || + c_rec.column_name ||'); ' || CRLF; + ELSIF c_rec.data_type = 'VARCHAR2' THEN + stmt_buf := stmt_buf || ' rc:= col_val.GETVARCHAR2(old.' || + c_rec.column_name ||'); ' || CRLF; + ELSIF c_rec.data_type = 'RAW' THEN + stmt_buf := stmt_buf || ' rc:= col_val.GETRAW(old.' || + c_rec.column_name ||'); ' || CRLF; + ELSIF c_rec.data_type = 'DATE' THEN + stmt_buf := stmt_buf || ' rc:= col_val.GETDATE(old.' || + c_rec.column_name ||'); ' || CRLF; + ELSIF c_rec.data_type = 'TIMESTAMP' THEN + stmt_buf := stmt_buf || ' rc:= col_val.GETTIMESTAMP(old.' || + c_rec.column_name ||'); ' || CRLF; + ELSE + raise_application_error(-20008, 'UNKNOWN data type'); + END IF; + + stmt_buf := stmt_buf || ' END IF; ' || CRLF; + END LOOP; + + stmt_buf := stmt_buf || ' END IF; ' || CRLF || + ' IF lcr.get_command_type() = ''DELETE'' THEN ' || CRLF || + ' new := NULL; ' || CRLF || ' ELSE' || CRLF; + + FOR c_rec IN col_c(tab_owner, tab_name) LOOP + stmt_buf := stmt_buf || + ' col_val := lcr.get_value(''NEW'', ''' || + c_rec.column_name || ''');' || CRLF || + ' IF col_val IS NULL THEN ' || CRLF || + ' new.' || c_rec.column_name || ':= NULL; ' || CRLF || + ' ELSE ' || CRLF; + + IF c_rec.data_type = 'NUMBER' or c_rec.data_type = 'FLOAT' THEN + stmt_buf := stmt_buf || ' rc:= col_val.GETNUMBER(new.' || + c_rec.column_name ||'); ' || CRLF; + ELSIF c_rec.data_type = 'VARCHAR2' THEN + stmt_buf := stmt_buf || ' rc:= col_val.GETVARCHAR2(new.' || + c_rec.column_name ||'); ' || CRLF; + ELSIF c_rec.data_type = 'RAW' THEN + stmt_buf := stmt_buf || ' rc:= col_val.GETRAW(new.' || + c_rec.column_name ||'); ' || CRLF; + ELSIF c_rec.data_type = 'DATE' THEN + stmt_buf := stmt_buf || ' rc:= col_val.GETDATE(new.' || + c_rec.column_name ||'); ' || CRLF; + ELSIF c_rec.data_type = 'TIMESTAMP' THEN + stmt_buf := stmt_buf || ' rc:= col_val.GETTIMESTAMP(new.' || + c_rec.column_name ||'); ' || CRLF; + ELSE + raise_application_error(-20008, 'UNKNOWN data type'); + END IF; + + stmt_buf := stmt_buf || ' END IF; ' || CRLF; + END LOOP; + + stmt_buf := stmt_buf || ' END IF; ' || CRLF; + + ELSE + stmt_buf := stmt_buf || + '" (dml_events IN binary_integer) IS' || CRLF || 'BEGIN' || + CRLF ; + END IF; + + IF (when_clause IS NOT NULL) THEN + stmt_buf := stmt_buf || ' IF ' || when_clause || ' THEN' || CRLF || + action || CRLF || ' END IF; ' || CRLF || 'END; '; + ELSE + stmt_buf := stmt_buf || action || CRLF || 'END; '; + END IF; + + -- create the trigger + execute immediate stmt_buf; + + -- insert into trigger table + IF for_each_row THEN + flags := 1; + ELSE + flags := 0; + END IF; + + insert into async_trigger$ values (tab_owner, tab_name, trig_owner, + trig_name, dml_events, flags); + commit; + + select trigger_capture, trigger_apply, trigger_apply_status into + capture_name, apply_name, apply_status from props$; + select global_name into db from global_name; + select count(*) into cnt from dba_apply_instantiated_objects + where source_object_owner = tab_owner and source_object_name = tab_name and + source_object_type = 'TABLE' and source_database = db; + + -- if table already has an instantiation scn registered, don't call + -- dbms_apply_adm.set_table_instantiation_scn() + + IF (cnt = 0) THEN + inst_scn := dbms_flashback.get_system_change_number(); + dbms_apply_adm.set_table_instantiation_scn( + source_object_name => full_name, + source_database_name => db, + instantiation_scn => inst_scn); + END IF; + + -- as a simplification, add one rule per-table for all triggers + -- on the table + select count(1) into cnt from async_trigger_rule$ + where owner = tab_owner and table_name = tab_name; + + IF cnt = 0 THEN + dbms_streams_adm.add_table_rules( + table_name => full_name, + streams_type => 'apply', + streams_name => apply_name, + queue_name => 'TRGADM.ASYNC_TRIG_Q', + include_tagged_lcr => true, + include_dml => true, + include_ddl => false, + source_database => db, + dml_rule_name => dml_rule_a, + ddl_rule_name => ddl_rule_a); + + dbms_apply_adm.set_dml_handler( + object_name => full_name, + object_type => 'TABLE', + operation_name => 'INSERT', + error_handler => false, + user_procedure => 'trgadm.async_trig_internal.dml_handler', + apply_database_link => NULL, + apply_name => apply_name); + + dbms_apply_adm.set_dml_handler( + object_name => full_name, + object_type => 'TABLE', + operation_name => 'UPDATE', + error_handler => false, + user_procedure => 'trgadm.async_trig_internal.dml_handler', + apply_database_link => NULL, + apply_name => apply_name); + + dbms_apply_adm.set_dml_handler( + object_name => full_name, + object_type => 'TABLE', + operation_name => 'DELETE', + error_handler => false, + user_procedure => 'trgadm.async_trig_internal.dml_handler', + apply_database_link => NULL, + apply_name => apply_name); + + dbms_streams_adm.add_table_rules( + table_name => full_name, + streams_type => 'capture', + streams_name => capture_name, + queue_name => 'TRGADM.ASYNC_TRIG_Q', + include_tagged_lcr => true, + include_dml => true, + include_ddl => false, + dml_rule_name => dml_rule_c, + ddl_rule_name => ddl_rule_c, + inclusion_rule => true); + + insert into async_trigger_rule$ values (tab_owner, tab_name, dml_rule_c, + dml_rule_a); + commit; + END IF; + + IF (apply_status = 'NOT STARTED') THEN + -- start capture and apply + dbms_apply_adm.set_parameter(apply_name => apply_name, + parameter => 'disable_on_error', + value => 'n'); + dbms_apply_adm.alter_apply( + apply_name => apply_name, + precommit_handler => 'trgadm.async_trig_internal.commit_handler'); + + dbms_apply_adm.start_apply(apply_name => apply_name); + dbms_capture_adm.start_capture(capture_name => capture_name); + + UPDATE props$ set trigger_apply_status = 'STARTED' + where trigger_capture = capture_name; + COMMIT; + END IF; + + END; + + procedure drop_trigger(trig_owner IN varchar2, + trig_name IN varchar2) IS + d_table VARCHAR2(30); + dml_evts binary_integer; + cnt NUMBER; + capture_name VARCHAR2(30); + apply_name VARCHAR2(30); + dml_rule_c VARCHAR2(65); + dml_rule_a VARCHAR2(65); + full_name VARCHAR2(65); + tab_owner VARCHAR2(30); + ob_does_not_exist EXCEPTION; + PRAGMA EXCEPTION_INIT(ob_does_not_exist, -4043); + BEGIN + + select table_owner, table_name, dml_events + into tab_owner, d_table, dml_evts + from async_trigger$ + where trigger_owner = trig_owner and trigger_name = trig_name; + + delete from async_trigger$ + where trigger_owner = trig_owner and trigger_name = trig_name; + + select count(1) into cnt from async_trigger$ + where table_owner = tab_owner and table_name = d_table; + commit; + + BEGIN + execute immediate 'drop procedure "' || + trig_owner || '"."' ||trig_name|| '"'; + EXCEPTION + WHEN ob_does_not_exist THEN + NULL; + WHEN others THEN + RAISE; + END; + + -- cleanup DML handler when necessary + select trigger_capture, trigger_apply into capture_name, apply_name + from props$; + + IF cnt = 0 THEN + BEGIN + select capture_rule, apply_rule into dml_rule_c, dml_rule_a + from async_trigger_rule$ + where owner = tab_owner and table_name = d_table; + + dbms_streams_adm.remove_rule(rule_name => dml_rule_c, + streams_type => 'CAPTURE', + streams_name => capture_name); + + dbms_streams_adm.remove_rule(rule_name => dml_rule_a, + streams_type => 'APPLY', + streams_name => apply_name); + full_name := '"' || tab_owner || '"."' || d_table || '"'; + dbms_apply_adm.set_dml_handler( + object_name => full_name, + object_type => 'TABLE', + operation_name => 'INSERT', + error_handler => false, + user_procedure => NULL, + apply_database_link => NULL, + apply_name => apply_name); + + dbms_apply_adm.set_dml_handler( + object_name => full_name, + object_type => 'TABLE', + operation_name => 'UPDATE', + error_handler => false, + user_procedure => NULL, + apply_database_link => NULL, + apply_name => apply_name); + + dbms_apply_adm.set_dml_handler( + object_name => full_name, + object_type => 'TABLE', + operation_name => 'DELETE', + error_handler => false, + user_procedure => NULL, + apply_database_link => NULL, + apply_name => apply_name); + EXCEPTION + WHEN no_data_found THEN + NULL; + WHEN OTHERS THEN + RAISE; + END; + END IF; + END; + + PROCEDURE add_table_dml(tab_owner IN varchar2, + tab_name IN varchar2, + dml_evts IN binary_integer) IS + tab_found boolean; + BEGIN + tab_found := FALSE; + FOR i IN 1 .. tabdml.count LOOP + IF tabdml(i).owner = tab_owner and tabdml(i).table_name = tab_name and + tabdml(i).dml = dml_evts THEN + tab_found := TRUE; + EXIT; + END IF; + END LOOP; + + IF NOT tab_found THEN + tabdml.extend(1); + tabdml(tabdml.count) := table_dml(tab_owner, tab_name, dml_evts); + END IF; + END; + + PROCEDURE dml_handler(in_any IN ANYDATA) IS + lcr SYS.LCR$_ROW_RECORD; + rc PLS_INTEGER; + commnd varchar2(30); + dml_evts binary_integer; + flags binary_integer; + cursor trg_c(tab_owner varchar2, tab_name varchar2, evts number) + IS select trigger_owner, trigger_name + from trgadm.async_trigger$ + where table_owner = tab_owner and table_name = tab_name and + bitand(dml_events, evts) > 0 and flags = 1; + tab_owner VARCHAR2(30); + tab_name VARCHAR2(30); + BEGIN + -- get LCR info + rc := in_any.getobject(lcr); + + -- Fire row triggers + commnd := lcr.get_command_type(); + IF commnd = 'INSERT' THEN + dml_evts := on_insert; + ELSIF commnd = 'UPDATE' THEN + dml_evts := on_update; + ELSIF commnd = 'DELETE' THEN + dml_evts := on_delete; + ELSE + dml_evts := 0; + END IF; + + IF dml_evts > 0 THEN + tab_owner := lcr.get_object_owner(); + tab_name := lcr.get_object_name(); + + -- remember to fire table triggers in the commit handler + add_table_dml(tab_owner, tab_name, dml_evts); + + FOR t_rec IN trg_c(tab_owner, tab_name, dml_evts) LOOP + execute immediate 'begin "' || t_rec.trigger_owner || '"."' || + t_rec.trigger_name || '"(:1, :2); end;' using + lcr, dml_evts; + END LOOP; + END IF; + END; + + PROCEDURE commit_handler(scn IN number) IS + cursor trg_c(tab_owner varchar2, tab_name varchar2, evts number) + IS select trigger_owner, trigger_name + from trgadm.async_trigger$ + where table_owner = tab_owner and table_name = tab_name and + bitand(dml_events, evts) > 0 and flags = 0; + BEGIN + + -- fire table triggers here + FOR i in 1 .. tabdml.count LOOP + FOR t_rec IN trg_c(tabdml(i).owner, tabdml(i).table_name, + tabdml(i).dml) LOOP + execute immediate 'begin "' || t_rec.trigger_owner || '"."' || + t_rec.trigger_name || '"(:1); end;' using tabdml(i).dml; + END LOOP; + END LOOP; + + tabdml.delete; + END; + +end; +/ diff --git a/strmats.sql b/strmats.sql new file mode 100644 index 0000000..869b377 --- /dev/null +++ b/strmats.sql @@ -0,0 +1,60 @@ +connect sys/knl_test7 as sysdba +drop user trgadm cascade +/ +grant dba to trgadm identified by trgadm +/ +begin + dbms_streams_auth.grant_admin_privilege( + grantee => 'trgadm', + grant_privileges => true); +end; +/ +grant create any procedure to trgadm +/ +grant drop any procedure to trgadm +/ +grant execute any procedure to trgadm +/ +grant select on dba_tab_columns to trgadm +/ + +connect trgadm/trgadm + +create table async_trigger$ ( + table_owner VARCHAR2(30), + table_name VARCHAR2(30), + trigger_owner VARCHAR2(30), + trigger_name VARCHAR2(30), + dml_events NUMBER, + flags NUMBER) +/ + +create table async_trigger_rule$( + owner VARCHAR2(30), + table_name VARCHAR2(30), + capture_rule VARCHAR2(65), + apply_rule VARCHAR2(65)) + / + +create table props$ ( + trigger_capture VARCHAR2(30), + trigger_apply VARCHAR2(30), + trigger_apply_status VARCHAR2(30)) +/ + +create index async_trigger_i1 on async_trigger$(table_owner, table_name) +/ +create unique index async_trigger_i2 on async_trigger$(trigger_owner, +trigger_name) +/ + +create type table_dml IS object ( + owner varchar2(30), + table_name varchar2(30), + dml number) +/ + +create type table_dml_list is varray(1024) of table_dml +/ + +@@strmatp.sql diff --git a/strmatu.sql b/strmatu.sql new file mode 100644 index 0000000..b5d343f --- /dev/null +++ b/strmatu.sql @@ -0,0 +1,125 @@ +/* + ************* asynchronous commit-time trigger using Streams ************* + + This script creates two row triggers and a table trigger on + table u1.accounts, recording any changes to user Alice's balance. + +*/ + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 + +SET ECHO ON +connect sys/knl_test7 as sysdba; +grant connect, resource to u1 identified by u1; + +connect trgadm/trgadm +exec async_trig_pkg.set_up_streams('ACCOUNT_CAPTURE', 'ACCOUNT_APPLY'); + +connect u1/u1 +create table accounts(name varchar2(30), balance number); +create table account_history (event_name varchar2(30), + event_time timestamp, + name varchar2(30), + old_balance number, + new_balance number); + +DECLARE + trigger_action VARCHAR2(1000); +BEGIN + + -- first, create an insert trigger, for each row + trigger_action := 'INSERT INTO u1.account_history values (''INSERT'', ' || + 'SYSTIMESTAMP, new.name, NULL, new.balance); '; + async_trig_pkg.create_trigger(trigger_owner => 'U1', + trigger_name => 'ACCOUNT_TRIG1', + table_owner => 'U1', + table_name => 'ACCOUNTS', + dml_events => async_trig_pkg.on_insert, + for_each_row => TRUE, + when_clause => 'new.name = ''ALICE''', + action => trigger_action); + + -- then, create an update/delete trigger, for each row + trigger_action := 'IF bitand(dml_events, async_trig_pkg.on_update) = ' || + 'async_trig_pkg.on_update THEN ' || + 'INSERT INTO u1.account_history values (''UPDATE'', ' || + 'SYSTIMESTAMP, old.name, old.balance, new.balance); ' || + ' ELSE ' || + 'INSERT INTO u1.account_history values (''DELETE'', ' || + 'SYSTIMESTAMP, old.name, old.balance, NULL); ' || + ' END IF; '; + async_trig_pkg.create_trigger(trigger_owner => 'U1', + trigger_name => 'ACCOUNT_TRIG2', + table_owner => 'U1', + table_name => 'ACCOUNTS', + dml_events => async_trig_pkg.on_update + + async_trig_pkg.on_delete, + for_each_row => TRUE, + when_clause => 'old.name = ''ALICE''', + action => trigger_action); + + -- last, create an insert/update/delete table trigger + trigger_action := 'INSERT INTO u1.account_history values (''DML'', ' || + 'SYSTIMESTAMP, NULL, NULL, NULL); '; + async_trig_pkg.create_trigger(trigger_owner => 'U1', + trigger_name => 'ACCOUNT_TRIG3', + table_owner => 'U1', + table_name => 'ACCOUNTS', + dml_events => async_trig_pkg.on_update + + async_trig_pkg.on_insert + + async_trig_pkg.on_delete, + for_each_row => FALSE, + action => trigger_action); + +END; +/ + +insert into accounts values ('ALICE', 1000); +commit; + +update accounts set balance = 2000 where name = 'ALICE'; +commit; + +delete from accounts where name= 'ALICE'; +commit; + +insert into accounts values ('BOB', 500); +commit; + +connect system/manager +declare +scn number; +cscn number; +slept number := 0; +begin + + -- Get current scn + scn := dbms_flashback.get_system_change_number; + while (slept < 1200) loop + dbms_lock.sleep(15); + slept := slept + 15; + begin + select lwm_message_number into cscn from gv$streams_apply_coordinator + where apply_name = 'ACCOUNT_APPLY'; + exception + when no_data_found + then cscn := 0; + when others then raise; + end; + if cscn >= scn then + exit; + end if; + end loop; +end; +/ + +connect u1/u1 +select * from account_history order by event_name, event_time; + +connect trgadm/trgadm +exec async_trig_pkg.clean_up_streams; diff --git a/strmmon.c b/strmmon.c new file mode 100644 index 0000000..a884011 --- /dev/null +++ b/strmmon.c @@ -0,0 +1,3845 @@ +/* Copyright (c) 2004, 2008, Oracle. All rights reserved. */ + +/* + + NAME + strmmon.c - STReams MONitor : used for Streams diagnostics + + DESCRIPTION + used for Streams diagnostics + + NOTES + Serves as an example for simple queries to monitor Streams performance. + + MODIFIED (MM/DD/YY) + snalla 06/06/08 - turn off domain controller authentication + rmao 09/26/07 - bug 6367892, add event message of knlslmw + snalla 09/07/07 - lrglrf1 3095832 do not include unistd.h on win32 + platform - adding changes reverted from bpwang_lrg-1938240 + tianli 02/27/07 - lrg 2858006: variable "status" fix + yizhang 08/16/06 - Fix bug 5382689 + yizhang 04/07/06 - Fix bug 5118340. + yizhang 09/29/05 - Collect the time used in wait events for all stream + related processes. + narora 09/13/05 - code hygiene + narora 08/12/05 - add propagation bandwidth + narora 04/27/05 - bug 4334913: fix LOG stats + narora 03/31/05 - print memsize with M acronym + narora 03/18/05 - print streams pool size repeatedly + narora 03/14/05 - bug 4204079: add destination to check for old prop + narora 02/04/05 - bug 4164092: -sysdba option shouldn't coredump + sbalaram 10/06/04 - indicate backlogs, flow control + sbalaram 08/17/04 - sbalaram_streams_diagnostics + sbalaram 07/26/04 - enhancements + narora 11/18/03 - fix flushing to file + narora 09/12/03 - handle errors if the anydata queue doesn't have + any buffered enqueues + narora 09/12/03 - + +*/ + +/***************************************************************************** + + STRMMON - Streams Monitoring Program + ------------------------------------ + +Overview: +-------- +STRMMON is a monitoring tool focused on Oracle Streams. Using this +tool, database administrators get a quick overview of the Streams +activity occurring within a database. In a single line display, strmmon +reports information. The reporting interval and number of iterations to +display are configurable. + +Usage: +----- +There are 7 command line input parameters for STRMMON: interval, count, +user, passw, dbname, sysdba, long. The first 2 parameters (interval and count) +control the sampling rate and the amount of output. The next 4 +parameters specify the connect information to the particular Streams +database. Specifying the last parameter displays cumulative information +rather than rate information, which is printed by default. + +When the command "strmmon" is issued without any parameters, a usage +message is displayed: + +% strmmon + +Usage: strmmon -interval -count [-user ] + [-passw ] [-dbname ] [-sysdba] + [-long] + +Parameters: +---------- +-interval The interval in seconds at which STRMMON will monitor the + database. To specify that the sampling rate to be every 3 + seconds: + -interval 3 + This is a required parameter for strmmon. + +-count The number of iterations to monitor the Streams environment. + To specify 5 iterations, use the following: + -count 5 + This is a required parameter for strmmon. + +-user The schema name for logging into the database. Any schema name + can be specified. If the SYS schema is specified, additional + information is displayed. To specify the SYSTEM schema, use + -user SYSTEM + This parameter should not be specified if logging in as + "/ as sysdba" is desired. + -user is an optional parameter for strmmon. + +-passw The login password for the schema identified with the -user + clause. To specify the password for the SYSTEM schema, use + -passw oracle + This parameter should not be specified if logging in as + "/ as sysdba" is desired. + -passw is an optional parameter for strmmon. + +-dbname The connection information or service name from tnsnames.ora + for the specific database to be monitored. To specify the connect + information for the monitored database, use + -dbname ORCL.WORLD + This is an optional parameter for strmmon. + +-sysdba This flag indicates that the login role is SYSDBA. This optional + parameter is typically used with the SYS schema. To specify the + login role SYSDBA, use + -sysdba + When logging in as "/ as sysdba", the -user and -passw + parameters are not required. + +-long Indication to print a detailed report for capture, apply + and propagation. + -long is an optional parameter. + By default, only the capture, apply and propagation rates are + displayed. + + +Output: +------ +The strmmon output begins with a banner line identifying the program parameters +and database. This information is followed with a brief description of the +major components of the output display. An example of this identifying output +is shown below: + +% strmmon -interval 5 -count 5 -sysdba + +STREAMS Monitor, v 2.5 Copyright Oracle Corp. 2002, 2005. +Interval = 5, Count=5 + +Logon= @ ORACLE 11.1.0.2.0 + +Streams Pool Size = 152M + +LOG : +NET: +Cxxx: +MEM : % +PRxx: +Qx : +PSxx: +Axxx: +: flow control in effect +: potential bottleneck +AR: apply reader +AS(n): n number of apply server +: +xx->: database instance name + +The following example shows the identifying output for "-long" option. + +% strmmon -long -interval 5 -count 5 -sysdba + +STREAMS Monitor, v 2.5 Copyright Oracle Corp. 2002, 2005. +Interval = 5, Count=5 + +Logon= @ ORACLE 11.1.0.2.0 + +Streams Pool Size = 152M + +LOG : +NET: +Cxxx: +MEM : % +PRxx: / +Qx : / +PSxx: / +Axxx: +: flow control in effect +: potential bottleneck +AR: apply reader +AS(n): n number of apply servers +: +xx->: database instance name + + +Note: The information about the Streams Pool Size is displayed only for +database versions greater than or equal to 10gR1. The wait event percentages +for propagation receiver are displayed only for database version greater than +or equal to 10gR2. The wait event percentages for the rest components are +displayed only for database version greater than or equal to 10gR1. + + +After this initial information about the program, Strmmon produces a single +line of output representing the current status of Oracle Streams after the +requested interval for each iteration . For example, if strmmon is invoked with +"-interval 5 -count 5", a line of output will be displayed every 5 seconds. +After 5 lines have been displayed (25 seconds), the monitoring will end. + +Each line is composed of multiple blocks of information dependent on the +Streams processes configured within the database. These blocks are displayed +by a keyword to identify the component followed by the statistics for that +particular component. The separator between the components is the "|" symbol. + +There are 6 components for Streams: LOG, Cxxx, Qx, PSxx, PRxx, Axxx. +Except for the LOG component, multiple occurrences of each component are +possible dependent on the streams processes configured at database. + + +LOG + +Information about the redo log activity is written in this block. The statistic +following the LOG: keyword gives the redo generated per second. If the "-long" +option is specified, then the first statistic following the LOG: keyword is the +current SCN that has been written to the redo log. This number represents the +current activity within the database. If this number does not increase, no +activity is occurring on the database. The second statistic is the last block +number written in the redo log. Redo blocks are always 512 bytes, so this +statistic can be used to calculate the amount of redo generated between +intervals. The output for the LOG component is always the first entry after the +timestamp on the display and appears as follows: + +2006-10-27 11:48:55 | LOG 440569 325388 +2006-10-27 11:49:00 | LOG 440609 325389 +2006-10-27 11:49:05 | LOG 440650 325391 +2006-10-27 11:49:10 | LOG 440691 325393 +2006-10-27 11:49:15 | LOG 440732 325395 + +In the above example, the current scn written to the redo log is 440569 and +the last block number is 325388. Since the strmmon command was issued with +-interval 5 -count 5, 5 lines of output are displayed with a 5 second interval +between them. + + +Cxxx + +For each capture process configured in the database, a separate block will be +displayed. Each block displays the number of lcrs captured per sec, number of +lcrs enqueued per sec and the capture latency. If "-long" option is specified, +then in each block, the Logminer read scn, the total number of messages +captured from the redo log and the most recent scn captured from the redo log +are shown. In addition, the number of messages that match the rules specified +for the capture process including the most recent message scn enqueued are +shown along with the capture latency. + +One can also use the difference between successive capture "messages captured" +statistics to determine the rate at which capture is mining the redo log. The +enqueue scn of capture is an indicator of where the capture process will +restart, if capture is stopped and restarted while the database is running. +This statistic can also be used for comparison with the appropriate database +Apply process high-water mark scn. If these statistics match, the capture and +apply are caught up and the data is synchronized. + +It lists the percentage of idle events, flow control events, and one of the +most significant wait event for the capture process if the database version +is 10gR1 or higher. + +MEM + +If strmmon is run from the SYS schema connected as SYSDBA, and the +database version is 10gR1 or higher, then this displays the percentage +of Streams Pool memory currently in use and the total size of the +streams pool. + + +Qx + +For each streams queue in the database, a seperate block displays the +queue identifier, the cummulative message rate and the spill rate. If +"-long" option is specified, then for each streams queue in the +database, a separate block will display the queue identifier as well +as the number of outstanding messages in the buffered queue, the +cumulative number of messages that have been in the queue and the +number of messages spilled from memory to disk. In version 9iR2, the +number of messages currently spilled is displayed. In 10gR1, the +cumulative number of messages spilled is displayed. For 9iR2, the +default and the "-long" option display the same data. + +The queue identifier (QID) can be used to identify the name of the +queue. Use the QID in queries against the DBA_QUEUES view to identify +the particular queue in the database. In 9i, the number of outstanding +messages in the buffered queue is only displayed if strmmon is run +from the SYS schema as SYSDBA. In 9iR2, if the number of spilled +messages becomes non-zero, consider stopping capture temporarily to +slow down the flow of data. + +PSxx + +For each propagation sender, the number of lcrs propagated per sec is +displayed. If "-long" option is specified, then for each propagation, +the total number of messages and the total number of bytes propagated to +the destination site and the total time needed to propagate those messages +is displayed. + +It lists the percentage of idle events, flow control events, and one of the +most significant wait event for the propagation sender process if the +database version is 10gR2 or higher. + +PRxx + +For each propagation receiver, the number of messages received per sec is +displayed. If "-long" option is specified, then for each propagation, +the total number of messages received and the total time needed to receive +those messages is displayed. + +It lists the percentage of idle events, flow control events, and one of the +most significant wait event for the propagation receiver process if the +database version is 10gR1 or higher. + +Axxx + +For each apply process, the number of lcrs dequeued per sec and the dequeue +latency are displayed. If the "-long" option is specified, then for each +apply process in the database, in addition to the total messages dequeued +and the most recent scn dequeued by the apply reader, the dequeue latency, the +total number of transactions received, assigned and applied by the coordinator +are displayed. The apply high water mark scn along with the apply high water +mark latency is also shown. This statistic records the most recent scn from +the source site that has been applied at the destination site. + +It lists the percentage of idle events, flow control events, and one of the +most significant wait event for the apply reader process and the apply server +processes if the database version is 10gR1 or higher. + + + +This indicates that the capture process is blocked due to flow control. + + + +This indicates that the capture or apply process is currently a bottleneck. + +xx-> + +This indicates the name of the database instance for which the data follows. + + +Installation: +------------ +Before compiling and linking the strmmon program, make sure that the +ORACLE_HOME and LD_LIBRARY_PATH environmental variables are set up +appropriately. First delete any old executable, and then compile and link: + + rm -f strmmon strmmon.o; make -f demo_rdbms.mk strmmon + +After the program has been compiled and linked, strmmon can be used for +monitoring a Streams environment. + +******************************************************************************/ + +/* for WINDOWS compatibility of 'sleep' call */ +#if defined(WIN32COMMON) || defined(WIN32) || defined(_WIN32) +#include +#define sleep(x) Sleep(1000*(x)) +#endif + +/* for WINDOWS compatibility of 'strncasecmp' call */ +#if defined(WIN32COMMON) || defined(WIN32) || defined(_WIN32) +#define strncasecmp strnicmp +#endif + +#ifndef ORATYPES +#include +#endif + +#ifndef _STDIO_H +#include +#endif + +#ifndef _STDLIB_H +#include +#endif + +#ifndef _STRING_H +#include +#endif + +#ifndef _SYS_TYPES_H +#include +#endif + +#ifndef _TIME_H +#include +#endif + +#if !(defined(WIN32COMMON) || defined(WIN32) || defined(_WIN32)) +#ifndef _UNISTD_H +#include +#endif +#endif + +#ifndef _SIGNAL_H +#include +#endif + +#ifndef OCI_ORACLE +#include +#endif + +#define VERSION_9iR2 92020 +#define VERSION_10g 101010 +#define VERSION_10gR2 102000 + +typedef enum process_type + {CAPTURE_PROCESS=1, PR_SENDER_PROCESS=2, + PR_RECEIVER_PROCESS=3, APPLY_READER=4, APPLY_SERVER=5} + process_type_t; + +/*STREAMS capture process waiting for archive log + *and wait for transaction are the idle events for 10.1 version + */ +static const char* capture_idle_events = + {"|LogMiner: client waiting for transaction||events in waitclass Other||Streams capture: waiting for archive log||wait for transaction||STREAMS capture process waiting for archive log|"}; + /*"LogMiner: wakeup event for builder", + "LogMiner: wakeup event for preparer" */ + +/* waiting for subscribers to catch up is the flowcontrol event for 10.1 + * version. Rest events are for 10.2 and above. */ +static const char* capture_flowcontrol_events = + {"|Streams capture: waiting for subscribers to catch up||Streams capture: resolve low memory condition||Streams: resolve low memory condition||waiting for subscribers to catch up|"}; + +static const char* propagation_sender_idle_events = + {"|wait for unread message on broadcast channel||jobq slave wait|"}; + +static const char* propagation_sender_flowcontrol_events = + {"|SQL*Net more data to dblink||SQL*Net message from dblink|"}; + +static const char* propagation_receiver_idle_events = + {"|SQL*Net more data from client||SQL*Net message from client||Streams AQ: qmn slave idle wait|"}; + +static const char* propagation_receiver_flowcontrol_events = + { "|Streams AQ: enqueue blocked on low memory||Streams AQ: enqueue blocked due to flow control|"}; + +/*queue messages & knlqdeq is the idle wait events for 10.1 version*/ +static const char* apply_reader_idle_events = + {"|Streams AQ: waiting for messages in the queue||queue messages||knlqdeq|"}; + +static const char* apply_reader_flowcontrol_events = + {"|rdbms ipc message|"}; + +static const char* apply_server_idle_events = + {"|rdbms ipc message|"}; + +static const char* apply_server_flowcontrol_events = + {"||"}; + +typedef struct options +{ + ub4 interval; + ub4 elapstim; /* The elape time in one-hundredth of second */ + ub4 count; + ub4 iters; + ub1 short_opt; +} options_t; + +typedef struct oci +{ + OCIEnv * envp; + OCIError * errp; + OCIServer * srvp; + OCISvcCtx * svcp; + OCISession * authp; + OCIStmt * stmtp; + OCIStmt * stmt2p; + OCIStmt * stmt3p; + struct oci *nxt_oci; +} oci_t; + +typedef struct sid_pval +{ + ub4 sid; + void * pval; + process_type_t type; + struct sid_pval *next; +} sid_pval_t; + +typedef struct event_pval +{ + /* For apply server, it contains the number of apply server process. + For other process, it is the sid of that process. */ + ub4 sidnum; + oratext event_name[128]; + ub2 event_namelen; + ub4 iters; + ub8 time_in_micro_second; + ub8 time_in_micro_second_old; + struct event_pval *next_event; +} event_pval_t; + +typedef struct cap_pval +{ + ub4 capturenum; + oratext capturename[128]; + ub2 capturenamelen; + OCINumber read_scn; + ub4 total_captured; + ub4 total_enqueued; + ub4 elapsed_pause_time; + boolean flow_ctrl; + struct event_pval *pevent; + struct cap_pval *next_cap; +} cap_pval_t; + +typedef struct app_pval +{ + ub4 applynum; + oratext applyname[128]; + ub2 applynamelen; + ub4 total_applied; + ub4 txns_applied; + struct event_pval *pevent_reader; + struct event_pval *pevent_server; + struct app_pval *next_app; + ub4 server_num; +} app_pval_t; + +typedef struct prop_pval +{ + ub4 src_queueid; + ub4 dst_queueid; + oratext src_queuename[30]; + ub2 src_queuenamelen; + oratext src_schemaname[30]; + ub2 src_schemanamelen; + oratext src_dbname[128]; + ub2 src_dbnamelen; + oratext dst_queuename[30]; + ub2 dst_queuenamelen; + oratext dst_schemaname[30]; + ub2 dst_schemanamelen; + oratext dst_dbname[128]; + ub2 dst_dbnamelen; + char *destination[128]; + ub2 destination_len; + ub4 total_number; + ub8 total_bytes; + struct event_pval *pevent_sender; + struct event_pval *pevent_receiver; + struct prop_pval *next_prop; +} prop_pval_t; + +typedef struct que_pval +{ + ub4 queueid; + ub4 cnummsgs; + ub4 cspillmsgs; + struct que_pval *next_que; +} que_pval_t; + +typedef struct connection +{ + oratext * user; + ub4 userlen; + oratext * passw; + ub4 passwlen; + oratext * dbname; + ub4 dbnamelen; + oratext instname[128]; + ub2 instnamelen; + oratext versionstr[20]; + ub2 versionstrlen; + ub4 version; + ub1 sysdba; + ub1 sysuser; + + struct connection * next_connection; + + oci_t *ocip; + cap_pval_t *cap_pval; + app_pval_t *app_pval; + que_pval_t *que_pval; + prop_pval_t *prop_pval; + sid_pval_t *sid_pval; + ub4 num_sid; + ub4 org_sid; + ub4 lgwr_pval; + ub8 client_bytes; + ub8 dblink_bytes; + char sidstr[2048]; +} connection_t; + +typedef struct queue +{ + ub4 queueid; + oratext queuename[128]; + ub2 queuenamelen; + oratext schemaname[128]; + ub2 schemanamelen; + ub4 cnummsgs; + ub4 cspillmsgs; + ub4 nummsgs; +} queue_t; + +#define OCICALL(ocip, function) do {\ +sword status=function;\ +if (OCI_SUCCESS==status) break;\ +else if (OCI_SUCCESS_WITH_INFO==status) \ +{puts((char *)"Error: OCI_SUCCESS_WITH_INFO");\ +exit(1);}\ +else if (OCI_NEED_DATA==status) \ +{puts((char *)"Error: OCI_NEED_DATA");\ +exit(1);}\ +else if (OCI_NO_DATA==status) \ +{puts((char *)"Error: OCI_NO_DATA");\ +exit(1);}\ +else if (OCI_ERROR==status) \ +{ocierror(ocip, (char *)"OCI_ERROR", TRUE);\ +exit(1);}\ +else if (OCI_INVALID_HANDLE==status) \ +{puts((char *)"Error: OCI_INVALID_HANDLE");\ +exit(1);}\ +else if (OCI_STILL_EXECUTING==status) \ +{puts((char *)"Error: OCI_STILL_EXECUTING");\ +exit(1);}\ +else if (OCI_CONTINUE==status) \ +{puts((char *)"Error: OCI_CONTINUE");\ +exit(1);}\ +else {printf("Error: unknown status %d\n", status);\ +exit(1);}\ +} while(0) + + +static void get_options(options_t * opts, connection_t ** first_conn, int argc, + char ** argv); +static void print_usage(int exitcode); +static void oraconnect(options_t * opts, connection_t * connp); +static void oradisconnect(oci_t * ocip); +static void ocierror(oci_t * ocip, char * msg, boolean stop_on_error); +static void print_header(options_t * opts, connection_t * connp); +static void print_stats(options_t * opts, connection_t * connp); +static void print_capture_stats(options_t * opts, connection_t * connp, + oci_t * ocip, cap_pval_t ** cap_pval); +static void print_short_capture_stats(options_t * opts, + connection_t * connp, oci_t * ocip, cap_pval_t ** cap_pval); +static void print_queue9i_stats(options_t * opts, connection_t * connp, + oci_t * ocip, prop_pval_t ** prop_pval); +static void print_queue_stats(options_t * opts, connection_t * connp, + oci_t * ocip, que_pval_t ** que_pval, prop_pval_t ** prop_pval); +static void print_prop_receiver_stats(options_t * opts, connection_t * connp, + oci_t * ocip, queue_t* que, + prop_pval_t ** prop_pval, + unsigned *pnum_ptr); +static void print_prop_sender_stats(options_t * opts, connection_t * connp, + oci_t * ocip, ub4 queueid, + prop_pval_t ** prop_pval, + unsigned *pnum_ptr); +static void print_apply_stats(options_t * opts, connection_t * connp, + oci_t * ocip, app_pval_t ** app_pval); +static void print_short_apply_stats(options_t * opts, connection_t * connp, + oci_t * ocip, app_pval_t ** app_pval); +static void get_version(connection_t * connp); +static void print_log_stats(options_t * opts, oci_t * ocip, ub4 *lgwr_pval); +static void print_net_stats(options_t * opts, connection_t * connp); +static void print_pool_size(oci_t * ocip); +static void print_mem_stats(options_t * opts, oci_t * ocip); +static void print_latency(sb4 latency); +static void print_bytes(ub8 bytes); +static void collect_event_data (options_t * opts, connection_t * connp); +static void print_event_stats(options_t * opts, void* pval, process_type_t type); + +int main(int argc, char ** argv) +{ + options_t opts; + connection_t *first_conn = (connection_t *)NULL; + connection_t *cur_conn; + time_t ptim = 0; + time_t tim; + struct tm * ltime; + + /* store the command line arguments */ + get_options(&opts, &first_conn, argc, argv); + + /* initialize each connection */ + for (cur_conn = first_conn; + cur_conn != (connection_t *)NULL; + cur_conn = cur_conn->next_connection) + { + /* connect to the database */ + oraconnect(&opts, cur_conn); + + /* get the version of ORACLE for current database */ + get_version(cur_conn); + + /* print header for current database */ + print_header(&opts, cur_conn); + + /* Set the number of sids to 0 */ + cur_conn->num_sid = 0; + cur_conn->org_sid = 0; + } + + opts.elapstim = opts.interval * 100; + + for (opts.iters = 0; opts.iters < opts.count; opts.iters++) + { + if (opts.iters) { + sleep(opts.interval); + } + + tim = time(NULL); + ltime = localtime(&tim); + + /* first print the current time */ + printf("%d-%02d-%d %02d:%02d:%02d", + (ltime->tm_year)+1900, (ltime->tm_mon)+1, ltime->tm_mday, + ltime->tm_hour, ltime->tm_min, ltime->tm_sec); + + /* don't sleep in the first iteration */ + if (opts.iters) { + opts.elapstim = (ub4)(difftime(tim, ptim) * 100); + } + + ptim = tim; + + for (cur_conn = first_conn; + cur_conn != (connection_t *)NULL; + cur_conn = cur_conn->next_connection) + { + /* print stats for current database */ + printf(" || %.*s->", cur_conn->instnamelen, cur_conn->instname); + print_stats(&opts, cur_conn); + } + + /* flush the current line of output */ + fprintf(stdout, "\n"); + fflush(stdout); + } + + for (cur_conn = first_conn; + cur_conn != (connection_t *)NULL; + cur_conn = cur_conn->next_connection) + { + oradisconnect(cur_conn->ocip); + } + + return 0; +} + +static void ocierror(oci_t * ocip, char * msg, boolean stop_on_error) +{ + sb4 errcode=0; + text bufp[4096]; + + if (ocip->errp) + { + OCIErrorGet((void *) ocip->errp, (ub4) 1, (text *) NULL, &errcode, + bufp, (ub4) 4096, (ub4) OCI_HTYPE_ERROR); + printf("%s: %s", msg, bufp); + } + else + puts(msg); + + if (stop_on_error) + exit(1); +} + +static void get_options(options_t * opts, connection_t ** first_conn, int argc, + char ** argv) +{ + char * option; + char * value; + connection_t *cur_connection = NULL; + connection_t *new_connection = NULL; + connection_t *prev_connection = NULL; + + /* clear the options */ + memset(opts, 0, sizeof(*opts)); + + /* The default option is the short option */ + opts->short_opt = 1; + + if (argc == 1) + { + print_usage(0); + } + + while(--argc) + { + /* get the option name */ + argv++; + option = *argv; + + /* check that the option begins with a "-" */ + if (!strncmp(option, (char *)"-", 1)) + { + option ++; + } + else + { + printf("Error: bad argument %s\n", option); + exit(1); + } + + /* check if its a boolean option */ + if (!strncmp(option, (char *)"sysdba", 6)) + { + if (!cur_connection) + { + /* allocate and clear a new connection options parameter */ + cur_connection = (connection_t *)malloc(sizeof(connection_t)); + memset(cur_connection, 0, sizeof(connection_t)); + /* for a blank username password a single byte user password still + * needs to be given */ + cur_connection->user = (oratext *)" "; + cur_connection->userlen = 1; + cur_connection->passw = (oratext *)" "; + cur_connection->passwlen = 1; + + if (*first_conn == (connection_t *) NULL) + { + *first_conn = cur_connection; + } + else + { + prev_connection->next_connection = cur_connection; + } + } + cur_connection->sysdba = 1; + /* sysdba is the last option for a connection */ + prev_connection = cur_connection; + cur_connection = (connection_t *)0; + + continue; + } + + if (!strncmp(option, (char *)"long", 4)) + { + opts->short_opt = 0; + continue; + } + + /* get the value of the option */ + --argc; + argv++; + if (!argc) + { + printf("Error: option '%s' needs a value\n", option); + exit(1); + } + value = *argv; + + if (!strncmp(option, (char *)"int", 3)) + { + opts->interval = (ub4) atol(value); + if (!opts->interval) + { + printf("Error: interval must be +ve\n"); + } + } + else if (!strncmp(option, (char *)"count", 5)) + { + opts->count = (ub4) atol(value); + if (!opts->count) + { + printf("Error: count must be +ve\n"); + } + } + else if (!strncmp(option, (char *)"user", 4)) + { + for (cur_connection = *first_conn; + cur_connection != (connection_t *)NULL; + cur_connection = cur_connection->next_connection) + prev_connection = cur_connection; + ; + new_connection = (connection_t *)malloc(sizeof(connection_t)); + memset(new_connection, 0, sizeof(connection_t)); + new_connection->user = (oratext *)value; + new_connection->userlen = strlen(value); + new_connection->next_connection = (connection_t *)NULL; + cur_connection = new_connection; + + if (*first_conn == (connection_t *) NULL) + { + *first_conn = new_connection; + } + else + { + prev_connection->next_connection = new_connection; + } + } + else if (!strncmp(option, (char *)"passw", 5)) + { + if (!cur_connection) + { + print_usage(1); + } + else + { + cur_connection->passw = (oratext *)value; + cur_connection->passwlen = strlen(value); + } + } + else if (!strncmp(option, (char *)"dbname", 6)) + { + if (!cur_connection) + { + print_usage(1); + } + else + { + cur_connection->dbname = (oratext *)value; + cur_connection->dbnamelen = strlen(value); + } + } + else + { + printf("Error: unknown option %s\n", option); + exit(1); + } + } + + if (!opts->interval || !opts->count) + { + print_usage(1); + } + + /* for each connection set the "sysuser" flag if either + * the username is SYS + * or + * the connection is made AS SYSDBA + */ + for (cur_connection = *first_conn; + cur_connection != (connection_t *)NULL; + cur_connection = cur_connection->next_connection) + { + if (cur_connection->sysdba || + (!strncasecmp((char *)cur_connection->user,(char *)"SYS",3) && + (cur_connection->userlen==3))) + { + cur_connection->sysuser = 1; + } + } + + /* + if (!opts->userlen) + { + opts->userlen = 1; + opts->user=(oratext *)" "; + } + if (!opts->passwlen) + { + opts->passwlen = 1; + opts->passw= (oratext *)" "; + } + */ +} + +static void print_usage(int exitcode) +{ + puts((char *)"Usage: strmmon -interval -count " + " [-user ]" + "\n" + " [-passw ] [-dbname ] [-sysdba]" + "\n" + " [-long]" + "\n"); + + exit(exitcode); +} + +static void oraconnect(options_t * opts, connection_t * connp) +{ + oci_t * ocip = connp->ocip = (oci_t *)malloc(sizeof(oci_t)); + + if (OCIEnvCreate(&ocip->envp, OCI_OBJECT, (void *)0, + (void * (*)(void *, size_t)) 0, + (void * (*)(void *, void *, size_t))0, + (void (*)(void *, void *)) 0, + (size_t) 0, (void **) 0 )) + { + ocierror(ocip, (char *)"OCIEnvCreate() failed", TRUE); + } + + if (OCIHandleAlloc((void *) ocip->envp, (void **) &ocip->errp, + (ub4) OCI_HTYPE_ERROR, (size_t) 0, (void **) 0)) + { + ocierror(ocip, (char *)"OCIHandleAlloc(OCI_HTYPE_ERROR) failed", TRUE); + } + + /* allocate the server handle */ + OCICALL(ocip, + OCIHandleAlloc((void *) ocip->envp, (void **) &ocip->srvp, + OCI_HTYPE_SERVER, (size_t) 0, (void **) 0)); + + /* create a server context */ + OCICALL(ocip, + OCIServerAttach (ocip->srvp, ocip->errp, connp->dbname, + (sb4)connp->dbnamelen, OCI_DEFAULT)); + + /* allocate the service handle */ + OCICALL(ocip, + OCIHandleAlloc((void *) ocip->envp, (void **) &ocip->svcp, + OCI_HTYPE_SVCCTX, (size_t) 0, (void **) 0)); + + /* set attribute server context in the service context */ + OCICALL(ocip, + OCIAttrSet((void *) ocip->svcp, OCI_HTYPE_SVCCTX, + (void *) ocip->srvp, (ub4) 0, OCI_ATTR_SERVER, + (OCIError *) ocip->errp)); + + /* allocate a session handle */ + OCICALL(ocip, + OCIHandleAlloc((void *) ocip->envp, (void **)&ocip->authp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (void **) 0)); + + /* set the username in the session */ + OCICALL(ocip, + OCIAttrSet((void *) ocip->authp, (ub4) OCI_HTYPE_SESSION, + (void *) connp->user, + (ub4) connp->userlen, + (ub4) OCI_ATTR_USERNAME, ocip->errp)); + + /* set the password in the session */ + OCICALL(ocip, + OCIAttrSet((void *) ocip->authp, (ub4) OCI_HTYPE_SESSION, + (void *) connp->passw, + (ub4) connp->passwlen, + (ub4) OCI_ATTR_PASSWORD, ocip->errp)); + + OCICALL(ocip, + OCISessionBegin(ocip->svcp, ocip->errp, ocip->authp, + OCI_CRED_RDBMS, + (ub4) connp->sysdba ? + OCI_SYSDBA : OCI_DEFAULT)); + + OCICALL(ocip, + OCIAttrSet((void *) ocip->svcp, (ub4) OCI_HTYPE_SVCCTX, + (void *) ocip->authp, (ub4) 0, + (ub4) OCI_ATTR_SESSION, ocip->errp)); + + if (OCIHandleAlloc((void *) ocip->envp, (void **) &ocip->stmtp, + (ub4) OCI_HTYPE_STMT, (size_t) 0, (void **) 0)) + { + ocierror(ocip, (char *)"OCIHandleAlloc(OCI_HTYPE_STMT) failed", TRUE); + } + + if (OCIHandleAlloc((void *) ocip->envp, (void **) &ocip->stmt2p, + (ub4) OCI_HTYPE_STMT, (size_t) 0, (void **) 0)) + { + ocierror(ocip, (char *)"OCIHandleAlloc(OCI_HTYPE_STMT-2) failed", TRUE); + } + + if (OCIHandleAlloc((void *) ocip->envp, (void **) &ocip->stmt3p, + (ub4) OCI_HTYPE_STMT, (size_t) 0, (void **) 0)) + { + ocierror(ocip, (char *)"OCIHandleAlloc(OCI_HTYPE_STMT-3) failed", TRUE); + } + + /* restore the interrupt signal handler */ + signal(SIGINT, SIG_DFL); +} + +static void oradisconnect(oci_t * ocip) +{ + if (OCILogoff(ocip->svcp, ocip->errp)) + { + ocierror(ocip, (char *)"OCILogoff() failed", TRUE); + } + + if (ocip->stmtp) + OCIHandleFree((void *) ocip->stmtp, (ub4) OCI_HTYPE_STMT); + + if (ocip->stmt2p) + OCIHandleFree((void *) ocip->stmt2p, (ub4) OCI_HTYPE_STMT); + + if (ocip->stmt2p) + OCIHandleFree((void *) ocip->stmt3p, (ub4) OCI_HTYPE_STMT); + + if (ocip->errp) + OCIHandleFree((void *) ocip->errp, (ub4) OCI_HTYPE_ERROR); + + if (ocip->envp) + OCIHandleFree((void *) ocip->envp, (ub4) OCI_HTYPE_ENV); +} + +static void print_header(options_t * opts, connection_t * connp) +{ + oci_t * ocip = connp->ocip; + + puts((char *)"\nSTREAMS Monitor, v 2.5 Copyright Oracle Corp. 2002, 2005."); + printf("Interval = %u, Count=%u \n\n", + opts->interval, opts->count); + + printf("Logon=%.*s@%.*s ORACLE %.*s\n\n", + connp->userlen, + connp->userlen ? (char *)connp->user : "", + connp->dbnamelen, + connp->dbnamelen ? (char *)connp->dbname : "", + connp->versionstrlen, connp->versionstr); + + if (connp->version >= VERSION_10g) + { + printf("Streams Pool Size = "); + print_pool_size(ocip); + printf("\n\n"); + } + + if (connp->sysuser) + { + if (opts->short_opt) + { + printf("LOG : \n"); + } + else + { + printf("LOG : \n"); + } + } + + printf("NET: "); + if (opts->short_opt) + { + printf(" \n"); + } + else + { + printf(" \n"); + } + + printf("Cxxx: "); + if(opts->short_opt) + { + printf(" " + "\n"); + } + else + { + if (connp->version >= VERSION_10g) + { + printf(" "); + } + printf(" " + "\n"); + } + + if ((connp->sysuser) && (connp->version >= VERSION_10g)) + { + printf("MEM : %% \n"); + } + + if (opts->short_opt) + { + puts((char *)"PRxx: "); + } + else { + puts((char *)"PRxx: /"); + } + + if (!opts->short_opt) + { + printf("Qx : "); + if (connp->version >= VERSION_10g) + { + printf("/ "); + } + else if (connp->sysuser) + { + /* in 9i only SYS can query the outstanding messages */ + printf(" "); + } + if (connp->version >= VERSION_10g) + { + printf("\n"); + } + else + { + printf("\n"); + } + } + else + { + if (connp->version >= VERSION_10g) + { + printf("Qx : \n"); + } + /* for 9i short queue stats are not printed */ + } + + if (opts->short_opt) + { + puts((char *)"PSxx: "); + } + else + { + puts((char *)"PSxx: /"); + } + + if (opts->short_opt) + { + puts((char *)"Axxx: " + ""); + } + else + { + puts((char *)"Axxx: " + " " + " "); + } + + puts((char *)": flow control in effect"); + puts((char *)": potential bottleneck"); + + puts((char *)"AR: apply reader"); + puts((char *)"AS(n): n number of apply server"); + + if (connp->version >= VERSION_10g) + puts((char *)": "); + + puts((char *)"xx->: database instance name"); + + printf("\n"); +} + +static void print_stats(options_t * opts, connection_t * connp) +{ + if (opts->iters > 0) + { + collect_event_data(opts, connp); + } + + if (connp->sysuser) + { + print_log_stats(opts, connp->ocip, &connp->lgwr_pval); + } + + /* print the network usage stats */ + print_net_stats(opts, connp); + + /* now print the capture statistics */ + if (opts->short_opt) + { + print_short_capture_stats(opts, connp, connp->ocip, &connp->cap_pval); + } + else + { + print_capture_stats(opts, connp, connp->ocip, &connp->cap_pval); + } + + if (connp->version >= VERSION_10g) + { + print_queue_stats(opts, connp, connp->ocip, &connp->que_pval, + &connp->prop_pval); + } + else + { + /* in 9iR2, we only get the current spilled messages. + * Also, there is no way to get the cummulative messages. + * So, we cannot compute the rates in 9iR2. + */ + print_queue9i_stats(opts, connp, connp->ocip, &connp->prop_pval); + } + + if (opts->short_opt) + { + print_short_apply_stats(opts, connp, connp->ocip, &connp->app_pval); + } + else + { + print_apply_stats(opts, connp, connp->ocip, &connp->app_pval); + } + + if ((connp->sysuser) && (connp->version >= VERSION_10g)) + { + print_mem_stats(opts, connp->ocip); + } + + if (opts->iters == 0) + { + collect_event_data(opts, connp); + } + +} + +#define POOL_SIZE_10g "select current_size from v$sga_dynamic_components \ +where component='streams pool'" + +static void print_pool_size(oci_t * ocip) +{ + OCIDefine *defnp; + OCINumber pool_size; + OCINumber megabyte; + OCINumber pool_mb; + sword temp; + uword tempsize; + + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, (oratext *) POOL_SIZE_10g, + sizeof(POOL_SIZE_10g), OCI_NTV_SYNTAX, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 1, + (void *)&pool_size, + sizeof(pool_size), SQLT_VNU, NULL, + NULL, NULL, OCI_DEFAULT)); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmtp, ocip->errp, 1, 0, + (OCISnapshot *)0, (OCISnapshot *)0, OCI_EXACT_FETCH)); + + /* create an OCI number with 1M in it */ + temp = (sword) 1 << 20; + tempsize = sizeof(temp); + OCICALL(ocip, OCINumberFromInt(ocip->errp, &temp, tempsize, + OCI_NUMBER_SIGNED, &megabyte)); + + /* divide the pool size by 1M */ + OCICALL(ocip, OCINumberDiv(ocip->errp, &pool_size, &megabyte, &pool_mb)); + + /* covert the pool size to an integer and print it */ + OCICALL(ocip, OCINumberToInt(ocip->errp, &pool_mb, tempsize, + OCI_NUMBER_SIGNED, &temp)); + + printf("%dM", temp); +} + + +#define CAPTURE_SHORT_STATS_9iR2 "select c.sid, c.CAPTURE# CAPTURENUM, \ +c.CAPTURE_NAME, nvl(c.TOTAL_MESSAGES_CAPTURED,0) TOTAL_MESSAGES_CAPTURED, \ +nvl(c.TOTAL_MESSAGES_ENQUEUED,0) TOTAL_MESSAGES_ENQUEUED, \ +nvl((c.CAPTURE_TIME - c.CAPTURE_MESSAGE_CREATE_TIME)*86400, -1) \ +CAPTURE_LATENCY from v$streams_capture c order by 1" + +#define CAPTURE_SHORT_STATS "select c.sid, c.CAPTURE# CAPTURENUM, \ +c.CAPTURE_NAME, nvl(c.TOTAL_MESSAGES_CAPTURED,0) TOTAL_MESSAGES_CAPTURED, \ +nvl(c.TOTAL_MESSAGES_ENQUEUED,0) TOTAL_MESSAGES_ENQUEUED, \ +nvl((c.CAPTURE_TIME - \ + c.CAPTURE_MESSAGE_CREATE_TIME)*86400, -1) CAPTURE_LATENCY, \ +nvl(c.CAPTURE_MESSAGE_NUMBER,0) CAPTURE_MESSAGE_NUMBER, \ +l.read_scn, c.ELAPSED_PAUSE_TIME \ +from v$streams_capture c, v$logmnr_session l where \ +c.capture_name=l.session_name order by 1" + +#define CAPTURE_STATS_9iR2 "select c.sid, c.CAPTURE# CAPTURENUM, \ +c.CAPTURE_NAME, nvl(c.TOTAL_MESSAGES_CAPTURED,0) TOTAL_MESSAGES_CAPTURED, \ +nvl(c.CAPTURE_MESSAGE_NUMBER,0) CAPTURE_MESSAGE_NUMBER, \ +nvl(c.TOTAL_MESSAGES_ENQUEUED,0) TOTAL_MESSAGES_ENQUEUED, \ +nvl(c.ENQUEUE_MESSAGE_NUMBER,0) ENQUEUE_MESSAGE_NUMBER, \ +nvl((c.CAPTURE_TIME - \ + c.CAPTURE_MESSAGE_CREATE_TIME)*86400, -1) CAPTURE_LATENCY \ +from v$streams_capture c order by 1" + +#define CAPTURE_STATS "select c.sid, c.CAPTURE# CAPTURENUM, c.CAPTURE_NAME, \ +nvl(c.TOTAL_MESSAGES_CAPTURED,0) TOTAL_MESSAGES_CAPTURED, \ +nvl(c.CAPTURE_MESSAGE_NUMBER,0) CAPTURE_MESSAGE_NUMBER, \ +nvl(c.TOTAL_MESSAGES_ENQUEUED,0) TOTAL_MESSAGES_ENQUEUED, \ +nvl(c.ENQUEUE_MESSAGE_NUMBER,0) ENQUEUE_MESSAGE_NUMBER, \ +nvl((c.CAPTURE_TIME - \ + c.CAPTURE_MESSAGE_CREATE_TIME)*86400, -1) CAPTURE_LATENCY, \ +l.read_scn, c.ELAPSED_PAUSE_TIME \ +from v$streams_capture c, v$logmnr_session l where \ +c.capture_name=l.session_name order by 1" + +typedef struct capture +{ + ub4 capturenum; + oratext capturename[128]; + ub2 capturenamelen; + ub4 total_captured; + OCINumber captured_scn; + oratext captured_scn_str[128]; + ub4 captured_scn_strlen; + ub4 total_enqueued; + OCINumber enqueued_scn; + oratext enqueued_scn_str[128]; + ub4 enqueued_scn_strlen; + OCINumber read_scn; + oratext read_scn_str[128]; + ub4 read_scn_strlen; + sb4 capture_latency; + ub4 elapsed_pause_time; + ub4 sid; +} capture_t; + + +static cap_pval_t* print_capture_rates(oci_t * ocip, options_t * opts, + connection_t * connp, + cap_pval_t **cap_pval, + capture_t cap, + boolean short_opt, boolean *flow_ctrl, + boolean *bottleneck) +{ + boolean cur_cap_exists = FALSE; + cap_pval_t *cap_elem; + cap_pval_t *new_elem; + sword result = 0; + cap_pval_t *cur_cap = 0; + sid_pval_t sidval; + sid_pval_t *new_sid = 0; + + for (cap_elem = *cap_pval; + cap_elem != (cap_pval_t *)NULL; + cap_elem = cap_elem->next_cap) + { + cur_cap = cap_elem; + + if ((cap_elem->capturenamelen == cap.capturenamelen) && + !memcmp((void *)cap_elem->capturename, (void *)cap.capturename, + (size_t)cap_elem->capturenamelen)) + { + cur_cap_exists = TRUE; + + if (connp->version >= VERSION_10g) + { + if ((*flow_ctrl) = (cap.elapsed_pause_time > + cap_elem->elapsed_pause_time)) + { + printf(" "); + } + else + { + OCICALL(ocip, OCINumberCmp(ocip->errp, &(cap.captured_scn), + &(cap_elem->read_scn), &result)); + + if (result < 0) + { + /* We do not want to report that capture is a bottleneck in the + * current interval if it was under flow control in the previous + * interval, and if the interval is less than 60 seconds. + */ + if ((!cap_elem->flow_ctrl) || + ((cap_elem->flow_ctrl) && (opts->interval > 60))) + { + *bottleneck = TRUE; + printf(" "); /* indicate capture as potential bottleneck */ + } + else + { + printf(" - "); /* for alignment */ + } + } + else + { + printf(" - "); /* for alignment */ + } + } + } + + if (short_opt) + { + /* In case the capture had been brought down and then restarted */ + if (cap.total_captured >= cap_elem->total_captured) + { + printf("C%03u %u %u", cap.capturenum, + (cap.total_captured-cap_elem->total_captured)*100/(opts->elapstim), + (cap.total_enqueued-cap_elem->total_enqueued)*100/(opts->elapstim)); + print_latency(cap.capture_latency); + } + else + { + printf(" "); /* for alignment */ + } + } + + /* update the data for the current capture in the linked list */ + memcpy((void *)cap_elem->capturename, (void *)cap.capturename, + (size_t)cap.capturenamelen); + cap_elem->capturenamelen = cap.capturenamelen; + cap_elem->capturenum = cap.capturenum; + cap_elem->total_captured = cap.total_captured; + cap_elem->total_enqueued = cap.total_enqueued; + + if (*flow_ctrl) + { + cap_elem->flow_ctrl = TRUE; + } + else + { + cap_elem->flow_ctrl = FALSE; + } + + if (connp->version >= VERSION_10g) + { + cap_elem->read_scn = cap.read_scn; + cap_elem->elapsed_pause_time = cap.elapsed_pause_time; + } + + break; + } + } + + /* add the data for this new capture process into the linked list */ + if (!cur_cap_exists) + { + printf(" "); /* for alignment */ + /* add the new capture stats to the linked list */ + new_elem = (cap_pval_t *)malloc (sizeof(cap_pval_t)); + memset(new_elem, 0, sizeof(cap_pval_t)); + if (connp->version >= VERSION_10g) + { + new_elem->read_scn = cap.read_scn; + new_elem->elapsed_pause_time = cap.elapsed_pause_time; + } + memcpy((void *)new_elem->capturename, (void *)cap.capturename, + (size_t)cap.capturenamelen); + new_elem->capturenamelen = cap.capturenamelen; + new_elem->capturenum = cap.capturenum; + new_elem->total_captured = cap.total_captured; + new_elem->total_enqueued = cap.total_enqueued; + new_elem->flow_ctrl = FALSE; + if (*cap_pval == (cap_pval_t *)NULL) + { + *cap_pval = new_elem; + } + else + { + cur_cap->next_cap = new_elem; + } + cur_cap = new_elem; + + /* add the new sid info to sid_pval list */ + new_sid = (sid_pval_t *)malloc(sizeof(sid_pval_t)); + new_sid->sid = cap.sid; + new_sid->pval = new_elem; + new_sid->type = CAPTURE_PROCESS; + new_sid->next = connp->sid_pval; + + connp->sid_pval = new_sid; + connp->num_sid ++; + } + return cur_cap; + +} + +static void print_short_capture_stats(options_t * opts, connection_t * connp, + oci_t * ocip, cap_pval_t ** cap_pval) +{ + capture_t cap; + OCIDefine *defnp; + sword result = 0; + boolean flow_ctrl = FALSE; + boolean bottleneck = FALSE; + sword status = OCI_SUCCESS; + boolean cur_cap_exists = FALSE; + cap_pval_t *cur_cap; + + if (connp->version >= VERSION_10g) + { + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, + (oratext *) CAPTURE_SHORT_STATS, + sizeof(CAPTURE_SHORT_STATS), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + } + else + { + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, + (oratext *) CAPTURE_SHORT_STATS_9iR2, + sizeof(CAPTURE_SHORT_STATS_9iR2), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + } + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmtp, ocip->errp, 0, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 1, &cap.sid, + sizeof(cap.sid), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 2, &cap.capturenum, + sizeof(cap.capturenum), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 3, &cap.capturename, + sizeof(cap.capturename), SQLT_CHR, NULL, + &cap.capturenamelen, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 4, + &cap.total_captured, sizeof(cap.total_captured), + SQLT_UIN, NULL, NULL, NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 5, + &cap.total_enqueued, sizeof(cap.total_enqueued), + SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 6, + &cap.capture_latency, sizeof(cap.capture_latency), + SQLT_INT, NULL, NULL, NULL, OCI_DEFAULT)); + + if (connp->version >= VERSION_10g) + { + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp,7,&cap.captured_scn, + sizeof(cap.captured_scn), SQLT_VNU, NULL, NULL, + NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 8, &cap.read_scn, + sizeof(cap.read_scn), SQLT_VNU, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 9, + &cap.elapsed_pause_time, + sizeof(cap.elapsed_pause_time), + SQLT_UIN, NULL, NULL, NULL, OCI_DEFAULT)); + } + + while(OCI_SUCCESS == + (status = OCIStmtFetch2(ocip->stmtp, ocip->errp, 1, OCI_DEFAULT, + 0, OCI_DEFAULT))) + { + flow_ctrl = FALSE; + bottleneck = FALSE; + result = 0; + + printf(" | "); + + cur_cap = print_capture_rates(ocip, opts, connp, cap_pval, cap, TRUE, + &flow_ctrl, &bottleneck); + + if (connp->version >= VERSION_10g) + { + print_event_stats(opts, (void *)cur_cap, CAPTURE_PROCESS); + } + } + + if (OCI_ERROR == status) + { + ocierror(ocip, (char *)" | C ", FALSE); + } + + /* finish the cursor */ + OCICALL(ocip, + OCIStmtFetch2(ocip->stmtp, ocip->errp, 0, OCI_DEFAULT, 0, OCI_DEFAULT)); +} + +static void print_capture_stats(options_t * opts, connection_t * connp, + oci_t * ocip, cap_pval_t ** cap_pval) +{ + capture_t cap; + OCIDefine *defnp; + sword result = 0; + boolean flow_ctrl = FALSE; + boolean bottleneck = FALSE; + sword status = OCI_ERROR; + boolean cur_cap_exists = FALSE; + cap_pval_t *cur_cap; + + if (connp->version >= VERSION_10g) + { + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, (oratext *) CAPTURE_STATS, + sizeof(CAPTURE_STATS), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + } + else + { + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, + (oratext *) CAPTURE_STATS_9iR2, + sizeof(CAPTURE_STATS_9iR2), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + } + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmtp, ocip->errp, 0, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 1, &cap.sid, + sizeof(cap.sid), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 2, &cap.capturenum, + sizeof(cap.capturenum), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 3, &cap.capturename, + sizeof(cap.capturename), SQLT_CHR, NULL, + &cap.capturenamelen, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 4, + &cap.total_captured, sizeof(cap.total_captured), + SQLT_UIN, NULL, NULL, NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 5, &cap.captured_scn, + sizeof(cap.captured_scn), SQLT_VNU, NULL, NULL, NULL, + OCI_DEFAULT)); + + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 6, + &cap.total_enqueued, sizeof(cap.total_enqueued), + SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 7, &cap.enqueued_scn, + sizeof(cap.enqueued_scn), SQLT_VNU, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 8, + &cap.capture_latency, sizeof(cap.capture_latency), + SQLT_INT, NULL, NULL, NULL, OCI_DEFAULT)); + + if (connp->version >= VERSION_10g) + { + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 9, &cap.read_scn, + sizeof(cap.read_scn), SQLT_VNU, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 10, + &cap.elapsed_pause_time, + sizeof(cap.elapsed_pause_time), + SQLT_UIN, NULL, NULL, NULL, OCI_DEFAULT)); + } + + while(OCI_SUCCESS == + (status = OCIStmtFetch2(ocip->stmtp, ocip->errp, 1, OCI_DEFAULT, + 0, OCI_DEFAULT))) + { + flow_ctrl = FALSE; + bottleneck = FALSE; + result = 0; + cur_cap_exists = FALSE; + + + if (connp->version >= VERSION_10g) + { + printf(" | "); + cur_cap = print_capture_rates(ocip, opts, connp, cap_pval, cap, FALSE, + &flow_ctrl, &bottleneck); + + cap.read_scn_strlen = 128; + OCICALL(ocip, + OCINumberToText(ocip->errp, &cap.read_scn, + (const oratext *)"TM9", 3, (oratext *)0, 0, + &cap.read_scn_strlen, cap.read_scn_str)); + printf(" C%03u %.*s ", cap.capturenum, cap.read_scn_strlen, + cap.read_scn_str); + } + else + { + printf(" | C%03u ", cap.capturenum); + } + + cap.captured_scn_strlen = 128; + OCICALL(ocip, + OCINumberToText(ocip->errp, &cap.captured_scn, + (const oratext *)"TM9", 3, (oratext *)0, 0, + &cap.captured_scn_strlen, cap.captured_scn_str)); + + cap.enqueued_scn_strlen = 128; + OCICALL(ocip, + OCINumberToText(ocip->errp, &cap.enqueued_scn, + (const oratext *)"TM9", 3, (oratext *)0, 0, + &cap.enqueued_scn_strlen, cap.enqueued_scn_str)); + + printf("%u %.*s %u %.*s", + cap.total_captured, cap.captured_scn_strlen, cap.captured_scn_str, + cap.total_enqueued, cap.enqueued_scn_strlen, cap.enqueued_scn_str + ); + + print_latency(cap.capture_latency); + + if (connp->version >= VERSION_10g) + { + print_event_stats(opts, (void *)cur_cap, CAPTURE_PROCESS); + } + } + + if (OCI_ERROR == status) + { + ocierror(ocip, (char *)" | C ", FALSE); + } + + /* finish the cursor */ + OCICALL(ocip, + OCIStmtFetch2(ocip->stmtp, ocip->errp, 0, OCI_DEFAULT, 0, OCI_DEFAULT)); +} + + +#define QUEUE9i_STATS "select dq.qid, dq.owner, dq.queue_table from dba_queues\ + dq, dba_queue_tables dqt where dq.owner not in ('SYS','SYSTEM') and \ +dq.QUEUE_TYPE='NORMAL_QUEUE' and dq.owner=dqt.owner and \ +dq.queue_table=dqt.queue_table and dqt.object_type='SYS.ANYDATA'" + +#define QUEUE9i_OUTMESG_STATS "select bufqm_nmsg from x$bufqm where \ +bufqm_qid=:1" + +#define QUEUE9i_SPILL_STATS "select count(*) from %.*s.AQ$_%.*s_P" + +typedef struct queue9i +{ + ub4 queueid; + oratext owner[128]; + ub2 ownerlen; + oratext qtable[128]; + ub2 qtablelen; + ub4 spilled; + ub4 outstanding; +} queue9i_t; + +static void print_queue9i_stats(options_t * opts, connection_t * connp, + oci_t * ocip, prop_pval_t ** prop_pval) +{ + queue9i_t que9i; + OCIDefine *defnp; + OCIBind *bndp; + unsigned pnum = 0; + char spillquery[1024]; + ub4 spillquerylen; + sword status; + sword status2 = OCI_SUCCESS; + + que_pval_t *que_elem; + que_pval_t *new_elem; + que_pval_t *cur_que; + boolean cur_que_exists = FALSE; + + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, (oratext *) QUEUE9i_STATS, + sizeof(QUEUE9i_STATS), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmtp, ocip->errp, 0, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 1, &que9i.queueid, + sizeof(que9i.queueid), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 2, &que9i.owner, + sizeof(que9i.owner), SQLT_CHR, NULL, + &que9i.ownerlen, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 3, &que9i.qtable, + sizeof(que9i.qtable), SQLT_CHR, NULL, + &que9i.qtablelen, NULL, + OCI_DEFAULT)); + + while(OCI_SUCCESS == + (status2 = OCIStmtFetch2(ocip->stmtp, ocip->errp, 1, OCI_DEFAULT, + 0, OCI_DEFAULT))) + { + if (!opts->short_opt) + { + printf(" | Q%u", que9i.queueid); + + if (connp->sysuser) + { + OCICALL(ocip, + OCIStmtPrepare(ocip->stmt2p, ocip->errp, + (oratext *)QUEUE9i_OUTMESG_STATS, + sizeof(QUEUE9i_OUTMESG_STATS), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + + bndp = (OCIBind *)0; + OCICALL(ocip, + OCIBindByPos(ocip->stmt2p, &bndp, ocip->errp, 1, + (void *) &que9i.queueid, sizeof(que9i.queueid), + SQLT_UIN, (void *) 0, (ub2 *) 0, (ub2 *) 0, + (ub4) 0, (ub4 *) 0, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 1, + &que9i.outstanding, sizeof(que9i.outstanding), + SQLT_UIN, NULL, NULL, NULL, OCI_DEFAULT)); + + status = OCIStmtExecute(ocip->svcp, ocip->stmt2p, ocip->errp, 1, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, + OCI_EXACT_FETCH); + + if (OCI_NO_DATA == status) + { + /* if there has been no buffered enqueues then x$bufqm will not show + * a row for this table */ + printf(" -"); + } + else if (OCI_SUCCESS == status) + { + printf(" %u", que9i.outstanding); + } + else + { + /* lrg 2858006: compiler issue, temporary fix to initialize status */ + sword status_tmp = status; + OCICALL(ocip, status_tmp); + } + } + + /* contruct the query for the spilled messages */ + spillquerylen = + (ub4)sprintf(spillquery, QUEUE9i_SPILL_STATS, que9i.ownerlen, + que9i.owner, que9i.qtablelen, que9i.qtable); + + OCICALL(ocip, + OCIStmtPrepare(ocip->stmt2p, ocip->errp, (oratext *) spillquery, + spillquerylen, OCI_NTV_SYNTAX, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 1, + &que9i.spilled, + sizeof(que9i.spilled), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + status = OCIStmtExecute(ocip->svcp, ocip->stmt2p, ocip->errp, 1, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, + OCI_EXACT_FETCH); + + if (OCI_SUCCESS == status) + { + printf(" %u", que9i.spilled); + } + else + { + printf(" -"); + } + } + print_prop_sender_stats(opts, connp, ocip, que9i.queueid, prop_pval, &pnum); + } + + if (OCI_ERROR == status2) + { + ocierror(ocip, (char *)" | Q ", FALSE); + } +} + +#define QUEUE_STATS "select queue_id, QUEUE_NAME, QUEUE_SCHEMA, nvl(cnum_msgs,0) CNUM_MSGS, \ +nvl(cspill_msgs,0) CSPILL_MSGS, nvl(num_msgs,0) num_msgs from \ +v$buffered_queues" + + +static void print_queue_stats(options_t * opts, connection_t * connp, + oci_t * ocip, que_pval_t ** que_pval, + prop_pval_t ** prop_pval) +{ + queue_t que; + OCIDefine *defnp; + sword status = OCI_SUCCESS; + que_pval_t *que_elem; + que_pval_t *new_elem; + que_pval_t *cur_que; + unsigned pnum = 0; + boolean cur_que_exists = FALSE; + + /* now print the queue statistics and the propagation stats for each + * buffered queue */ + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, (oratext *) QUEUE_STATS, + sizeof(QUEUE_STATS), OCI_NTV_SYNTAX, OCI_DEFAULT)); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmtp, ocip->errp, 0, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 1, &que.queueid, + sizeof(que.queueid), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 2, &que.queuename, + sizeof(que.queuename), SQLT_CHR, NULL, + &que.queuenamelen, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 3, &que.schemaname, + sizeof(que.schemaname), SQLT_CHR, NULL, + &que.schemanamelen, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 4, &que.cnummsgs, + sizeof(que.cnummsgs), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 5, &que.cspillmsgs, + sizeof(que.cspillmsgs), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 6, &que.nummsgs, + sizeof(que.nummsgs), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + while(OCI_SUCCESS == + (status = OCIStmtFetch2(ocip->stmtp, ocip->errp, 1, OCI_DEFAULT, 0, + OCI_DEFAULT))) + { + print_prop_receiver_stats(opts, connp, ocip, &que, prop_pval, &pnum); + + if (!opts->short_opt) + { + printf(" | Q%u %5u/%u %5u", que.queueid, que.nummsgs, que.cnummsgs, + que.cspillmsgs); + } + else + { + for (que_elem = *que_pval; + que_elem != (que_pval_t *)NULL; + que_elem = que_elem->next_que) + { + cur_que = que_elem; + if (que_elem->queueid == que.queueid) + { + cur_que_exists = TRUE; + printf (" | Q%u %u %u", que.queueid, + (que.cnummsgs-que_elem->cnummsgs)*100/(opts->elapstim), + (que.cspillmsgs-que_elem->cspillmsgs)*100/(opts->elapstim)); + + /* update the values for the queue in the list */ + que_elem->cnummsgs = que.cnummsgs; + que_elem->cspillmsgs = que.cspillmsgs; + break; + } + } + if (!cur_que_exists) + { + /* add the values for the new queue to the linked list */ + new_elem = (que_pval_t *)malloc(sizeof(que_pval_t)); + new_elem->queueid = que.queueid; + new_elem->cnummsgs = que.cnummsgs; + new_elem->cspillmsgs = que.cspillmsgs; + new_elem->next_que = (que_pval_t *)NULL; + if (*que_pval == (que_pval_t *)NULL) + { + *que_pval = new_elem; + } + else + { + cur_que->next_que = new_elem; + } + } + } + print_prop_sender_stats(opts, connp, ocip, que.queueid, prop_pval, &pnum); + + } + + if (OCI_ERROR == status) + { + ocierror(ocip, (char *)" | Q ", FALSE); + } + + /* finish fetching from the buffered queue cursor */ + OCICALL(ocip, + OCIStmtFetch2(ocip->stmtp, ocip->errp, 0, OCI_DEFAULT, 0, + OCI_DEFAULT)); +} + +typedef struct prop +{ + ub4 total_number; + ub4 total_time; + ub8 total_bytes; + oratext src_queuename[30]; + ub2 src_queuenamelen; + oratext src_schemaname[30]; + ub2 src_schemanamelen; + oratext src_dbname[128]; + ub2 src_dbnamelen; + oratext dst_queuename[30]; + ub2 dst_queuenamelen; + oratext dst_schemaname[30]; + ub2 dst_schemanamelen; + oratext dst_dbname[128]; + ub2 dst_dbnamelen; + oratext destination[128]; + ub2 destination_len; +} prop_t; + +#define PROP_RECEIVER_STATS_10gR2_FIRST \ +"select NVL(SRC_QUEUE_NAME, '\0'), \ +NVL(SRC_QUEUE_SCHEMA, '\0'), TOTAL_MSGS, ELAPSED_ENQUEUE_TIME, \ +NVL(SRC_DBNAME, '\0') \ +from v$propagation_receiver \ +where (DST_QUEUE_NAME=:1 or DST_QUEUE_NAME is NULL) and \ +(DST_QUEUE_SCHEMA=:2 or DST_QUEUE_SCHEMA is NULL)" + +#define PROP_RECEIVER_STATS_10gR2 "select NVL(SRC_QUEUE_NAME, '\0'), \ +NVL(SRC_QUEUE_SCHEMA, '\0'), TOTAL_MSGS, ELAPSED_ENQUEUE_TIME, \ +NVL(SRC_DBNAME, '\0') \ +from v$propagation_receiver \ +where DST_QUEUE_NAME=:1 and DST_QUEUE_SCHEMA=:2" + +#define PROPAGATION_RECEIVER_SIDS_10gR2 \ +"select k.KWQPDSID from x$kwqpd k where k.KWQPDDQN=:1 and k.KWQPDDQS=:2 \ +and (KWQPDSQN IS NULL or KWQPDSQN=:3) \ +and (KWQPDSQS IS NULL or KWQPDSQS=:4) \ +and (KWQPDDBN IS NULL or KWQPDDBN=:5)" + +static void print_prop_receiver_stats(options_t * opts, connection_t * connp, + oci_t * ocip, queue_t *que, + prop_pval_t ** prop_pval, + unsigned * pnum_ptr) +{ + prop_t prp; + OCIBind *bndp; + OCIDefine *defnp; + sword status = OCI_SUCCESS; + prop_pval_t *prop_elem; + prop_pval_t *new_elem; + prop_pval_t *cur_prop; + boolean cur_prop_exists = FALSE; + sid_pval_t sidval; + sid_pval_t *new_sid = 0; + + if (connp->version >= VERSION_10gR2) + { + if (*pnum_ptr == 0) + OCICALL(ocip, + OCIStmtPrepare(ocip->stmt2p, ocip->errp, + (oratext *) PROP_RECEIVER_STATS_10gR2_FIRST, + sizeof(PROP_RECEIVER_STATS_10gR2_FIRST), + OCI_NTV_SYNTAX, + OCI_DEFAULT)); + else + OCICALL(ocip, + OCIStmtPrepare(ocip->stmt2p, ocip->errp, + (oratext *) PROP_RECEIVER_STATS_10gR2, + sizeof(PROP_RECEIVER_STATS_10gR2), + OCI_NTV_SYNTAX, + OCI_DEFAULT)); + } + else + { + return; + } + + bndp = (OCIBind *)0; + OCIBindByPos(ocip->stmt2p, &bndp, ocip->errp, 1, + (void *) &(que->queuename), + (sword) sizeof(que->queuename), + SQLT_CHR, (void *) 0, + (ub2 *)&(que->queuenamelen), (ub2 *) 0, (ub4) 0, (ub4 *) 0, + OCI_DEFAULT); + + bndp = (OCIBind *)0; + OCIBindByPos(ocip->stmt2p, &bndp, ocip->errp, 2, + (void *) &(que->schemaname), + (sword) sizeof(que->schemaname), + SQLT_CHR, + (void *) 0, (ub2 *)&(que->schemanamelen), (ub2 *) 0, (ub4) 0, (ub4 *) 0, + OCI_DEFAULT); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmt2p, ocip->errp, 0, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 1, + (void *)&prp.src_queuename, + sizeof(prp.src_queuename), + SQLT_CHR, NULL, &prp.src_queuenamelen, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 2, + (void *)&prp.src_schemaname, + sizeof(prp.src_schemaname), + SQLT_CHR, NULL, &prp.src_schemanamelen, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 3, + &prp.total_number, sizeof(prp.total_number), + SQLT_UIN, NULL, NULL, NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 4, + &prp.total_time, sizeof(prp.total_time), + SQLT_UIN, NULL, NULL, NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 5, + (void *)&prp.src_dbname, sizeof(prp.src_dbname), + SQLT_CHR, NULL, &prp.src_dbnamelen, NULL, + OCI_DEFAULT)); + + while(OCI_SUCCESS == + (status = OCIStmtFetch2(ocip->stmt2p, ocip->errp, 1, OCI_DEFAULT, 0, + OCI_DEFAULT))) + { + (*pnum_ptr)++; + cur_prop_exists = FALSE; + + for (prop_elem = *prop_pval; + prop_elem != (prop_pval_t *)NULL; + prop_elem = prop_elem->next_prop) + { + cur_prop = prop_elem; + if ((prop_elem->src_dbnamelen == prp.src_dbnamelen) + && (prop_elem->src_queuenamelen == prp.src_queuenamelen) + && !memcmp((void *)prop_elem->src_dbname, (void *)prp.src_dbname, + prp.src_dbnamelen) + && !memcmp((void *)prop_elem->src_queuename, + (void *)prp.src_queuename, + prp.src_queuenamelen)) + { + cur_prop_exists = TRUE; + + if (opts->short_opt) + { + /* In case the propagation process was brought down and restarted */ + if (prp.total_number >= prop_elem->total_number) + { + printf(" | PR%02u ", *pnum_ptr); + printf("%u", (prp.total_number - prop_elem->total_number)*100 + /opts->elapstim); + } + else if (prp.total_time > 0) + { + printf(" | PR%02u ", *pnum_ptr); + printf("%u", prp.total_number/prp.total_time); + } + } + + /* update the data for the current propagation process */ + prop_elem->total_number = prp.total_number; + + break; + } + } + if (!cur_prop_exists) + { + /* add the data for the new propagation process into the linked list*/ + new_elem = (prop_pval_t *)malloc (sizeof(prop_pval_t)); + new_elem->dst_queueid = que->queueid; + memcpy((void *)new_elem->src_queuename, (void *)(prp.src_queuename), + (prp.src_queuenamelen)); + new_elem->src_queuenamelen = prp.src_queuenamelen; + memcpy((void *)new_elem->src_schemaname, (void *)(prp.src_schemaname), + (prp.src_schemanamelen)); + new_elem->src_schemanamelen = prp.src_schemanamelen; + new_elem->src_dbnamelen = prp.src_dbnamelen; + memcpy((void *)new_elem->src_dbname, (void *)prp.src_dbname, + prp.src_dbnamelen); + + new_elem->total_number = prp.total_number; + new_elem->total_bytes = prp.total_bytes; + new_elem->pevent_sender = NULL; + new_elem->pevent_receiver = NULL; + new_elem->next_prop = (prop_pval_t *)NULL; + + + if (*prop_pval == (prop_pval_t *)NULL) + { + *prop_pval = new_elem; + } + else + { + cur_prop->next_prop = new_elem; + } + cur_prop = new_elem; + + if ((connp->version >= VERSION_10gR2) && connp->sysdba) + { + OCICALL(ocip, + OCIStmtPrepare(ocip->stmt3p, ocip->errp, + (oratext *) PROPAGATION_RECEIVER_SIDS_10gR2, + sizeof(PROPAGATION_RECEIVER_SIDS_10gR2), + OCI_NTV_SYNTAX, + OCI_DEFAULT)); + + bndp = (OCIBind *)0; + OCIBindByPos(ocip->stmt3p, &bndp, ocip->errp, 1, + (void *) &(que->queuename), + (sword) sizeof(que->queuename), + SQLT_CHR, + (void *) 0, (ub2 *)&(que->queuenamelen), + (ub2 *) 0, (ub4) 0, (ub4 *) 0, + OCI_DEFAULT); + + bndp = (OCIBind *)0; + OCIBindByPos(ocip->stmt3p, &bndp, ocip->errp, 2, + (void *) &(que->schemaname), + (sword) sizeof(que->schemaname), + SQLT_CHR, + (void *) 0, (ub2 *)&(que->schemanamelen), + (ub2 *) 0, (ub4) 0, (ub4 *) 0, + OCI_DEFAULT); + + bndp = (OCIBind *)0; + OCIBindByPos(ocip->stmt3p, &bndp, ocip->errp, 3, + (void *) &(cur_prop->src_queuename), + (sword) sizeof(cur_prop->src_queuename), + SQLT_CHR, + (void *) 0, (ub2 *)&(cur_prop->src_queuenamelen), + (ub2 *) 0, (ub4) 0, (ub4 *) 0, + OCI_DEFAULT); + + bndp = (OCIBind *)0; + OCIBindByPos(ocip->stmt3p, &bndp, ocip->errp, 4, + (void *) &(cur_prop->src_schemaname), + (sword) sizeof(cur_prop->src_schemaname), + SQLT_CHR, + (void *) 0, (ub2 *)&(cur_prop->src_schemanamelen), + (ub2 *) 0, (ub4) 0, (ub4 *) 0, + OCI_DEFAULT); + + bndp = (OCIBind *)0; + OCIBindByPos(ocip->stmt3p, &bndp, ocip->errp, 5, + (void *) &(cur_prop->src_dbname), + (sword) sizeof(cur_prop->src_dbname), + SQLT_CHR, + (void *) 0, (ub2 *)&(cur_prop->src_dbnamelen), + (ub2 *) 0, (ub4) 0, (ub4 *) 0, + OCI_DEFAULT); + + + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmt3p, ocip->errp, 0, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt3p, &defnp, ocip->errp, 1, + &sidval.sid, + sizeof(sidval.sid), SQLT_UIN, NULL, + NULL, NULL, + OCI_DEFAULT)); + + while (OCI_SUCCESS == + (status = OCIStmtFetch2(ocip->stmt3p, ocip->errp, 1, + OCI_DEFAULT, + 0, OCI_DEFAULT))) + { + new_sid = (sid_pval_t *)malloc(sizeof(sid_pval_t)); + new_sid->sid = sidval.sid; + new_sid->pval = new_elem; + new_sid->type = PR_RECEIVER_PROCESS; + new_sid->next = connp->sid_pval; + + connp->sid_pval = new_sid; + connp->num_sid ++; + } + } + } + + if (!opts->short_opt) + { + printf(" | PR%02u %u/%u", *pnum_ptr, prp.total_number, + prp.total_time); + } + + if (cur_prop != NULL && (connp->version >= VERSION_10gR2) && connp->sysdba) + { + print_event_stats(opts, (void *)cur_prop, PR_RECEIVER_PROCESS); + } + } + + if (OCI_ERROR == status) + { + ocierror(ocip, (char *)" | PR ", FALSE); + } + + /* finish fetching from the propagation cursor */ + OCICALL(ocip, + OCIStmtFetch2(ocip->stmt2p, ocip->errp, 0, OCI_DEFAULT, 0, + OCI_DEFAULT)); +} + + +#define PROP_SENDER_STATS "select dq.name, dq.owner, dqs.TOTAL_NUMBER, dqs.TOTAL_TIME, \ +dqs.TOTAL_BYTES, dqs.destination \ +from dba_queue_schedules dqs, dba_queues dq where dqs.schema=dq.owner and \ +dqs.qname=dq.name and dq.qid=:1 order by dqs.destination" + +#define PROP_SENDER_STATS_10gR2 "select dq.name, dq.owner, dqs.TOTAL_NUMBER, dqs.TOTAL_TIME, \ +dqs.TOTAL_BYTES, dqs.destination \ +from dba_queue_schedules dqs, dba_queues dq where dqs.schema=dq.owner and \ +dqs.qname=dq.name and dq.qid=:1 and dqs.message_delivery_mode = 'BUFFERED' \ +order by dqs.destination" + +#define PROPAGATION_SENDER_SIDS \ +"select KWQPSSID from x$kwqps where KWQPSQID=:1 and (KWQPSDBN=:2 or KWQPSDQN=:3)" + +static void print_prop_sender_stats(options_t * opts, connection_t * connp, + oci_t * ocip, ub4 queueid, + prop_pval_t ** prop_pval, + unsigned *pnum_ptr) +{ + prop_t prp; + OCIBind *bndp; + OCIDefine *defnp; + OCINumber total_bytes_num; + sword status = OCI_SUCCESS; + prop_pval_t *prop_elem; + prop_pval_t *new_elem; + prop_pval_t *cur_prop; + boolean cur_prop_exists = FALSE; + sid_pval_t sidval; + sid_pval_t *new_sid = 0; + + if (connp->version >= VERSION_10gR2) + { + OCICALL(ocip, + OCIStmtPrepare(ocip->stmt2p, ocip->errp, + (oratext *) PROP_SENDER_STATS_10gR2, + sizeof(PROP_SENDER_STATS_10gR2), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + } + else + { + OCICALL(ocip, + OCIStmtPrepare(ocip->stmt2p, ocip->errp, + (oratext *) PROP_SENDER_STATS, + sizeof(PROP_SENDER_STATS), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + } + + bndp = (OCIBind *)0; + OCIBindByPos(ocip->stmt2p, &bndp, ocip->errp, 1, + (void *) &queueid, + (sword) sizeof(queueid), + SQLT_UIN, + (void *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) 0, (ub4 *) 0, + OCI_DEFAULT); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 1, + (void *)&prp.src_queuename, + sizeof(prp.src_queuename), + SQLT_CHR, NULL, &prp.src_queuenamelen, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 2, + (void *)&prp.src_schemaname, + sizeof(prp.src_schemaname), + SQLT_CHR, NULL, &prp.src_schemanamelen, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 3, + &prp.total_number, sizeof(prp.total_number), + SQLT_UIN, NULL, NULL, NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 4, + &prp.total_time, sizeof(prp.total_time), + SQLT_UIN, NULL, NULL, NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 5, + &total_bytes_num, sizeof(total_bytes_num), + SQLT_VNU, NULL, NULL, NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 6, + (void *)&prp.destination, sizeof(prp.destination), + SQLT_CHR, NULL, &prp.destination_len, NULL, + OCI_DEFAULT)); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmt2p, ocip->errp, 0, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, + OCI_DEFAULT)); + + while(OCI_SUCCESS == + (status = OCIStmtFetch2(ocip->stmt2p, ocip->errp, 1, OCI_DEFAULT, 0, + OCI_DEFAULT))) + { + (*pnum_ptr)++; + cur_prop_exists = FALSE; + + /* convert total bytes to ub8 */ + OCICALL(ocip, + OCINumberToInt(ocip->errp, &total_bytes_num, + sizeof(prp.total_bytes), OCI_NUMBER_UNSIGNED, + &prp.total_bytes)); + + for (prop_elem = *prop_pval; + prop_elem != (prop_pval_t *)NULL; + prop_elem = prop_elem->next_prop) + { + cur_prop = prop_elem; + if ((prop_elem->src_queueid == queueid) + && (prop_elem->destination_len == prp.destination_len) + && !memcmp((void *)prop_elem->destination, (void *)prp.destination, + prp.destination_len)) + { + cur_prop_exists = TRUE; + + if (opts->short_opt) + { + /* In case the propagation process was brought down and restarted */ + if (prp.total_number >= prop_elem->total_number) + { + printf(" | PS%02u ", *pnum_ptr); + printf("%u", (prp.total_number - prop_elem->total_number)*100 + /opts->elapstim); + printf(" "); + printf("%d ",(prp.total_bytes - prop_elem->total_bytes)*100 + /opts->elapstim); + + print_bytes((prp.total_bytes - prop_elem->total_bytes)*100 + /opts->elapstim); + } + } + + /* update the data for the current propagation process */ + prop_elem->total_number = prp.total_number; + prop_elem->total_bytes = prp.total_bytes; + + break; + } + } + if (!cur_prop_exists) + { + /* add the data for the new propagation process into the linked list*/ + new_elem = (prop_pval_t *)malloc (sizeof(prop_pval_t)); + new_elem->src_queueid = queueid; + memcpy((void *)new_elem->src_queuename, (void *)(prp.src_queuename), + (prp.src_queuenamelen)); + new_elem->src_queuenamelen = prp.src_queuenamelen; + memcpy((void *)new_elem->src_schemaname, (void *)(prp.src_schemaname), + (prp.src_schemanamelen)); + new_elem->src_schemanamelen = prp.src_schemanamelen; + new_elem->destination_len = prp.destination_len; + memcpy((void *)new_elem->destination, (void *)prp.destination, + prp.destination_len); + new_elem->total_number = prp.total_number; + new_elem->total_bytes = prp.total_bytes; + new_elem->pevent_sender = NULL; + new_elem->pevent_receiver = NULL; + new_elem->next_prop = (prop_pval_t *)NULL; + if (*prop_pval == (prop_pval_t *)NULL) + { + *prop_pval = new_elem; + } + else + { + cur_prop->next_prop = new_elem; + } + cur_prop = new_elem; + + + if (connp->version >= VERSION_10gR2 && connp->sysdba) { + + OCICALL(ocip, + OCIStmtPrepare(ocip->stmt3p, ocip->errp, + (oratext *) PROPAGATION_SENDER_SIDS, + sizeof(PROPAGATION_SENDER_SIDS), + OCI_NTV_SYNTAX, + OCI_DEFAULT)); + + bndp = (OCIBind *)0; + OCIBindByPos(ocip->stmt3p, &bndp, ocip->errp, 1, + (void *) &(cur_prop->src_queueid), + (sword) sizeof(cur_prop->src_queueid), + SQLT_UIN, + (void *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) 0, (ub4 *) 0, + OCI_DEFAULT); + + + bndp = (OCIBind *)0; + OCIBindByPos(ocip->stmt3p, &bndp, ocip->errp, 2, + (void *) &(cur_prop->destination), + (sword) sizeof(cur_prop->destination), + SQLT_CHR, + (void *) 0, (ub2 *)&(cur_prop->destination_len), + (ub2 *) 0, (ub4) 0, (ub4 *) 0, + OCI_DEFAULT); + + bndp = (OCIBind *)0; + OCIBindByPos(ocip->stmt3p, &bndp, ocip->errp, 3, + (void *) &(cur_prop->destination), + (sword) sizeof(cur_prop->destination), + SQLT_CHR, + (void *) 0, (ub2 *)&(cur_prop->destination_len), + (ub2 *) 0, (ub4) 0, (ub4 *) 0, + OCI_DEFAULT); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmt3p, ocip->errp, 0, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt3p, &defnp, ocip->errp, 1, + &sidval.sid, + sizeof(sidval.sid), SQLT_UIN, NULL, + NULL, NULL, + OCI_DEFAULT)); + + while (OCI_SUCCESS == + (status = OCIStmtFetch2(ocip->stmt3p, ocip->errp, 1, OCI_DEFAULT, + 0, OCI_DEFAULT))) + { + new_sid = (sid_pval_t *)malloc(sizeof(sid_pval_t)); + new_sid->sid = sidval.sid; + new_sid->pval = new_elem; + new_sid->type = PR_SENDER_PROCESS; + new_sid->next = connp->sid_pval; + + connp->sid_pval = new_sid; + connp->num_sid ++; + } + } + + } + + if (!opts->short_opt) + { + printf(" | PS%02u %u %llu/%u", *pnum_ptr, prp.total_number, prp.total_bytes, + prp.total_time); + } + + if (cur_prop != NULL &&(connp->version >= VERSION_10gR2) && connp->sysdba) + { + print_event_stats(opts, (void *)cur_prop, PR_SENDER_PROCESS); + } + } + + if (OCI_ERROR == status) + { + ocierror(ocip, (char *)" | PS ", FALSE); + } + + /* finish fetching from the propagation cursor */ + OCICALL(ocip, + OCIStmtFetch2(ocip->stmt2p, ocip->errp, 0, OCI_DEFAULT, 0, + OCI_DEFAULT)); +} + +typedef struct apply +{ + ub4 sid; + ub4 applynum; + oratext applyname[128]; + ub2 applynamelen; + ub4 msgs_deqd; + OCINumber dequeue_scn; + oratext dequeue_scn_str[128]; + ub4 dequeue_scn_strlen; + ub4 txns_recvd; + ub4 txns_assigned; + ub4 txns_applied; + OCINumber hwm_scn; + oratext hwm_scn_str[128]; + ub4 hwm_scn_strlen; + sb4 hwm_latency; + sb4 dequeue_latency; + ub4 total_applied; +} apply_t; + +#define APPLY_SHORT_STATS "select ac.apply# applynum, \ +ac.apply_name, \ +nvl((ac.hwm_time - ac.hwm_message_create_time)*86400, -1) HWM_LATENCY, \ +sum(aps.TOTAL_MESSAGES_APPLIED), ac.total_received, \ +ac.total_assigned, ac.total_applied \ +from v$streams_apply_coordinator ac, \ +v$streams_apply_server aps where ac.apply#=aps.apply# \ +group by ac.apply#, ac.apply_name, ac.hwm_time, ac.hwm_message_create_time, \ +ac.total_assigned, ac.total_received, ac.total_applied order by 1" + +#define APPLY_READER_SERVER_SIDS \ +"(select sid, 4 process_type from v$streams_apply_reader where APPLY#=:1) UNION (select sid, 5 from v$streams_apply_server where APPLY#=:1) order by 1" + +static void print_short_apply_stats(options_t * opts, connection_t * connp, + oci_t * ocip, + app_pval_t ** app_pval) +{ + OCIBind *bndp; + OCIDefine *defnp; + apply_t app; + sb4 diff = 0; + sword status = OCI_SUCCESS; + app_pval_t *app_elem; + app_pval_t *new_elem; + app_pval_t *cur_app; + boolean cur_app_exists = FALSE; + sid_pval_t sidval; + sid_pval_t *new_sid = 0; + + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, + (oratext *) APPLY_SHORT_STATS, + sizeof(APPLY_SHORT_STATS), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmtp, ocip->errp, 0, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 1, &app.applynum, + sizeof(app.applynum), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 2, &app.applyname, + sizeof(app.applyname), SQLT_CHR, NULL, + &app.applynamelen, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 3, &app.hwm_latency, + sizeof(app.hwm_latency), SQLT_INT, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 4, + &app.total_applied, + sizeof(app.total_applied), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 5, &app.txns_recvd, + sizeof(app.txns_recvd), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 6, &app.txns_assigned, + sizeof(app.txns_assigned), SQLT_UIN, NULL, NULL,NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 7, &app.txns_applied, + sizeof(app.txns_applied), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + while(OCI_SUCCESS == + (status = OCIStmtFetch2(ocip->stmtp, ocip->errp, 1, OCI_DEFAULT, + 0, OCI_DEFAULT))) + { + cur_app_exists = FALSE; + + printf(" | "); + + for (app_elem = *app_pval; + app_elem != (app_pval_t *)NULL; + app_elem = app_elem->next_app) + { + cur_app = app_elem; + if ((app_elem->applynamelen == app.applynamelen) && + !memcmp((void *)app_elem->applyname, (void *)app.applyname, + (size_t)app_elem->applynamelen)) + { + cur_app_exists = TRUE; + + /* In case the apply had been brought down and then restarted */ + if (app.total_applied >= app_elem->total_applied) + { + if ((diff=(sb4)(app.txns_recvd - app.txns_assigned)) > 10) + { + printf(""); /* indicate apply as the potential bottleneck */ + } + else + { + printf(" - "); /* for alignment */ + } + + printf(" A%03u %u %u", app.applynum, + (app.total_applied - app_elem->total_applied)*100/opts->elapstim, + (app.txns_applied - app_elem->txns_applied)*100/opts->elapstim); + print_latency(app.hwm_latency); + + if (connp->version >= VERSION_10g) + { + print_event_stats(opts, (void *)cur_app, APPLY_READER); + print_event_stats(opts, (void *)cur_app, APPLY_SERVER); + } + + } + else + { + printf(" "); /* for alignment */ + } + + /* update the data for the current apply process */ + app_elem->total_applied = app.total_applied; + app_elem->txns_applied = app.txns_applied; + + break; + } + } + + if (!cur_app_exists) + { + printf(" "); /* for alignment */ + + /* add the data for the new apply process to the linked list */ + new_elem = (app_pval_t *)malloc(sizeof(app_pval_t)); + new_elem->applynum = app.applynum; + memcpy((void *)new_elem->applyname, (void *)app.applyname, + (size_t)app.applynamelen); + new_elem->applynamelen = app.applynamelen; + new_elem->total_applied = app.total_applied; + new_elem->txns_applied = app.txns_applied; + new_elem->server_num = 0; + + new_elem->pevent_reader = NULL; + new_elem->pevent_server = NULL; + new_elem->next_app = (app_pval_t *)NULL; + if (*app_pval == (app_pval_t *)NULL) + { + *app_pval = new_elem; + } + else + { + cur_app->next_app = new_elem; + } + cur_app = new_elem; + + if (connp->version >= VERSION_10g) + { + + /* Add the new sid info to sid_pval list */ + new_sid = (sid_pval_t *)malloc(sizeof(sid_pval_t)); + new_sid->sid = app.sid; + new_sid->pval = new_elem; + new_sid->type = APPLY_READER; + new_sid->next = connp->sid_pval; + + connp->sid_pval = new_sid; + connp->num_sid ++; + + /* Query to find the sids of the apply servers */ + OCICALL(ocip, + OCIStmtPrepare(ocip->stmt2p, ocip->errp, + (oratext *) APPLY_READER_SERVER_SIDS, + sizeof(APPLY_READER_SERVER_SIDS), + OCI_NTV_SYNTAX, + OCI_DEFAULT)); + + bndp = (OCIBind *)0; + OCIBindByPos(ocip->stmt2p, &bndp, ocip->errp, 1, + (void *) &(app.applynum), + (sword) sizeof(app.applynum), + SQLT_UIN, + (void *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) 0, (ub4 *) 0, + OCI_DEFAULT); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmt2p, ocip->errp, 0, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 1, + &sidval.sid, + sizeof(sidval.sid), SQLT_UIN, NULL, + NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 2, + &sidval.type, + sizeof(sidval.type), SQLT_UIN, NULL, + NULL, NULL, + OCI_DEFAULT)); + + while (OCI_SUCCESS == + (status = OCIStmtFetch2(ocip->stmt2p, ocip->errp, 1, OCI_DEFAULT, + 0, OCI_DEFAULT))) + { + new_sid = (sid_pval_t *)malloc(sizeof(sid_pval_t)); + new_sid->sid = sidval.sid; + new_sid->pval = new_elem; + new_sid->type = sidval.type; + new_sid->next = connp->sid_pval; + + connp->sid_pval = new_sid; + connp->num_sid ++; + + if (new_sid->type == APPLY_SERVER) + { + new_elem->server_num++; + } + } + } + } + + } + + if (OCI_ERROR == status) + { + ocierror(ocip, (char *)" | A ", FALSE); + } + + /* finish the cursor */ + OCICALL(ocip, + OCIStmtFetch2(ocip->stmtp, ocip->errp, 0, OCI_DEFAULT, 0, OCI_DEFAULT)); +} + +#define APPLY_STATS "select ar.sid, ac.apply# applynum, ac.apply_name, ar.TOTAL_MESSAGES_DEQUEUED, \ +nvl(ar.DEQUEUED_MESSAGE_NUMBER,0) DEQUEUED_MESSAGE_NUMBER, ac.total_received, \ +ac.total_assigned, ac.total_applied, nvl(ac.hwm_message_number,0) \ +HWM_MESSAGE_NUMBER, \ +nvl((ac.hwm_time - hwm_message_create_time)*86400, -1) HWM_LATENCY, \ +nvl((ar.dequeue_time - \ + ar.dequeued_message_create_time)*86400, -1) DEQUEUE_LATENCY \ +from v$streams_apply_coordinator ac, \ +v$streams_apply_reader ar where ac.apply#=ar.apply# order by 1" + +#define APPLY_SERVER_SIDS \ +"select sid from v$streams_apply_server where APPLY#=:1 order by 1" + +static void print_apply_stats(options_t * opts, connection_t * connp, + oci_t * ocip, + app_pval_t ** app_pval) +{ + OCIBind *bndp; + OCIDefine *defnp; + apply_t app; + sb4 diff = 0; + sword status = OCI_SUCCESS; + app_pval_t *app_elem; + app_pval_t *new_elem; + app_pval_t *cur_app; + boolean cur_app_exists = FALSE; + sid_pval_t sidval; + sid_pval_t *new_sid = 0; + + /* prepare the apply query */ + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, (oratext *) APPLY_STATS, + sizeof(APPLY_STATS), OCI_NTV_SYNTAX, OCI_DEFAULT)); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmtp, ocip->errp, 0, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 1, &app.sid, + sizeof(app.sid), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 2, &app.applynum, + sizeof(app.applynum), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 3, &app.applyname, + sizeof(app.applyname), SQLT_CHR, NULL, + &app.applynamelen, NULL, + OCI_DEFAULT)); + + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 4, &app.msgs_deqd, + sizeof(app.msgs_deqd), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 5, &app.dequeue_scn, + sizeof(app.dequeue_scn), SQLT_VNU, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 6, &app.txns_recvd, + sizeof(app.txns_recvd), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 7,&app.txns_assigned, + sizeof(app.txns_assigned), SQLT_UIN, NULL, NULL,NULL, + OCI_DEFAULT)); + + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 8, &app.txns_applied, + sizeof(app.txns_applied), SQLT_UIN, NULL, NULL, NULL, + OCI_DEFAULT)); + + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 9, &app.hwm_scn, + sizeof(app.hwm_scn), SQLT_VNU, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 10, + &app.hwm_latency, + sizeof(app.hwm_latency), SQLT_INT, NULL, NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 11, + &app.dequeue_latency, + sizeof(app.txns_recvd), SQLT_INT, NULL, NULL, NULL, + OCI_DEFAULT)); + + while(OCI_SUCCESS == + (status = OCIStmtFetch2(ocip->stmtp, ocip->errp, 1, OCI_DEFAULT, + 0, OCI_DEFAULT))) + { + cur_app_exists = FALSE; + + for (app_elem = *app_pval; + app_elem != (app_pval_t *)NULL; + app_elem = app_elem->next_app) + { + cur_app = app_elem; + if ((app_elem->applynamelen == app.applynamelen) && + !memcmp((void *)app_elem->applyname, (void *)app.applyname, + (size_t)app_elem->applynamelen)) + { + cur_app_exists = TRUE; + + /* update the data for the current apply process */ + app_elem->total_applied = app.total_applied; + app_elem->txns_applied = app.txns_applied; + + break; + } + } + + if (!cur_app_exists) + { + new_elem = (app_pval_t *)malloc(sizeof(app_pval_t)); + new_elem->applynum = app.applynum; + memcpy((void *)new_elem->applyname, (void *)app.applyname, + (size_t)app.applynamelen); + new_elem->applynamelen = app.applynamelen; + new_elem->total_applied = app.total_applied; + new_elem->txns_applied = app.txns_applied; + new_elem->pevent_reader = NULL; + new_elem->pevent_server = NULL; + new_elem->server_num = 0; + new_elem->next_app = (app_pval_t *)NULL; + if (*app_pval == (app_pval_t *)NULL) + { + *app_pval = new_elem; + } + else + { + cur_app->next_app = new_elem; + } + cur_app = new_elem; + + if (connp->version >= VERSION_10g) + { + + /* Add the new sid info to sid_pval list */ + new_sid = (sid_pval_t *)malloc(sizeof(sid_pval_t)); + new_sid->sid = app.sid; + new_sid->pval = new_elem; + new_sid->type = APPLY_READER; + new_sid->next = connp->sid_pval; + + connp->sid_pval = new_sid; + connp->num_sid ++; + + /* Query to find the sids of the apply servers */ + OCICALL(ocip, + OCIStmtPrepare(ocip->stmt2p, ocip->errp, + (oratext *) APPLY_SERVER_SIDS, + sizeof(APPLY_SERVER_SIDS), + OCI_NTV_SYNTAX, + OCI_DEFAULT)); + + bndp = (OCIBind *)0; + OCIBindByPos(ocip->stmt2p, &bndp, ocip->errp, 1, + (void *) &(app.applynum), + (sword) sizeof(app.applynum), + SQLT_UIN, + (void *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) 0, (ub4 *) 0, + OCI_DEFAULT); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmt2p, ocip->errp, 0, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt2p, &defnp, ocip->errp, 1, + &sidval.sid, + sizeof(sidval.sid), SQLT_UIN, NULL, + NULL, NULL, + OCI_DEFAULT)); + + while (OCI_SUCCESS == + (status = OCIStmtFetch2(ocip->stmt2p, ocip->errp, 1, OCI_DEFAULT, + 0, OCI_DEFAULT))) + { + new_sid = (sid_pval_t *)malloc(sizeof(sid_pval_t)); + new_sid->sid = sidval.sid; + new_sid->pval = new_elem; + new_sid->type = APPLY_SERVER; + new_sid->next = connp->sid_pval; + + connp->sid_pval = new_sid; + connp->num_sid ++; + new_elem->server_num++; + } + } + } + + app.dequeue_scn_strlen = 128; + OCICALL(ocip, + OCINumberToText(ocip->errp, &app.dequeue_scn, + (const oratext *)"TM9", 3, (oratext *)0, 0, + &app.dequeue_scn_strlen, app.dequeue_scn_str)); + + app.hwm_scn_strlen = 128; + OCICALL(ocip, + OCINumberToText(ocip->errp, &app.hwm_scn, + (const oratext *)"TM9", 3, (oratext *)0, 0, + &app.hwm_scn_strlen, app.hwm_scn_str)); + + printf(" | "); + + if ((diff=(sb4)(app.txns_recvd - app.txns_assigned)) > 10) + { + printf(" "); /* indicate apply as the potential bottleneck */ + } + else + { + printf(" - "); /* for alignment */ + } + + printf(" A%03u %5u %.*s", app.applynum, app.msgs_deqd, + app.dequeue_scn_strlen, app.dequeue_scn_str); + + print_latency(app.dequeue_latency); + + printf(" %5u %5u %5u %.*s", + app.txns_recvd, app.txns_assigned, app.txns_applied, + app.hwm_scn_strlen, app.hwm_scn_str); + + print_latency(app.hwm_latency); + + if (connp->version >= VERSION_10g) + { + print_event_stats(opts, (void *)cur_app, APPLY_READER); + print_event_stats(opts, (void *)cur_app, APPLY_SERVER); + } + } + + if (OCI_ERROR == status) + { + ocierror(ocip, (char *)" | A ", FALSE); + } + + /* finish the cursor */ + OCICALL(ocip, + OCIStmtFetch2(ocip->stmtp, ocip->errp, 0, OCI_DEFAULT, 0, OCI_DEFAULT)); +} + +#define MEM_STATS_10g "select frused_kwqbpmt from x$kwqbpmt" + +static void print_mem_stats(options_t * opts, oci_t * ocip) +{ + OCIDefine *defnp; + ub2 mem_used; + + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, (oratext *) MEM_STATS_10g, + sizeof(MEM_STATS_10g), OCI_NTV_SYNTAX, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 1, &mem_used, + sizeof(mem_used), SQLT_UIN, NULL, + NULL, NULL, OCI_DEFAULT)); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmtp, ocip->errp, 1, 0, + (OCISnapshot *)0, (OCISnapshot *)0, OCI_EXACT_FETCH)); + + printf(" | MEM %u %% ", mem_used); + print_pool_size(ocip); +} + + +#define VERSION_SQL "select version, instance_name from v$instance" + +static void get_version(connection_t * connp) +{ + OCIDefine *defnp; + ub2 i; + oratext tempstr[20]; + ub2 tempstrlen; + oci_t *ocip = connp->ocip; + + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, (oratext *) VERSION_SQL, + sizeof(VERSION_SQL), OCI_NTV_SYNTAX, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 1, + (void *)connp->versionstr, + sizeof(connp->versionstr), SQLT_CHR, NULL, + &connp->versionstrlen, NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 2, + (void *)connp->instname, + sizeof(connp->instname), SQLT_CHR, NULL, + &connp->instnamelen, NULL, OCI_DEFAULT)); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmtp, ocip->errp, 1, 0, + (OCISnapshot *)0, (OCISnapshot *)0, OCI_EXACT_FETCH)); + + tempstrlen = 0; + for (i=0; iversionstrlen; i++) + { + if (connp->versionstr[i] == '.') + { + continue; + } + tempstr[tempstrlen++] = connp->versionstr[i]; + } + tempstr[tempstrlen] = '\0'; + sscanf((char *)tempstr,"%u", &connp->version); + + if (connp->version < VERSION_9iR2) + { + printf("Error: ORACLE version %.*s didn't have STREAMS\n", + connp->versionstrlen, connp->versionstr); + exit(1); + } +} + +static void print_latency(sb4 latency) +{ + if (latency < 0) + { + printf(" -"); + } + else if (latency < 60) + { + printf(" %usec", latency); + } + else if (latency < 60*60) + { + printf(" %umin", (latency/60)); + } + else if (latency < 60*60*24) + { + printf(" %uhr ", (latency/(60*60))); + } + else if (latency < 60*60*24*12) + { + printf(" %uday", (latency/(60*60*24))); + } + else if (latency < 60*60*24*12*30) + { + printf(" %umon", (latency/(60*60*24*12))); + } + else + { + printf(" %uyr ", (latency/(60*60*24*12))); + } +} + +#define LGWR_STATS_SCN "select (LAST_WRITE_SCN_BAS + \ +(4294967296*LAST_WRITE_SCN_WRP)) LAST_WRITE_SCN from x$kcrfws" + +#define LGWR_STATS_BLKS "select value from v$sysstat where name =\ +'redo blocks written'" + +typedef struct lgwr +{ + OCINumber last_scn; + OCINumber last_blk; +} lgwr_t; + +static void print_log_stats(options_t * opts, oci_t * ocip, ub4 *lgwr_pval) +{ + + lgwr_t log; + OCIBind *bndp; + OCIDefine *defnp; + sb4 redo_rate; + OCINumber result; + ub4 int_result; + ub4 diff; + + /* get the count of blocks written */ + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, (oratext *) LGWR_STATS_BLKS, + sizeof(LGWR_STATS_BLKS), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + + defnp = (OCIDefine *)0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 1, &log.last_blk, + sizeof(log.last_blk), SQLT_VNU, NULL, NULL, NULL, + OCI_DEFAULT)); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmtp, ocip->errp, 1, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, OCI_EXACT_FETCH)); + + /* for long option, we need to get the last scn also and print out + * the number of blocks and last scn as a string */ + if (!opts->short_opt) + { + oratext last_scn_str[128]; + ub4 last_scn_strlen = 128; + oratext last_blk_str[128]; + ub4 last_blk_strlen = 128; + + /* get the last scn written */ + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, (oratext *) LGWR_STATS_SCN, + sizeof(LGWR_STATS_SCN), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + + defnp = (OCIDefine *)0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 1, &log.last_scn, + sizeof(log.last_scn), SQLT_VNU, NULL, NULL, NULL, + OCI_DEFAULT)); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmtp, ocip->errp, 1, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, + OCI_EXACT_FETCH)); + + OCICALL(ocip, + OCINumberToText(ocip->errp, &log.last_scn, + (const oratext *)"TM9", 3, (oratext *)0, 0, + &last_scn_strlen, last_scn_str)); + + OCICALL(ocip, + OCINumberToText(ocip->errp, &log.last_blk, + (const oratext *)"TM9", 3, (oratext *)0, 0, + &last_blk_strlen, last_blk_str)); + + printf(" | LOG %s %6s", last_scn_str, last_blk_str); + } + else + { + OCICALL(ocip, + OCINumberToInt(ocip->errp, &log.last_blk, sizeof(int_result), + OCI_NUMBER_UNSIGNED, &int_result)); + + if (*lgwr_pval) + { + /* take care of the case where the block number wraps around */ + if (int_result < *lgwr_pval) + { + printf(" | LOG - "); + } + else + { + redo_rate = (sb4)(((int_result - *lgwr_pval)*512*100)/(opts->elapstim)); + + printf(" | LOG "); + print_bytes((ub8)redo_rate); + } + } + + /* update the previous value last block number */ + *lgwr_pval = int_result; + } +} + +#define NET_STATS_CLIENT "select sum(value) from v$sysstat where name like\ +'bytes%client'" + +#define NET_STATS_DBLINK "select sum(value) from v$sysstat where name like\ +'bytes%dblink'" + +static void print_net_stats(options_t * opts, connection_t * connp) +{ + oci_t *ocip = connp->ocip; + OCIBind *bndp; + OCIDefine *defnp; + OCINumber client_bytes_num; + OCINumber dblink_bytes_num; + ub8 client_bytes; + ub8 dblink_bytes; + + /* get the client stats */ + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, (oratext *) NET_STATS_CLIENT, + sizeof(NET_STATS_CLIENT), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + + defnp = (OCIDefine *)0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 1, &client_bytes_num, + sizeof(client_bytes_num), SQLT_VNU, NULL, NULL, NULL, + OCI_DEFAULT)); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmtp, ocip->errp, 1, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, OCI_EXACT_FETCH)); + + /* get the dblink stats */ + OCICALL(ocip, + OCIStmtPrepare(ocip->stmtp, ocip->errp, (oratext *) NET_STATS_DBLINK, + sizeof(NET_STATS_DBLINK), OCI_NTV_SYNTAX, + OCI_DEFAULT)); + + defnp = (OCIDefine *)0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmtp, &defnp, ocip->errp, 1, &dblink_bytes_num, + sizeof(dblink_bytes_num), SQLT_VNU, NULL, NULL, NULL, + OCI_DEFAULT)); + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmtp, ocip->errp, 1, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, OCI_EXACT_FETCH)); + + + /* convert OCI Numbers to ub8s */ + OCICALL(ocip, OCINumberToInt(ocip->errp, &client_bytes_num, + sizeof(client_bytes), OCI_NUMBER_UNSIGNED, + &client_bytes)); + + OCICALL(ocip, OCINumberToInt(ocip->errp, &dblink_bytes_num, + sizeof(dblink_bytes), OCI_NUMBER_UNSIGNED, + &dblink_bytes)); + + if (opts->short_opt) + { + if (connp->client_bytes || connp->dblink_bytes) + { + printf(" | NET "); + print_bytes((client_bytes - connp->client_bytes)*100/opts->elapstim); + printf(" "); + print_bytes((dblink_bytes - connp->dblink_bytes)*100/opts->elapstim); + } + + connp->client_bytes = client_bytes; + connp->dblink_bytes = dblink_bytes; + } + else + { + printf(" | NET %llu %llu", client_bytes, dblink_bytes); + } +} + + +static void print_event_stats (options_t * opts, void* pval, process_type_t type) +{ + ub8 idleTime = 0; + ub8 flowControlTime = 0; + ub8 maxEventTime = 0; + + ub8 idle_rate = 0; + ub8 flowcontrol_rate = 0; + ub8 max_event_rate = 0; + ub8 sum_rate = 0; + ub8 total_rate = 100; + ub8 time_diff; + + event_pval_t** pevt; + event_pval_t* cur = NULL; + event_pval_t* maxEvt = NULL; + ub2 i = 0; + const char* idle_events; + const char* flowcontrol_events; + char event_name[800]; + OCIBind *bndp; + + if (pval == NULL) + return; + + /*Construct the sqlcommand*/ + if (type == CAPTURE_PROCESS) + { + cap_pval_t * cap_pval = (cap_pval_t *)pval; + pevt = &(cap_pval->pevent); + + idle_events = capture_idle_events; + flowcontrol_events = capture_flowcontrol_events; + } + + else if (type == PR_SENDER_PROCESS) + { + + prop_pval_t * prop_pval = (prop_pval_t *)pval; + pevt = &(prop_pval->pevent_sender); + + idle_events = propagation_sender_idle_events; + flowcontrol_events = propagation_sender_flowcontrol_events; + } + else if (type == PR_RECEIVER_PROCESS) + { + + prop_pval_t * prop_pval = (prop_pval_t *)pval; + pevt = &(prop_pval->pevent_receiver); + + idle_events = propagation_receiver_idle_events; + flowcontrol_events = propagation_receiver_flowcontrol_events; + } + else if (type == APPLY_READER) + { + app_pval_t * app_pval = (app_pval_t *)pval; + pevt = &(app_pval->pevent_reader); + + printf(" AR:"); + + idle_events = apply_reader_idle_events; + flowcontrol_events = apply_reader_flowcontrol_events; + } + else if (type == APPLY_SERVER) + { + app_pval_t * app_pval = (app_pval_t *)pval; + pevt = &(app_pval->pevent_server); + + /* For apply server, maxEvt contains the number of apply server + process. total rate is 100 * number of apply server process. + */ + if (app_pval->server_num > 0) + total_rate = 100 * app_pval->server_num; + + printf(" AS(%d)", app_pval->server_num); + + idle_events = apply_server_idle_events; + flowcontrol_events = apply_server_flowcontrol_events; + } + + if (*pevt == NULL) return; + + for (cur = (*pevt); cur != NULL; cur = cur->next_event) + { + + sprintf(event_name, "|%.*s|\0",cur->event_namelen, cur->event_name); + time_diff = cur->time_in_micro_second - cur->time_in_micro_second_old; + if (strstr(idle_events,event_name)) + { + idleTime += time_diff; + continue; + } + + else if (strstr(flowcontrol_events,event_name)) + { + flowControlTime += time_diff; + continue; + } + else if (time_diff > maxEventTime) + { + maxEventTime = time_diff; + maxEvt = cur; + } + } + + /* printf("\nidle: %llu, flowcontrol: %llu, maxeventtime: %llu \n", idleTime, flowControlTime, maxEventTime); + */ + idle_rate = idleTime/opts->elapstim/100; + + flowcontrol_rate = flowControlTime/opts->elapstim/100; + + max_event_rate = maxEventTime/opts->elapstim/100; + + sum_rate = idle_rate + flowcontrol_rate + max_event_rate; + + if (sum_rate > total_rate) + { + idle_rate = (idle_rate * total_rate) / sum_rate; + flowcontrol_rate = (flowcontrol_rate * total_rate) / sum_rate; + max_event_rate = (max_event_rate * total_rate) / sum_rate; + } + + if ((opts->short_opt && max_event_rate < 5) || max_event_rate < 1) + { + printf(" <%llu%%I %llu%%F -> ", idle_rate, flowcontrol_rate); + } + else + printf(" <%llu%%I %llu%%F %llu%%\"%.*s\"> ", idle_rate, flowcontrol_rate, max_event_rate, maxEvt->event_namelen, maxEvt->event_name); + + fflush(stdout); + +} + +#define WAIT_EVENT_STATS \ + "select sid, event, TIME_WAITED_MICRO from V$SESSION_EVENT s where sid in %s order by 1" + +static void collect_event_data (options_t * opts, connection_t *connp) +{ + oci_t *ocip = connp->ocip; + OCIDefine *defnp; + event_pval_t wevt; + event_pval_t **pevt; + event_pval_t *cur = NULL; + sword status = OCI_SUCCESS; + OCINumber time_in_micro_second; + ub2 found; + char eventquery[3072]; + ub4 eventquerylen; + sid_pval_t *sidpval; + char *curpos; + ub4 in_process_sid = 0; + + if (connp->num_sid <= 0) return; + + if (connp->num_sid != connp->org_sid) { + sidpval = connp->sid_pval; + sprintf(connp->sidstr, "(%d", sidpval->sid); + sidpval = sidpval->next; + curpos = connp->sidstr + strlen(connp->sidstr); + + while (sidpval != NULL) { + sprintf(curpos, ",%d", sidpval->sid); + sidpval = sidpval->next; + curpos = curpos + strlen(curpos); + } + + sprintf(curpos, ")"); + + connp->org_sid = connp->num_sid; + + /* Reinitial sidpval to NULL */ + sidpval = NULL; + + } + + (ub4)sprintf(eventquery, WAIT_EVENT_STATS, connp->sidstr); + eventquerylen = strlen(eventquery); + + OCICALL(ocip, + OCIStmtPrepare(ocip->stmt3p, ocip->errp, + (oratext *) eventquery, + eventquerylen, OCI_NTV_SYNTAX, + OCI_DEFAULT)); + + /* Start to query V$SESSION_EVENT to get the wait_event data.*/ + + OCICALL(ocip, + OCIStmtExecute(ocip->svcp, ocip->stmt3p, ocip->errp, 0, 0, + (OCISnapshot *)NULL, (OCISnapshot *)NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt3p, &defnp, ocip->errp, 1, &wevt.sidnum, + sizeof(wevt.sidnum), SQLT_UIN, NULL, + NULL, NULL, + OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt3p, &defnp, ocip->errp, 2, + &wevt.event_name, sizeof(wevt.event_name), + SQLT_CHR, NULL, &wevt.event_namelen, NULL, OCI_DEFAULT)); + + defnp = (OCIDefine *) 0; + OCICALL(ocip, + OCIDefineByPos(ocip->stmt3p, &defnp, ocip->errp, 3, &time_in_micro_second, + sizeof(time_in_micro_second), SQLT_VNU, NULL, NULL, NULL, + OCI_DEFAULT)); + + while(OCI_SUCCESS == + (status = OCIStmtFetch2(ocip->stmt3p, ocip->errp, 1, OCI_DEFAULT, + 0, OCI_DEFAULT))) + { + OCICALL(ocip, + OCINumberToInt(ocip->errp, &time_in_micro_second, 8, OCI_NUMBER_UNSIGNED, &(wevt.time_in_micro_second))); + + + if (wevt.sidnum != in_process_sid || sidpval == NULL) + { + in_process_sid = wevt.sidnum; + + sidpval = connp->sid_pval; + while ( sidpval != NULL && sidpval->sid != in_process_sid) + { + sidpval = sidpval->next; + } + } + + if (sidpval == NULL) + { + /* error out */ + } + + if (sidpval->type == CAPTURE_PROCESS) + { + pevt = &(((cap_pval_t *)sidpval->pval)->pevent); + } + else if (sidpval->type == PR_SENDER_PROCESS) + { + pevt = &(((prop_pval_t *)sidpval->pval)->pevent_sender); + } + else if (sidpval->type == PR_RECEIVER_PROCESS) + { + pevt = &(((prop_pval_t *)sidpval->pval)->pevent_receiver); + } + else if (sidpval->type == APPLY_READER) + { + pevt = &(((app_pval_t *)sidpval->pval)->pevent_reader); + } + else if (sidpval->type == APPLY_SERVER) + { + pevt = &(((app_pval_t *)sidpval->pval)->pevent_server); + } + + found = 0; + + for (cur = *pevt; cur != NULL; cur = cur->next_event) + { + if ((cur->event_namelen == wevt.event_namelen) && !strncmp((const char *)cur->event_name, (const char *)wevt.event_name, wevt.event_namelen)) + { + found = 1; + break; + } + } + + if(found) + { + if (opts->iters > cur->iters) + { + /* Save old time_in_micro_second */ + cur->time_in_micro_second_old = cur->time_in_micro_second; + + /* Update time_in_micro_second */ + cur->time_in_micro_second = wevt.time_in_micro_second; + cur->iters = opts->iters; + } + /* Where there are multiple apply servers */ + else if ( opts->iters == cur->iters) + { + cur->time_in_micro_second += wevt.time_in_micro_second; + } + } + else { + /* Two possibilities: First time monitor or new wait event */ + event_pval_t *evt = (event_pval_t *)malloc(sizeof(event_pval_t)); + + evt->sidnum = wevt.sidnum; + memcpy((void *)evt->event_name, (void *)wevt.event_name, (size_t)wevt.event_namelen); + evt->event_namelen = wevt.event_namelen; + + evt->time_in_micro_second = wevt.time_in_micro_second; + evt->time_in_micro_second_old = 0; + evt->iters = opts->iters; + evt->next_event = NULL; + + if (*pevt == NULL) + { + *pevt = evt; + } + else { + evt->next_event = *pevt; + *pevt = evt; + } + } + } + if (OCI_ERROR == status) + { + ocierror(ocip, (char *)" | A ", FALSE); + } + +} + +static void print_bytes(ub8 bytes) +{ + if (bytes < 1024) + { + printf("%llu", bytes); + } + else if (bytes < (1024*1024)) + { + printf("%lluK", bytes/1024); + } + else if (bytes < 1000000000) + { + printf("%lluM", bytes/(1024*1024)); + } + else + { + printf("%lluG", bytes/(1024*1024*1024)); + } +} + +/* end of file strmmon.c */ + diff --git a/strmmv1.sql b/strmmv1.sql new file mode 100644 index 0000000..37385f3 --- /dev/null +++ b/strmmv1.sql @@ -0,0 +1,363 @@ +Rem +Rem $Header: strmmv1.sql 13-dec-2006.02:59:43 davzhang Exp $ +Rem +Rem strmmv1.sql +Rem +Rem Copyright (c) 2006, Oracle. All rights reserved. +Rem +Rem NAME +Rem strmmv1.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem davzhang 12/13/06 - drop job before drop user +Rem davzhang 08/29/06 - where clause when selecting from +Rem dba_apply_instantiated_objects +Rem liwong 05/16/06 - sync capture cleanup +Rem davzhang 04/18/06 - wait for job queue before drop user +Rem wesmith 01/19/06 - Created +Rem + +set echo on +set pages 10000 +set serveroutput on +COLUMN STREAMS_TYPE HEADING 'STREAMS_TYPE' FORMAT A19 + +connect system/manager + +-- +-- create user for MVs +-- +drop user tabowner cascade; +grant connect, resource, create materialized view to tabowner + identified by tabowner; + +-- +-- create procedure to wait for job queue processes to finish +-- +set echo off +grant create any job to system; +CREATE OR REPLACE PROCEDURE wait_for_jobq AS + JQ_COUNT NUMBER :=1; + WAIT_SEC NUMBER :=600; + cursor stradm_jobs is + select owner,job_name from dba_scheduler_jobs + where owner='STRADM'; +BEGIN + for rec in stradm_jobs loop + sys.dbms_scheduler.drop_job( + job_name => rec.owner || '.' || rec.job_name, + force => true); + end loop; + -- disable job queue, make sure no jobs are started from now + -- wait for given time + SYS.DBMS_IJOB.SET_ENABLED(FALSE); + WAIT_SEC := WAIT_SEC * 2; + FOR I IN 1..WAIT_SEC LOOP + DBMS_LOCK.SLEEP(0.5); + -- any removed job still running? + SELECT COUNT(*) INTO JQ_COUNT + FROM V$LOCK V + WHERE V.TYPE = 'JQ' AND NOT EXISTS + (SELECT * FROM DBA_JOBS J WHERE V.ID2=J.JOB); + IF JQ_COUNT<=0 THEN + EXIT; + END IF; + END LOOP; + IF JQ_COUNT>0 THEN + -- ISSUE USER-DEFINED ERROR MESSAGE. + RAISE_APPLICATION_ERROR(-20101, 'Time Out Waiting Jobs To Finish'); + END IF; + SYS.DBMS_IJOB.SET_ENABLED(TRUE); +END; +/ +set echo on +-- +-- create tables, mvlogs, mvs +-- +connect tabowner/tabowner +create table foo (c1 number primary key, c2 varchar2(20)); +create table bar (c1 number, c2 varchar2(20)); + +create materialized view log on foo; +create materialized view log on bar with rowid; + +create materialized view foo_s refresh fast as select * from foo; +create materialized view bar_s refresh fast with rowid as select * from bar; + + +-- grant necessary privileges for streams admin +connect system/manager + +drop user stradm cascade; +grant dba to stradm identified by stradm; +begin + dbms_streams_auth.grant_admin_privilege( + grantee => 'stradm', + grant_privileges => true); +end; +/ + +-- +-- create package async_mv_pkg for async on-commit MV support +-- +connect stradm/stradm +set echo off +@strmmvp1 +set echo on + +-- +-- streams setup +-- +begin + dbms_streams_adm.set_up_queue( + queue_table => 'stradm.ASYNC_MV_QT', + queue_name => 'stradm.ASYNC_MV_Q'); +end; +/ + +variable site1 varchar2(80); +execute select global_name into :site1 from global_name; +print site1; + +-- set up streams for all tables with MV logs +exec async_mv_pkg.register_tables('CAPTURE_MV', 'APPLY_MV'); + +begin + dbms_apply_adm.set_parameter( + apply_name => 'APPLY_MV', + parameter => 'disable_on_error', + value => 'n'); +end; +/ + +-- assign precommit handler to apply process +begin + dbms_apply_adm.alter_apply( + apply_name => 'APPLY_MV', + precommit_handler => 'stradm.async_mv_pkg.async_mv_commit_hdlr'); +end; +/ + +begin + dbms_apply_adm.start_apply( + apply_name => 'APPLY_MV'); +end; +/ + +begin + dbms_capture_adm.start_capture( + capture_name => 'CAPTURE_MV'); +end; +/ + +-- check streams metadata +select streams_type, streams_name, table_owner, table_name, + rule_owner, rule_name +from dba_streams_table_rules +where streams_name in ('CAPTURE_MV', 'APPLY_MV') +order by streams_type, streams_name, table_owner, table_name; + +select source_object_owner, source_object_name, source_database, + instantiation_scn +from dba_apply_instantiated_objects +where source_object_owner='TABOWNER' +order by source_database, source_object_owner, source_object_name; + +select object_owner, object_name, operation_name, user_procedure +from dba_apply_dml_handlers +where apply_name = 'APPLY_MV' +order by object_owner, object_name, operation_name; + +-- do some DMLs +connect tabowner/tabowner +insert into foo values (1, 'foo_a'); +insert into foo values (2, 'foo_b'); +insert into bar values (1, 'bar_a'); +insert into bar values (2, 'bar_b'); +commit; + +update foo set c2 = 'foo_b_updated' where c1=2; +delete from foo where c1=1; +commit; + +update bar set c2 = 'bar_b_updated' where c1=2; +delete from bar where c1=1; +commit; + +-- wait for streams to finish +set serveroutput on +set timing on +exec verify_tables('foo','foo_s'); +exec verify_tables('bar','bar_s'); +set timing off + +-- check for convergence (verify that refresh_dependent was called) +select * from foo; +select * from foo_s; + +select * from bar; +select * from bar_s; + +-- submit a job to register new tables having MV logs every minute +connect stradm/stradm +declare + l_jobnum number; + str varchar2(100); +begin + str := + 'begin ' || + ' stradm.async_mv_pkg.register_tables(''CAPTURE_MV'',''APPLY_MV''); ' || + ' commit; ' || + 'end;'; + + dbms_scheduler.create_job( + job_name => dbms_scheduler.generate_job_name, + job_type => 'PLSQL_BLOCK', + job_action => str, + start_date => sysdate, + repeat_interval => 'FREQ=minutely', + enabled => TRUE); + + commit; +end; +/ + +-- create another table with an MV log and MV on it and verify that +-- it is set up for streams +connect tabowner/tabowner +create table foo2 (c1 number primary key, c2 varchar2(20)); +create materialized view log on foo2; +create materialized view foo2_s refresh fast as select * from foo2; + +-- wait for the register_tables() job to finish +set serveroutput on +exec verify_table_rules('TABOWNER', 'FOO2', true); + +-- do some dmls +insert into foo2 values (1, 'foo_a'); +insert into foo2 values (2, 'foo_b'); +commit; +update foo2 set c2 = 'foo2_b_updated' where c1=2; +delete from foo2 where c1=1; +commit; + +-- check streams metadata: should include foo2 +connect stradm/stradm +select streams_type, streams_name, table_owner, table_name, + rule_owner, rule_name +from dba_streams_table_rules +where streams_name in ('CAPTURE_MV', 'APPLY_MV') +order by streams_type, streams_name, table_owner, table_name; + +select source_object_owner, source_object_name, source_database, + instantiation_scn +from dba_apply_instantiated_objects +where source_object_owner='TABOWNER' +order by source_database, source_object_owner, source_object_name; + +select object_owner, object_name, operation_name, user_procedure +from dba_apply_dml_handlers +where apply_name = 'APPLY_MV' +order by object_owner, object_name, operation_name; + +-- wait for streams to finish +connect tabowner/tabowner +set serveroutput on +set timing on +exec verify_tables('foo2','foo2_s'); +set timing off + +-- check for convergence (verify that refresh_dependent was called) +select * from foo2; +select * from foo2_s; + +-- submit a job to unregister tables no longer having MV logs every minute +connect stradm/stradm +declare + l_jobnum number; + str varchar2(100); +begin + str := + 'begin ' || + ' stradm.async_mv_pkg.unregister_tables(''CAPTURE_MV'',''APPLY_MV''); ' || + ' commit; ' || + 'end;'; + + dbms_scheduler.create_job( + job_name => dbms_scheduler.generate_job_name, + job_type => 'PLSQL_BLOCK', + job_action => str, + start_date => sysdate, + repeat_interval => 'FREQ=minutely', + enabled => TRUE); + + commit; +end; +/ + +--- now drop an mvlog from foo, all streams metadata should be removed for foo +connect tabowner/tabowner +drop materialized view log on foo; + +-- wait for the unregister_tables() job to finish +set serveroutput on +exec verify_table_rules('TABOWNER', 'FOO', false); + +-- check streams metadata: should not include foo +connect stradm/stradm +select streams_type, streams_name, table_owner, table_name, + rule_owner, rule_name +from dba_streams_table_rules +where streams_name in ('CAPTURE_MV', 'APPLY_MV') +order by streams_type, streams_name, table_owner, table_name; + +select source_object_owner, source_object_name, source_database, + instantiation_scn +from dba_apply_instantiated_objects +where source_object_owner='TABOWNER' +order by source_database, source_object_owner, source_object_name; + +select object_owner, object_name, operation_name, user_procedure +from dba_apply_dml_handlers +where apply_name = 'APPLY_MV' +order by object_owner, object_name, operation_name; + +-- drop mvlog on bar, foo2 +connect tabowner/tabowner +drop materialized view log on bar; +drop materialized view log on foo2; + +-- remove async_mv streams configuration +connect stradm/stradm +exec async_mv_pkg.remove_async_mv_streams('CAPTURE_MV', 'APPLY_MV'); + +select 1 from dba_capture where capture_name = 'CAPTURE_MV'; +select 1 from dba_apply where apply_name = 'APPLY_MV'; + +select streams_type, streams_name, table_owner, table_name, + rule_owner, rule_name +from dba_streams_table_rules +where streams_name in ('CAPTURE_MV', 'APPLY_MV'); + +select source_object_owner, source_object_name, source_database, + instantiation_scn +from dba_apply_instantiated_objects +where source_object_owner='TABOWNER' +order by source_database, source_object_owner, source_object_name; + +select object_owner, object_name, operation_name, user_procedure +from dba_apply_dml_handlers +where apply_name = 'APPLY_MV' +order by object_owner, object_name, operation_name; + +-- cleanup +connect system/manager +exec wait_for_jobq; +drop user tabowner cascade; +drop user stradm cascade; diff --git a/strmmv1README.txt b/strmmv1README.txt new file mode 100644 index 0000000..d154e89 --- /dev/null +++ b/strmmv1README.txt @@ -0,0 +1,62 @@ +/ +/ $Header: strmmv1README.txt 24-jan-2006.16:01:05 wesmith Exp $ +/ +/ strmmv1README.txt +/ +/ Copyright (c) 2006, Oracle. All Rights Reserved. +/ +/ NAME +/ strmmv1README.txt - +/ +/ DESCRIPTION +/ +/ +/ NOTES +/ +/ +/ MODIFIED (MM/DD/YY) +/ wesmith 01/24/06 - Creation +/ + +Asynchronous commit-time MV refresh using Streams + +This script creates a package with the following procedures: +- register_tables() which sets up streams for all tables with MV logs +- unregister_tables() which removes streams for all tables that no longer + have MV logs +- apply DML handler which caches all tables involved in a transaction in + a package state variable +- apply pre-commit handler which submits a job to call refresh_dependent + (in this package) on all tables that were cached. +- refresh_dependent() which calls dbms_mview.refresh_dependent() after + possibly eliminating tables that no longer have any dependent MVs that + need refreshing (due to other concurrent refresh_dependent() jobs). + Nested MVs are refreshed too, if required. +- remove_async_mv_streams() which removes ASYNC_MV streams configuration +Using this package will allow you to set up local MVs that will refresh +asynchronously at commit-time using Streams. + +NOTES: +- refresh_dependent() references all_refresh_dependencies which gives the + oldest refresh scn for a master table, so + commit_scn > oldest_refresh_scn implies that at least one dependent MV + is stale. So calling dbms_mview.refresh_dependent() may still + result in null refreshes. It may be possible to modify this procedure + to consider the last refresh scn of each dependent MV. + +- refresh_dependent() does not consider refresh groups. It may be possible + to modify this to consider additional refresh group views. + +Instructions: +- create streams administrator +- create streams queue +- call async_mv_pkg.register_tables() passing a special capture and apply name +- set applicable apply parameters +- call dbms_apply_adm.alter_apply to assign precommit handler to apply process +- start capture and apply +- you can submit jobs for async_mv_pkg.register_tables(), + async_mv_pkg.unregister_tables() + to keep track of new tables with MV logs, or tables that no longer have + MV logs, simplifying the administration. +- call async_mv_pkg.remove_async_mv_streams() to remove the streams + configuration for async MV refresh. diff --git a/strmmv2.sql b/strmmv2.sql new file mode 100644 index 0000000..1d5d77f --- /dev/null +++ b/strmmv2.sql @@ -0,0 +1,493 @@ +Rem +Rem $Header: strmmv2.sql 27-sep-2006.15:36:22 davzhang Exp $ +Rem +Rem strmmv2.sql +Rem +Rem Copyright (c) 2006, Oracle. All rights reserved. +Rem +Rem NAME +Rem strmmv2.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem davzhang 09/27/06 - grant create view explicitly +Rem davzhang 08/29/06 - where clause when selecting from +Rem dba_apply_instantiated_objects +Rem wesmith 06/23/06 - register_mv: add parameter queue_name +Rem wesmith 06/12/06 - remove wait_for_jobq() call and misc cleanup +Rem liwong 05/16/06 - sync capture cleanup +Rem davzhang 04/18/06 - wait for job queue before drop user +Rem wesmith 01/19/06 - Created +Rem + +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 10000 +SET SERVEROUTPUT ON + +COLUMN SRC_LONG_CNAME FORMAT A15 +COLUMN SCHEMA_NAME FORMAT A15 +COLUMN OBJECT_NAME FORMAT A15 +COLUMN STREAMS_TYPE HEADING 'STREAMS_TYPE' FORMAT A19 + +variable site1 varchar2(80); + +-- grant necessary privileges for streams admin +connect system/manager + +drop user stradm cascade; +grant dba to stradm identified by stradm; +grant execute on SYS.DBMS_SYSTEM to stradm; +begin + dbms_streams_auth.grant_admin_privilege( + grantee => 'stradm', + grant_privileges => true); +end; +/ + +-- create user for MVs +drop user sqst cascade; +grant connect, resource to sqst identified by sqst; +grant create materialized view, create view to sqst; + +connect sqst/sqst + +-- create base tables and load +set echo off +@strmmv2s +set echo on + +-- create views to aid data verification +create view orders_v as +select o_id, orders.c_id c_id, ol_num, + orders.rowid o_rid, customer.rowid c_rid +from orders, customer +where orders.c_id = customer.c_id +and customer.zip >= 19555; + +create view oline_v as +select ol_id, order_line.o_id, i_id, + order_line.rowid ol_rid, orders.rowid o_rid, customer.rowid c_rid +from order_line, orders, customer +where order_line.o_id = orders.o_id +and orders.c_id = customer.c_id +and customer.zip >= 19555; + +-- MV logs +--create materialized view log on orders with primary key, rowid; +--create materialized view log on order_line with rowid; +--create materialized view log on customer with primary key, rowid(zip); + +-- MJV +create materialized view orders_mv refresh force as +select o_id, orders.c_id, ol_num, orders.rowid o_rid, customer.rowid c_rid +from orders, customer +where orders.c_id = customer.c_id +and customer.zip >= 19555; + +-- another MJV +create materialized view oline_mv refresh force as +select ol_id, order_line.o_id, i_id, + order_line.rowid ol_rid, orders.rowid o_rid, customer.rowid c_rid +from order_line, orders, customer +where order_line.o_id = orders.o_id +and orders.c_id = customer.c_id +and customer.zip >= 19555; + +create unique index oline_mv_u1 on oline_mv(ol_rid, o_rid, c_rid); + +-- pk-based MV (single table) +create materialized view customer_mv refresh force as select * from customer; + +-- +-- create unsupported MVs +-- + +-- rowid MV +create materialized view bad_rowid refresh force with rowid as +select * from customer; + +-- on-commit MV +create materialized view bad_oncmt refresh force with rowid on commit as +select * from customer; + +-- updatable MV +create materialized view bad_upd refresh force for update as +select * from customer; + +-- subquery MV +create materialized view bad_sq refresh force as +select o_id, orders.c_id, ol_num from orders + where exists + (select c_id from customer + where zip >= 19555 and orders.c_id = customer.c_id); + +-- union all MJV +create materialized view bad_mjv_union_all refresh force as +select '1' mark, o_id, orders.c_id, ol_num, orders.rowid o_rid, + customer.rowid c_rid +from orders, customer +where orders.c_id = customer.c_id +and customer.zip >= 19555 +union all +select '2' mark, o_id, orders.c_id, ol_num, orders.rowid o_rid, + customer.rowid c_rid +from orders, customer +where orders.c_id = customer.c_id +and customer.zip <= 11005; + +-- MV with objects +create or replace type t1 as object (a1 number, a2 date) +/ +create table objreltab (c1 number primary key, c2 t1, c3 varchar2(10)); +create snapshot log on objreltab; +create materialized view bad_obj refresh force as select * from objreltab; + + +-- create supporting objects and packages for streams refresh metadata +connect stradm/stradm +set echo off +@strmmvp2 +set echo on + +-- +-- streams setup +-- +begin + dbms_streams_adm.set_up_queue + (queue_user => 'stradm', queue_name => 'mv_master_q', + queue_table => 'mv_master_qt'); +end; +/ + +-- setting key columns is mandatory if a primary key does not exist on the MV +exec dbms_apply_adm.set_key_columns('SQST.ORDERS_MV', 'o_rid, c_rid'); +exec dbms_apply_adm.set_key_columns('SQST.OLINE_MV', 'ol_rid, o_rid, c_rid'); + +-- register orders_mv for dbms_mview.refresh() +begin + streams_mv_refresh_adm.register_mv( + mv_owner=>'"SQST"', mv_name=>'"ORDERS_MV"', + capture_name=>'"CAPTURE"', apply_name=>'"APPLY_MV_MASTER"', + queue_name=>'mv_master_q', + instantiate=>FALSE, use_streams_refresh=>FALSE); +end; +/ + +-- register oline_mv, customer_mv for streams-based refresh +begin + streams_mv_refresh_adm.register_mv( + mv_owner=>'sqst', mv_name=>'oline_mv', + capture_name=>'capture', apply_name=>'apply_mv_master', + instantiate=>TRUE, use_streams_refresh=>TRUE); +end; +/ + +begin + streams_mv_refresh_adm.register_mv( + mv_owner=>'SQST', mv_name=>'CUSTOMER_MV', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER', + instantiate=>FALSE, use_streams_refresh=>TRUE); +end; +/ + +-- FAIL: non-existent MV +begin + streams_mv_refresh_adm.register_mv( + mv_owner=>'SQST', mv_name=>'no_such_mv', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER', + instantiate=>FALSE, use_streams_refresh=>TRUE); +end; +/ + +-- +-- unsupported registrations for streams-based refresh (neg testcases) +-- +begin + streams_mv_refresh_adm.register_mv( + mv_owner=>'SQST', mv_name=>'BAD_ROWID', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER', + instantiate=>FALSE, use_streams_refresh=>TRUE); +end; +/ +begin + streams_mv_refresh_adm.register_mv( + mv_owner=>'SQST', mv_name=>'BAD_ONCMT', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER', + instantiate=>FALSE, use_streams_refresh=>TRUE); +end; +/ +begin + streams_mv_refresh_adm.register_mv( + mv_owner=>'SQST', mv_name=>'BAD_UPD', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER', + instantiate=>FALSE, use_streams_refresh=>TRUE); +end; +/ +begin + streams_mv_refresh_adm.register_mv( + mv_owner=>'SQST', mv_name=>'BAD_SQ', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER', + instantiate=>FALSE, use_streams_refresh=>TRUE); +end; +/ +begin + streams_mv_refresh_adm.register_mv( + mv_owner=>'SQST', mv_name=>'BAD_MJV_UNION_ALL', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER', + instantiate=>FALSE, use_streams_refresh=>TRUE); +end; +/ + + +connect stradm/stradm +exec dbms_capture_adm.start_capture('CAPTURE'); + +exec dbms_apply_adm.set_parameter('APPLY_MV_MASTER','DISABLE_ON_ERROR','N'); + +-- assign precommit handler to apply process +begin + dbms_apply_adm.alter_apply( + apply_name => 'APPLY_MV_MASTER', + precommit_handler => 'streams_mv_refresh.source_commit_hdlr'); +end; +/ +exec dbms_apply_adm.start_apply('APPLY_MV_MASTER'); + +-- check streams metadata +select apply_name, status from dba_apply order by apply_name; +select capture_name, status from dba_capture order by 1,2; + +select streams_type, streams_name, table_owner, table_name, + rule_owner, rule_name +from dba_streams_table_rules +where streams_name in ('CAPTURE', 'APPLY_MV_MASTER') +order by streams_type, streams_name, table_owner, table_name; + +select source_object_owner, source_object_name, source_database, + instantiation_scn +from dba_apply_instantiated_objects +where source_object_owner='SQST' +order by source_database, source_object_owner, source_object_name; + +select object_owner, object_name, operation_name, user_procedure +from dba_apply_dml_handlers +where apply_name = 'APPLY_MV_MASTER' +order by object_owner, object_name, operation_name; + +-- check MV registration metadata +select mv_owner, mv_name from stmv_reg order by mv_owner, mv_name; + +-- do some DMLs +connect sqst/sqst +set serveroutput on +update customer set zip = 0; +update order_line set i_id = 101 where ol_id < 800; +commit; + +-- wait for streams to finish +set timing on +exec verify_tables('orders_v','orders_mv'); +exec verify_tables('oline_v','oline_mv'); +exec verify_tables('customer','customer_mv'); +set timing off + +-- 0 rows expected +select o_id, c_id, ol_num from orders_mv order by o_id; +select ol_id, o_id, i_id from oline_mv order by ol_id; + +update customer set zip = 19555 where c_id > 5; +update order_line set i_id = 61 where ol_id >= 800; +-- update primary key +update order_line set ol_id = 599 where ol_id = 522; +commit; + +-- wait for streams to finish +set timing on +exec verify_tables('orders_v','orders_mv'); +exec verify_tables('oline_v','oline_mv'); +exec verify_tables('customer','customer_mv'); +set timing off + +select o_id, c_id, ol_num from orders_mv order by o_id; +select ol_id, o_id, i_id from oline_mv order by ol_id; + +update customer set zip = -19555 where zip > 19455; +commit; + +-- wait for streams to finish +set timing on +exec verify_tables('orders_v','orders_mv'); +exec verify_tables('oline_v','oline_mv'); +exec verify_tables('customer','customer_mv'); +set timing off + +--0 rows +select o_id, c_id, ol_num from orders_mv order by o_id; +--0 rows +select ol_id, o_id, i_id from oline_mv order by ol_id; + + +update customer set zip = 19556 where zip = -19555; +commit; + +-- wait for streams to finish +set timing on +exec verify_tables('orders_v','orders_mv'); +exec verify_tables('oline_v','oline_mv'); +exec verify_tables('customer','customer_mv'); +set timing off + +select o_id, c_id, ol_num from orders_mv order by o_id; +select ol_id, o_id, i_id from oline_mv order by ol_id; + +delete from order_line where o_id = 71; +delete from orders where c_id = 6; +delete from customer where c_id = 9; +commit; + +-- wait for streams to finish +set timing on +exec verify_tables('orders_v','orders_mv'); +exec verify_tables('oline_v','oline_mv'); +exec verify_tables('customer','customer_mv'); +set timing off + +select o_id, c_id, ol_num from orders_mv order by o_id; +select ol_id, o_id, i_id from oline_mv order by ol_id; + +insert into customer (c_id, zip) values (101, 29555); +insert into orders (o_id, c_id, ol_num) values (1001, 101, 11); +insert into orders (o_id, c_id, ol_num) values (1002, 101, 11); +delete from orders where o_id < 22; +update orders set c_id = 7 where c_id = 5; +update order_line set o_id = 2 where o_id = 82; +commit; + +-- wait for streams to finish +set timing on +exec verify_tables('orders_v','orders_mv'); +exec verify_tables('oline_v','oline_mv'); +exec verify_tables('customer','customer_mv'); +set timing off + +select o_id, c_id, ol_num from orders_mv order by o_id; +select ol_id, o_id, i_id from oline_mv order by ol_id; + +-- Cleanup +connect stradm/stradm + +-- FAIL: apply must be stopped before you can unregister an MV +begin + streams_mv_refresh_adm.unregister_mv( + mv_owner=>'sqst', mv_name=>'"OLINE_MV"', + capture_name=>'CAPTURE', apply_name=>'apply_mv_master'); +end; +/ + +exec dbms_apply_adm.stop_apply('APPLY_MV_MASTER'); + +-- unregister one MV +begin + streams_mv_refresh_adm.unregister_mv( + mv_owner=>'sqst', mv_name=>'"OLINE_MV"', + capture_name=>'CAPTURE', apply_name=>'apply_mv_master'); +end; +/ + +select streams_type, streams_name, table_owner, table_name, + rule_owner, rule_name +from dba_streams_table_rules +where streams_name in ('CAPTURE', 'APPLY_MV_MASTER') +order by streams_type, streams_name, table_owner, table_name; + +select source_object_owner, source_object_name, source_database, + instantiation_scn +from dba_apply_instantiated_objects +where source_object_owner='SQST' +order by source_database, source_object_owner, source_object_name; + +select object_owner, object_name, operation_name, user_procedure +from dba_apply_dml_handlers +where apply_name = 'APPLY_MV_MASTER' +order by object_owner, object_name, operation_name; + +select mv_owner, mv_name from stmv_reg order by mv_owner, mv_name; + +-- unregister the remaining MVs +begin + streams_mv_refresh_adm.unregister_mv( + mv_owner=>'SQST', mv_name=>'ORDERS_MV', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER'); +end; +/ + +begin + streams_mv_refresh_adm.unregister_mv( + mv_owner=>'sqst', mv_name=>'customer_mv', + capture_name=>'capture', apply_name=>'apply_mv_master'); +end; +/ + +select streams_type, streams_name, table_owner, table_name, + rule_owner, rule_name +from dba_streams_table_rules +where streams_name in ('CAPTURE', 'APPLY_MV_MASTER') +order by streams_type, streams_name, table_owner, table_name; + +select source_object_owner, source_object_name, source_database, + instantiation_scn +from dba_apply_instantiated_objects +where source_object_owner='SQST' +order by source_database, source_object_owner, source_object_name; + +select object_owner, object_name, operation_name, user_procedure +from dba_apply_dml_handlers +where apply_name = 'APPLY_MV_MASTER' +order by object_owner, object_name, operation_name; + +select mv_owner, mv_name from stmv_reg order by mv_owner, mv_name; + +-- remove streams configuration +begin + streams_mv_refresh_adm.remove_streams_mv_refresh( + 'CAPTURE', 'apply_mv_master'); +end; +/ + +select 1 from dba_capture where capture_name = 'CAPTURE'; +select 1 from dba_apply where apply_name = 'APPLY_MV_MASTER'; + +select streams_type, streams_name, table_owner, table_name, + rule_owner, rule_name +from dba_streams_table_rules +where streams_name in ('CAPTURE', 'APPLY_MV_MASTER'); + +select source_object_owner, source_object_name, source_database, + instantiation_scn +from dba_apply_instantiated_objects +where source_object_owner='SQST' +order by source_database, source_object_owner, source_object_name; + +select object_owner, object_name, operation_name, user_procedure +from dba_apply_dml_handlers +where apply_name = 'APPLY_MV_MASTER' +order by object_owner, object_name, operation_name; + +-- check mvs +select name, refresh_method, type, refresh_mode +from dba_snapshots where owner = 'SQST' order by name; + +-- cleanup +connect system/manager +drop user stradm cascade; +drop user sqst cascade; diff --git a/strmmv2README.txt b/strmmv2README.txt new file mode 100644 index 0000000..ee51075 --- /dev/null +++ b/strmmv2README.txt @@ -0,0 +1,272 @@ +/ +/ $Header: strmmv2README.txt 08-sep-2006.14:04:06 wesmith Exp $ +/ +/ strmmv2README.txt +/ +/ Copyright (c) 2006, Oracle. All Rights Reserved. +/ +/ NAME +/ strmmv2README.txt - +/ +/ DESCRIPTION +/ +/ +/ NOTES +/ +/ +/ MODIFIED (MM/DD/YY) +/ wesmith 06/23/06 - register_mv: add parameter queue_name +/ wesmith 06/12/06 - corrections +/ wesmith 01/24/06 - Creation +/ + +Streams-driven MV refresh +------------------------- +A set of packages is provided that allows the user to set up an MV for +streams-driven refresh. Whenever a user transaction commits that modifies +the MV's master tables, the MV will be refreshed, either using +dbms_mview.refresh() or a streams-based refresh algorithm. This provides +on-commit MV behavior asynchronously. + +In addition, MV refresh changes may be processed using user-supplied +plsql code. + +Packages: +streams_mv_refresh_adm +streams_mv_refresh +streams_mv_lcr + + +Package streams_mv_refresh_adm +============================== +1. register_mv: sets up an MV for streams-driven refresh + +procedure register_mv(mv_owner varchar2, + mv_name varchar2, + capture_name varchar2 := 'CAPTURE_MV_MASTER', + apply_name varchar2 := 'APPLY_MV_MASTER', + queue_name varchar2 := NULL, + instantiate boolean := FALSE, + use_streams_refresh boolean := FALSE, + mv_dml_handler varchar2 := NULL); + +Parameters +---------- +mv_owner, mv_name: MV to register + +capture_name: + name of the capture process to use. It is recommended to specify a capture + that does not already exist. + +apply_name: + name of the apply process to use. It is recommended to specify an apply + that does not already exist. + +queue_name: + name of the streams queue associated with the capture and apply process. + If NULL, then the queue_name is derived from the capture process + metadata, if it exists. + +instantiate: + if TRUE, then the MV is refreshed (FAST if possible) and + the refresh scn is used for the streams instantiation scn. If FALSE, + then the MV is not refreshed and the current scn is used (the MV is + assumed to be fresh with respect to its dependent master tables.) + +use_streams_refresh: + if TRUE, then streams-based refresh is used (only supported for limited + types of MVs). If FALSE, then the standard MV refresh API is used + (dbms_mview.refresh) + +mv_dml_handler: + if NOT NULL, then the MV is set up for capture/apply and mv_dml_handler + is registered as the dml handler for the MV. This allows MV changes to + be processed in a specific way by the user (ex: for notification to + a middle tier). This parameter is most useful when + use_streams_refresh = FALSE. If use_streams_refresh = TRUE, then there + is a more efficient way for the user to process an MV refresh LCR + (mentioned below.) + + +Description +----------- +This procedure does the following: + - if use_streams_refresh = TRUE, validates that the MV is supported + - if instantiate = TRUE, refreshes the MV and uses the refresh scn as + the instantiation_scn + else uses the current scn as the instantiation scn + - sets up all the MV's master tables for capture/apply + - sets streams_mv_refresh.source_dml_handler() as the dml handler + - set the instantiation_scn + - sets up capture to include rowids + - if mv_dml_handler is NOT NULL: + - sets up the MV for capture/apply + - sets mv_dml_handler as the dml handler for the MV + +Notes +----- +- WARNING: this api should be used only if a separate apply + process was created, otherwise it could effect other applications + (since it may change the dml handler to a table) +- this API assumes that the streams queue used for the capture and + apply process exists in the stream admin's schema +- for use_streams_refresh = TRUE, the default behavior is that + MV refresh LCRs are applied to the MV. If the user wishes to perform + other steps in addition to or in lieu of applying the LCR, they may + modify the procedure streams_mv_lcr.process_lcr(). For example, the + user may send a notification to a middle tier in addition to applying + the LCR to the MV (similar to passing a non-NULL mv_dml_handler) +- table stmv_reg is used to store registration information and + must exist (in the stream admin's schema) + +table stmv_reg: + + mv_owner varchar2(30), /* MV owner */ + mv_name varchar2(30), /* MV name */ + inst_scn number, /* MV instantiation scn */ + use_str_refresh number, /* streams-based refresh ? 1=yes, 0=no */ + mjv number, /* materialized join view? 1=yes, 0=no */ + key_cols stmv_column_list, /* MV key columns */ + select_list varchar2(4000), /* MV select list */ + base_tabs stmv_table_list, /* MV base tables */ + where_clause varchar2(4000) /* MV where clause */ + + +2. unregister_mv: removes an MV from streams-driven refresh + +procedure unregister_mv(mv_owner varchar2, + mv_name varchar2, + capture_name varchar2 := 'CAPTURE_MV_MASTER', + apply_name varchar2 := 'APPLY_MV_MASTER'); + +Parameters +---------- +mv_owner, mv_name: MV to unregister + +capture_name: + name of the capture process to used for streams-driven refresh + +apply_name: + name of the apply process to used for streams-driven refresh + +Description +----------- +This procedure does the following: + - remove all MV dml handlers and table rules, it they exist + - removes dml handlers and table rules for the MV's master tables + if they are not used by an existing registered MV. + - deletes registration metadata for the MV + +Notes +----- +- WARNING: this api should be used only if a separate capture and apply + process was created, otherwise it could effect other applications. +- the apply process must be disabled in order to use this procedure +- table stmv_reg is used to store registration information and + must exist (in the stream admin's schema) + + +3. remove_streams_mv_refresh: removes streams configuration for + streams-driven MV refresh + +procedure remove_streams_mv_refresh( + capture_name varchar2 := 'CAPTURE_MV_MASTER', + apply_name varchar2 := 'APPLY_MV_MASTER'); + + +Parameters +---------- +capture_name: + name of the capture process to used for streams-driven refresh + +apply_name: + name of the apply process to used for streams-driven refresh + +Description +----------- +This procedure does the following: + - stops capture and apply + - remove all dml handlers associated with the apply + - drops capture and apply + - removes the queue and queue table + - removes table instantiation scns, if possible + - deletes any MV registration metadata + + + +package streams_mv_refresh +========================== +1. source_dml_handler: + dml handler used by streams-driven refresh + classic refresh: + if an LCR belongs to a table referenced by MVs registered for + classic refresh, store all such MVs in a package state collection + for commit-time processing. + streams-based refresh: + if an LCR belongs to a table referenced by MVs registered for + streams-based refresh, store the table name, the LCR's dmltype + and rowid in a package state collection for commit-time processing. + +2. source_commit_hdlr: + pre-commit handler used by streams-driven refresh + classic refresh: + submits a job to call dbms_mview.refresh() on all MVs that were collected + in the DML handler + streams-based refresh: + - derives delete and insert deltas based on the information collected + in the DML handler + - creates LCRs from these deltas and calls streams_mv_lcr.process_lcr() + for each LCR. + - for OJ MJVs, special processing for antijoin rows (AJ) + + +package streams_mv_lcr +====================== +1. procedure process_lcr(lcr sys.lcr$_row_record) + +- this procedure applies an LCR to an MV during streams-based refresh + +NOTE: this procedure may be modified by the user to perform + other steps in addition to or in lieu of applying the LCR + + + +Instructions: +- create streams administrator +- create streams-driven refresh supporting objects +- load streams-driven refresh packages +- create streams queue +- call streams_mv_refresh_adm.register_mv() passing a special capture + and apply name +- set applicable apply parameters +- call dbms_apply_adm.alter_apply to assign precommit handler to apply process +- start capture and apply +- call streams_mv_refresh_adm.remove_async_mv_streams() to remove the streams + configuration for async MV refresh. +- to register a new MV or unregister an MV, stop the apply process first + +See the script for a demonstration of this. + + +Restrictions +------------ +- supports single table PK-based MVs or MJVs +- MJVs: + - no UNION ALL + - no inline views +- must be read-only MV +- no on-commit MV +- no objects +- all registered MVs must be registered w/ same capture and apply ! +- no MVs with new column aliasing feature + + +Usage notes +----------- +- MJVs: + - must have a unique index on the MV container table's rowid columns + - call set_key_columns() on the MV container's rowid columns +- MV will be converted to NEVER REFRESH after calling register_mv +- MV logs are not necessary when registering an MV to use streams-based refresh +- all SQL is parsed as the stream admin, so everything in where clause must + be qualified by the owner (at least function calls must be) diff --git a/strmmv2s.sql b/strmmv2s.sql new file mode 100644 index 0000000..2f45fad --- /dev/null +++ b/strmmv2s.sql @@ -0,0 +1,142 @@ +Rem +Rem $Header: strmmv2s.sql 19-jan-2006.16:52:08 wesmith Exp $ +Rem +Rem strmmv2s.sql +Rem +Rem Copyright (c) 2006, Oracle. All rights reserved. +Rem +Rem NAME +Rem strmmv2s.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem wesmith 01/19/06 - Created +Rem + +create table customer ( + c_id number primary key, + zip number, + c_name varchar(30) default NULL /* non-filter column */ +); + +create table orders ( + o_id number primary key, + c_id number, + ol_num number default 0 /* non-filter column */ +); + +create table order_line ( + ol_id number, + o_id number, + i_id number default NULL /* non-filter column */ +); + + +create index c_ind on orders(c_id); +create index oid_ind on order_line(o_id); + +alter table order_line add SUPPLEMENTAL LOG DATA (ALL) columns; +alter table orders add SUPPLEMENTAL LOG DATA (ALL) columns; +alter table customer add SUPPLEMENTAL LOG DATA (ALL) columns; + +create table sales (region varchar2(10), amt number); +alter table sales add SUPPLEMENTAL LOG DATA (ALL) columns; + +-- This sleep is needed to as the min flashback window should be >= 3 seconds +exec dbms_lock.sleep(10); + +set echo off +Rem -------------------------------------------------------. +Rem Insert rows into the master tables(2-1 fanout) which are +Rem not part of the snapshot definitions. The pk columns of +Rem these rows start with digits between 0-4 +Rem -------------------------------------------------------. +insert into customer (c_id, zip) values (0, 1); +insert into customer (c_id, zip) values (1, 1); +insert into customer (c_id, zip) values (2, 1); +insert into customer (c_id, zip) values (3, 1); +insert into customer (c_id, zip) values (4, 1); + +insert into orders (o_id, c_id) values (01, 0); +insert into orders (o_id, c_id) values (02, 0); +insert into orders (o_id, c_id) values (11, 1); +insert into orders (o_id, c_id) values (12, 1); +insert into orders (o_id, c_id) values (21, 2); +insert into orders (o_id, c_id) values (22, 2); +insert into orders (o_id, c_id) values (31, 3); +insert into orders (o_id, c_id) values (32, 3); +insert into orders (o_id, c_id) values (41, 4); +insert into orders (o_id, c_id) values (42, 4); + +insert into order_line (ol_id, o_id) values (011, 01); +insert into order_line (ol_id, o_id) values (012, 01); +insert into order_line (ol_id, o_id) values (021, 02); +insert into order_line (ol_id, o_id) values (022, 02); +insert into order_line (ol_id, o_id) values (111, 11); +insert into order_line (ol_id, o_id) values (112, 11); +insert into order_line (ol_id, o_id) values (121, 12); +insert into order_line (ol_id, o_id) values (122, 12); +insert into order_line (ol_id, o_id) values (211, 21); +insert into order_line (ol_id, o_id) values (212, 21); +insert into order_line (ol_id, o_id) values (221, 22); +insert into order_line (ol_id, o_id) values (222, 22); +insert into order_line (ol_id, o_id) values (311, 31); +insert into order_line (ol_id, o_id) values (312, 31); +insert into order_line (ol_id, o_id) values (321, 32); +insert into order_line (ol_id, o_id) values (322, 32); +insert into order_line (ol_id, o_id) values (411, 41); +insert into order_line (ol_id, o_id) values (412, 41); +insert into order_line (ol_id, o_id) values (421, 42); +insert into order_line (ol_id, o_id) values (422, 42); + +Rem -------------------------------------------------------. +Rem Insert rows into the master tables(2-1 fanout) which +Rem are a part of the snapshot definition. The pk columns +Rem of these rows start with digits between 5-9 +Rem -------------------------------------------------------. +insert into customer (c_id, zip) values (5, 19555); +insert into customer (c_id, zip) values (6, 19555); +insert into customer (c_id, zip) values (7, 19555); +insert into customer (c_id, zip) values (8, 19555); +insert into customer (c_id, zip) values (9, 19555); + +insert into orders (o_id, c_id) values (51, 5); +insert into orders (o_id, c_id) values (52, 5); +insert into orders (o_id, c_id) values (61, 6); +insert into orders (o_id, c_id) values (62, 6); +insert into orders (o_id, c_id) values (71, 7); +insert into orders (o_id, c_id) values (72, 7); +insert into orders (o_id, c_id) values (81, 8); +insert into orders (o_id, c_id) values (82, 8); +insert into orders (o_id, c_id) values (91, 9); +insert into orders (o_id, c_id) values (92, 9); + +insert into order_line (ol_id, o_id) values (511, 51); +insert into order_line (ol_id, o_id) values (512, 51); +insert into order_line (ol_id, o_id) values (521, 52); +insert into order_line (ol_id, o_id) values (522, 52); +insert into order_line (ol_id, o_id) values (611, 61); +insert into order_line (ol_id, o_id) values (612, 61); +insert into order_line (ol_id, o_id) values (621, 62); +insert into order_line (ol_id, o_id) values (622, 62); +insert into order_line (ol_id, o_id) values (711, 71); +insert into order_line (ol_id, o_id) values (712, 71); +insert into order_line (ol_id, o_id) values (721, 72); +insert into order_line (ol_id, o_id) values (722, 72); +insert into order_line (ol_id, o_id) values (811, 81); +insert into order_line (ol_id, o_id) values (812, 81); +insert into order_line (ol_id, o_id) values (821, 82); +insert into order_line (ol_id, o_id) values (822, 82); +insert into order_line (ol_id, o_id) values (911, 91); +insert into order_line (ol_id, o_id) values (912, 91); +insert into order_line (ol_id, o_id) values (921, 92); +insert into order_line (ol_id, o_id) values (922, 92); +commit; + +insert into sales values ('West', null); +commit; diff --git a/strmmvp1.sql b/strmmvp1.sql new file mode 100644 index 0000000..81cd054 --- /dev/null +++ b/strmmvp1.sql @@ -0,0 +1,607 @@ +Rem +Rem $Header: strmmvp1.sql 29-jan-2007.10:31:25 davzhang Exp $ +Rem +Rem strmmvp1.sql +Rem +Rem Copyright (c) 2006, 2007, Oracle. All rights reserved. +Rem +Rem NAME +Rem strmmvp1.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem davzhang 01/29/07 - increase max_time for verify_table_rules +Rem wesmith 03/28/06 - Created +Rem + +create or replace package async_mv_pkg AUTHID CURRENT_USER as + type name_arr is table of varchar2(30); + type mycurtyp IS REF cursor; + + -- collection of table owners + tab_owners name_arr := name_arr(); + -- collection of table names + tab_names name_arr := name_arr(); + + -- sets up streams, if necessary, for all tables with MV logs + procedure register_tables (capture_name varchar2, apply_name varchar2); + + -- removes streams, if necessary, for all tables that no longer have MV logs + procedure unregister_tables (capture_name varchar2, apply_name varchar2); + + -- removes ASYNC_MV streams configuration + procedure remove_async_mv_streams(capture_name varchar2, + apply_name varchar2); + + -- apply DML handler + procedure async_mv_dml_hdlr(in_any IN ANYDATA); + + -- apply pre-commit handler + procedure async_mv_commit_hdlr(commit_scn number); + + -- calls dbms_mview.refresh_dependent() if required + procedure refresh_dependent(tab_owners name_arr, + tab_names name_arr, commit_scn number); +end; +/ + +create or replace package body async_mv_pkg as + +-- Sets up streams for all tables with MV logs +-- Does the following: +-- set table instatiation scn +-- add apply rule +-- assign dml handler for insert/update/delete +-- add capture rule +procedure register_tables (capture_name varchar2, apply_name varchar2) is + + owner_name varchar2(80); -- table_owner.table_name + inst_scn number; -- instantiation SCN + db varchar2(128); + cnt pls_integer := 0; + + -- tables with MV logs that are not set up for streams + mycur mycurtyp; + need_reg varchar2(10000) := + 'select log_owner tabown, master tabname ' || + 'from dba_mview_logs ' || + 'minus ' || + 'select table_owner tabown, table_name tabname ' || + 'from dba_streams_table_rules ' || + 'where streams_type = ''APPLY'' ' || + 'and streams_name = :apply_name'; + tabowner varchar2(30); + tabname varchar2(30); + + +begin + select global_name into db from global_name; + + open mycur for need_reg using apply_name; + + -- set up streams for all tables needing registration + loop + FETCH mycur INTO tabowner, tabname; + EXIT WHEN mycur%NOTFOUND; -- exit loop when last row is fetched + + -- construct ""."" + owner_name := '"' || tabowner || '"."' || tabname || '"'; + + inst_scn := dbms_flashback.get_system_change_number(); + + -- if table already has an instantiation scn registered, don't call + -- dbms_apply_adm.set_table_instantiation_scn() + select count(*) into cnt + from dba_apply_instantiated_objects + where source_object_owner = tabowner + and source_object_name = tabname + and source_object_type = 'TABLE' + and source_database = db; + + if (cnt = 0) then + dbms_apply_adm.set_table_instantiation_scn( + source_object_name => owner_name, + source_database_name => db, + instantiation_scn => inst_scn); + end if; + + -- add apply rule + dbms_streams_adm.add_table_rules( + table_name => owner_name, + streams_type => 'apply', + streams_name => apply_name, + queue_name => 'stradm.ASYNC_MV_Q', + include_tagged_lcr => true, + include_dml => true, + include_ddl => false, + source_database => db); + + dbms_apply_adm.set_dml_handler( + object_name => owner_name, + object_type => 'TABLE', + operation_name => 'DEFAULT', + error_handler => false, + user_procedure => 'stradm.async_mv_pkg.async_mv_dml_hdlr', + apply_database_link => NULL, + apply_name => apply_name); + + -- add capture rule + dbms_streams_adm.add_table_rules( + table_name => owner_name, + streams_type => 'capture', + streams_name => capture_name, + queue_name => 'stradm.ASYNC_MV_Q', + include_tagged_lcr => true, + include_dml => true, + include_ddl => false, + inclusion_rule => true); + + end loop; + close mycur; + +exception when others then + if mycur%isopen then + close mycur; + end if; + raise; +end; + +-- Removes streams for all tables no longer having MV logs +-- For each table, it does the following: +-- removes dml handler for insert/update/delete +-- remove capture rule +-- remove apply rule +procedure unregister_tables (capture_name varchar2, apply_name varchar2) is + owner_name varchar2(80); + inst_scn number; + db varchar2(128); + + mycur mycurtyp; --- declare cursor variable + tabowner varchar2(30); + tabname varchar2(30); + rowner varchar2(30); + rname varchar2(30); + strtype varchar2(11); + strname varchar2(30); + + -- tables set up for streams that no longer have MV logs + need_unreg varchar2(10000) := + 'select table_owner tabowner, table_name tabname ' || + 'from dba_streams_table_rules str ' || + 'where streams_type = ''APPLY'' ' || + 'and streams_name = :apply_name ' || + 'minus ' || + 'select log_owner tabowner, master tabname ' || + 'from dba_mview_logs'; + + -- corresponding capture/apply rules to remove for the tables + -- in the cursor need_unreg + remove_rules varchar2(10000) := + 'select streams_name, streams_type, rule_owner, rule_name ' || + 'from dba_streams_table_rules str ' || + 'where ((streams_type = ''CAPTURE'' and streams_name = :capture_name ) ' || + ' OR ' || + ' (streams_type = ''APPLY'' and streams_name = :apply_name )) ' || + 'and not exists ' || + '(select 1 from dba_mview_logs mvl ' || + ' where str.table_owner = mvl.log_owner ' || + ' and str.table_name = mvl.master)'; + +begin + select global_name into db from global_name; + + open mycur for need_unreg using apply_name; + + loop + FETCH mycur INTO tabowner, tabname; + EXIT WHEN mycur%NOTFOUND; -- exit loop when last row is fetched + + -- construct ""."" + owner_name := '"' || tabowner || '"."' || tabname || '"'; + + dbms_apply_adm.set_dml_handler( + object_name => owner_name, + object_type => 'TABLE', + operation_name => 'DEFAULT', + error_handler => false, + user_procedure => NULL, + apply_database_link => NULL, + apply_name => apply_name); + + end loop; + close mycur; + + open mycur for remove_rules using capture_name, apply_name; + loop + FETCH mycur INTO strname, strtype, rowner, rname; + EXIT WHEN mycur%NOTFOUND; -- exit loop when last row is fetched + + -- construct ""."" + owner_name := '"' || rowner || '"."' || rname || '"'; + + dbms_streams_adm.remove_rule( + rule_name => owner_name, + streams_type => strtype, + streams_name => strname); + end loop; + close mycur; + +exception when others then + if mycur%isopen then + close mycur; + end if; + raise; +end; + +-- removes ASYNC_MV streams configuration +procedure remove_async_mv_streams(capture_name varchar2, + apply_name varchar2) is + + owner_name varchar2(80); + inst_scn number; + db varchar2(128); + cnt pls_integer := 0; + + -- selects tables set up for ASYNC_MV apply + cursor apply_tables(apply_name varchar2) is + select table_owner, table_name + from dba_streams_table_rules + where streams_type = 'APPLY' + and streams_name = apply_name; + + cursor instantiated_objects is + select source_object_owner table_owner, source_object_name table_name + from dba_apply_instantiated_objects + where SOURCE_OBJECT_TYPE = 'TABLE'; + +begin + select global_name into db from global_name; + + -- stop capture and apply + dbms_capture_adm.stop_capture(capture_name); + dbms_apply_adm.stop_apply(apply_name); + + for rec in apply_tables(apply_name) loop + -- construct ""."" + owner_name := '"' || rec.table_owner || '"."' || rec.table_name || '"'; + + -- remove dml handlers + dbms_apply_adm.set_dml_handler( + object_name => owner_name, + object_type => 'TABLE', + operation_name => 'DEFAULT', + error_handler => false, + user_procedure => NULL, + apply_database_link => NULL, + apply_name => apply_name); + + end loop; + + -- remove capture and apply + dbms_apply_adm.drop_apply(apply_name, true); + dbms_capture_adm.drop_capture(capture_name, true); + + -- remove queues + dbms_streams_adm.remove_queue('ASYNC_MV_Q'); + + -- if there are no apply processes left, remove any dangling + -- table instantiation scns + select count(*) into cnt + from dba_apply; + + if (cnt = 0) then + for rec in instantiated_objects loop + -- construct ""."" + owner_name := '"' || rec.table_owner || '"."' || rec.table_name || '"'; + + dbms_apply_adm.set_table_instantiation_scn( + source_object_name => owner_name, + source_database_name => db, + instantiation_scn => null); + end loop; + else + -- other apply processes exist, so print a message to the caller + dbms_output.put_line('NOTE: Other apply processes exist so '|| + 'table instantiation scns were not removed.'); + dbms_output.put_line('To remove them, call ' || + 'dbms_apply_adm.set_table_instantiation_scn'); + dbms_output.put_line('Example:'); + dbms_output.put_line(' dbms_apply_adm.set_table_instantiation_scn('); + dbms_output.put_line(' source_object_name => ''tabowner.foo'','); + dbms_output.put_line(' source_database_name => db,'); + dbms_output.put_line(' instantiation_scn => null);'); + end if; + +end; + +-- apply DML handler +procedure async_mv_dml_hdlr(in_any IN ANYDATA) is + lcr SYS.LCR$_ROW_RECORD; + rc PLS_INTEGER; + tab_owner varchar2(30); + tab_name varchar2(30); + next_pos pls_integer; + source_db varchar2(128); +begin + -- get LCR info + rc := in_any.getobject(lcr); + tab_owner := lcr.get_object_owner(); + tab_name := lcr.get_object_name(); + source_db := lcr.get_source_database_name(); + + -- see if name already exists in table cache + if (async_mv_pkg.tab_owners.count > 0) then + for i in async_mv_pkg.tab_owners.first..async_mv_pkg.tab_owners.last loop + if (tab_owner = async_mv_pkg.tab_owners(i) and + tab_name = async_mv_pkg.tab_names(i)) then + return; -- found entry, done + end if; + end loop; + end if; + + -- new table: add to pkg state cache + if (async_mv_pkg.tab_owners.count = 0) then + next_pos := 1; + else + next_pos := async_mv_pkg.tab_owners.last + 1; + end if; + + async_mv_pkg.tab_owners.extend; + async_mv_pkg.tab_owners(next_pos) := tab_owner; + async_mv_pkg.tab_names.extend; + async_mv_pkg.tab_names(next_pos) := tab_name; + +end; + +-- +-- autonmous block to create a scheduler job (this api commits) +-- +procedure create_scheduler_job(str varchar2) is + pragma autonomous_transaction; +begin + -- submit the refresh job + dbms_scheduler.create_job( + job_name => dbms_scheduler.generate_job_name, + job_type => 'PLSQL_BLOCK', + job_action => str, + start_date => sysdate, + enabled => TRUE); +end; + +-- pre-commit handler +procedure async_mv_commit_hdlr(commit_scn number) is + l_jobnum number; + str varchar2(10000); + ownerlist varchar2(10000); + namelist varchar2(10000); +begin + + -- no table to process, done + if (async_mv_pkg.tab_owners.count = 0) then + return; + end if; + + -- create comma-separated list of table owners and table names + for i in async_mv_pkg.tab_owners.first..async_mv_pkg.tab_owners.last loop + if (i > async_mv_pkg.tab_owners.first) then + ownerlist := ownerlist || ','; + namelist := namelist || ','; + end if; + ownerlist := ownerlist || '''' || async_mv_pkg.tab_owners(i) || ''''; + namelist := namelist || '''' || async_mv_pkg.tab_names(i) || ''''; + end loop; + + -- submit a stradm.async_mv_pkg.refresh_dependent() job + str := + 'begin ' || + 'stradm.async_mv_pkg.refresh_dependent(' || + 'async_mv_pkg.name_arr(' || ownerlist || '), ' || + 'async_mv_pkg.name_arr(' || namelist || '), ' || + commit_scn || '); ' || + 'end;'; + + create_scheduler_job(str); + + -- reset tab_owners, tab_names collections + async_mv_pkg.tab_owners.delete; + async_mv_pkg.tab_names.delete; +end; + +-- Given a collection of tables, this determines the minimal set of +-- tables to pass to dbms_mview.refresh_dependent() +-- by comparing the commit scn of a transaction with the minimum +-- refresh scns of all MVs dependent on the tables. +procedure refresh_dependent(tab_owners name_arr, tab_names name_arr, + commit_scn number) is + min_refscn number; + tablist varchar2(10000); + is_first boolean := TRUE; + num_fail number :=0; +begin + + -- construct comma-separated list of table names, + -- skipping tables if dependent MVs do not need refreshing + for i in tab_owners.first..tab_owners.last loop + begin + select oldest_refresh_scn into min_refscn + from all_refresh_dependencies + where owner = tab_owners(i) + and table_name = tab_names(i); + + if commit_scn >= min_refscn then + -- add table to the list + if not is_first then + tablist := tablist || ','; + end if; + tablist := tablist || + '"' || tab_owners(i) || '"."' || tab_names(i) || '"'; + is_first := FALSE; + end if; + + exception when no_data_found then + null; + end; + end loop; + + -- do the refresh + if tablist is not null then + dbms_mview.refresh_dependent(number_of_failures => num_fail, + list => tablist, + refresh_after_errors => TRUE, + atomic_refresh => FALSE, + nested => TRUE); + end if; +end; + +end async_mv_pkg; +/ + +-- Procedure for verifying results +create or replace procedure verify_tables(tab1 in varchar2, + tab2 in varchar2, + max_time in integer default 3600) + authid current_user as + + tab2_sql varchar2(1000); + tab1_sql varchar2(1000); + diff_sql varchar2(1000); + cur integer; + ret integer; + num_rows integer; + slept integer := 0; + wait_for_convergence boolean := true; + +begin + dbms_output.enable ( 10000 ) ; + + tab1_sql := 'select * from ' || tab1; + + tab2_sql := 'select * from ' || tab2; + +-- diff_sql is the query that should return 0 rows if the snapshot rows +-- have converged + diff_sql := '(' || + tab1_sql || + ' minus ' || + tab2_sql || + ')' || + ' union ' || + '(' || + tab2_sql || + ' minus ' || + tab1_sql || + ')' ; + + +-- get the no. of rows returned by diff_sql. + cur := dbms_sql.open_cursor; + dbms_sql.parse(cur, + 'select count(*) from ( ' || diff_sql || ' )', dbms_sql.v7); + sys.dbms_sql.define_column(cur, 1, num_rows); + begin + ret := dbms_sql.execute_and_fetch(cur); + dbms_sql.column_value(cur,1,num_rows); + exception when others then + if dbms_sql.is_open(cur) then + dbms_sql.close_cursor(cur); + end if; + dbms_output.put_line ('-- error while counting rows in diff_sql'); + raise; + end; + +while (wait_for_convergence) loop + ret := dbms_sql.execute_and_fetch(cur); + dbms_sql.column_value(cur,1,num_rows); + +-- begin num_rows if + if num_rows = 0 then + dbms_output.put_line( + '---------------------------------------------------------------------------' + ); + dbms_output.put_line('-- Tables/views '||tab1 ||' and '||tab2 || ' are identical'); + dbms_output.put_line( + '---------------------------------------------------------------------------' + ); + wait_for_convergence := false; + else + dbms_lock.sleep(3); + slept := slept + 3; + if (slept >= max_time ) then + dbms_output.put_line( + '---------------------------------------------------------------------------' + ); + dbms_output.put_line('-- WARNING: maximum wait time of '|| slept ||' seconds exceeded'); + dbms_output.put_line('-- Tables/views '||tab1 ||' and '||tab2 || ' are NOT identical'); + dbms_output.put_line('-- Check trace files to determine what is going wrong'); + dbms_output.put_line( + '---------------------------------------------------------------------------' + ); + wait_for_convergence := false; + end if; + end if; +end loop; + dbms_sql.close_cursor(cur); + +end; +/ + +create or replace public synonym verify_tables for verify_tables; +grant execute on verify_tables to public; + +-- verifies that a table's rules have been added or removed +-- if check_exists = TRUE, it waits until the rules exist +-- else if FALSE, it waits until the rules no longer exist +create or replace procedure verify_table_rules(towner varchar2, + tname varchar2, + check_exists boolean, + max_time pls_integer := 600) +is + sleep_total pls_integer := 0; + cnt1 pls_integer; + cnt2 pls_integer; + done boolean := false; +begin + + while (not done) loop + select count(*) into cnt1 + from dba_streams_table_rules + where streams_name = 'CAPTURE_MV' + and table_owner = towner + and table_name = tname; + + select count(*) into cnt2 + from dba_streams_table_rules + where streams_name = 'APPLY_MV' + and table_owner = towner + and table_name = tname; + + if (check_exists) then + -- check if table is set up for capture/apply + if (cnt1 > 0 and cnt2 > 0) then + exit; + end if; + else + -- check if table is not set up for capture/apply + if (cnt1 = 0 and cnt2 = 0) then + exit; + end if; + end if; + + -- try again after 3 seconds + dbms_lock.sleep(3); + sleep_total := sleep_total + 3; + if (sleep_total >= max_time ) then + dbms_output.put_line('-- Tables rules are NOT verified'); + end if; + end loop; + dbms_output.put_line('-- Tables rules are verified'); +end; +/ + +create or replace public synonym verify_table_rules for verify_table_rules; +grant execute on verify_table_rules to public; diff --git a/strmmvp2.sql b/strmmvp2.sql new file mode 100644 index 0000000..5665a87 --- /dev/null +++ b/strmmvp2.sql @@ -0,0 +1,2267 @@ +Rem +Rem $Header: strmmvp2.sql 23-jun-2006.13:43:59 wesmith Exp $ +Rem +Rem strmmvp2.sql +Rem +Rem Copyright (c) 2006, Oracle. All rights reserved. +Rem +Rem NAME +Rem strmmvp2.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem wesmith 06/23/06 - register_mv: add parameter queue_name +Rem wesmith 06/12/06 - LRG 2247322: remove insert append hint +Rem wesmith 01/19/06 - Created +Rem + +---------------------- +-- supporting objects +---------------------- +create or replace type stmv_num_list is table of number +/ +create or replace type stmv_name_list is table of varchar2(30) +/ +create or replace type stmv_anydata_list is table of anydata +/ +create or replace type stmv_column_list is table of varchar2(30) +/ + +-- master table metadata +create or replace type stmv_table_t as object ( + table_owner varchar2(30), + table_name varchar2(30), + table_alias varchar2(30), + key_cols stmv_column_list +) +/ +create or replace type stmv_table_list is table of stmv_table_t +/ + +-- MV metadata +create or replace type stmv_mv_t as object ( + mv_owner varchar2(30), /* MV owner */ + mv_name varchar2(30), /* MV name */ + inst_scn number, /* MV instantiation scn */ + use_str_refresh number, /* streams-based refresh ? 1=yes, 0=no */ + mjv number, /* obsolete */ + flags number, /* MV properties */ + key_cols stmv_column_list, /* MV key columns */ + select_list varchar2(4000), /* MV select list */ + base_tabs stmv_table_list, /* MV base tables */ + where_clause varchar2(4000) /* MV where clause */ +) +/ +create or replace type stmv_mvs_t is table of stmv_mv_t +/ + +-- store streams MV metadata +create table stmv_reg of stmv_mv_t (primary key(mv_owner, mv_name)) + nested table key_cols store as stmv_mv_keycol_st + nested table base_tabs store as stmv_tab_st + (nested table key_cols store as stmv_tab_keycol_st); + +-- temp table to store rowids for a transaction +create global temporary table stmv_rid +(table_owner varchar2(30), + table_name varchar2(30), + dml_type number, + rid rowid +) +on commit delete rows; + +create index rid_i1 on stmv_rid(table_owner, table_name, dml_type); + + +------------ +-- packages +------------ +create or replace package streams_mv_refresh_adm AUTHID CURRENT_USER as + type mycurtyp IS REF cursor; + reg_mvs stmv_mvs_t := stmv_mvs_t(); + + -- constants + source_dbname constant varchar2(256) := dbms_standard.database_name; + + -- constants for flags + flg_mjv constant pls_integer := 1; + flg_hasoj constant pls_integer := 2; + + -- returns primary key columns for a table + function get_pkcols(tabowner in varchar2, tabname in varchar2) + return stmv_column_list; + + -- returns key columns for a table + -- (PK or from the api dbms_apply_adm.set_key_columns) + function get_keycols(tabowner in varchar2, tabname in varchar2) + return stmv_column_list; + + -- sets up an MV for streams-driven refresh + procedure register_mv(mv_owner varchar2, + mv_name varchar2, + capture_name varchar2 := 'CAPTURE_MV_MASTER', + apply_name varchar2 := 'APPLY_MV_MASTER', + queue_name varchar2 := NULL, + instantiate boolean := FALSE, + use_streams_refresh boolean := FALSE, + mv_dml_handler varchar2 := NULL); + + -- removes an MV from streams-driven refresh + procedure unregister_mv(mv_owner varchar2, + mv_name varchar2, + capture_name varchar2 := 'CAPTURE_MV_MASTER', + apply_name varchar2 := 'APPLY_MV_MASTER'); + + -- removes streams configuration for streams-driven MV refresh + procedure remove_streams_mv_refresh( + capture_name varchar2 := 'CAPTURE_MV_MASTER', + apply_name varchar2 := 'APPLY_MV_MASTER'); + +end streams_mv_refresh_adm; +/ + + +create or replace package streams_mv_refresh AUTHID CURRENT_USER as + type rowid_list is table of varchar2(18); + type txn_tab_t is record ( + table_owner varchar2(30), + table_name varchar2(30), + dmltypes pls_integer, + delete_rowids rowid_list, + insert_rowids rowid_list + ); + type txn_tab_list is table of txn_tab_t; + + -- collection of MV owners, names + txn_mvs txn_tab_list := txn_tab_list(); + + -- collection of table owners, names + txn_tabs txn_tab_list := txn_tab_list(); + + -- dml types + insert_dml constant pls_integer := 1; + update_dml constant pls_integer := 2; + delete_dml constant pls_integer := 4; + + rowid_col constant varchar2(5) := 'ROWID'; + scn_bind constant varchar2(5) := 'SCN'; + rowid_bind constant varchar2(5) := 'RID'; + + -- dml handler used by streams-driven refresh + procedure source_dml_handler(lcr_anydata in sys.anydata); + + -- pre-commit handler used by streams-driven refresh + procedure source_commit_hdlr(commit_scn number); + + procedure add_to_table_coll(tab_owner IN varchar2, + tab_name IN varchar2, + tab_dmltype IN pls_integer, + tab_rowid IN urowid, + tab_coll IN OUT NOCOPY txn_tab_list); + + procedure define_columns(sql_cursor pls_integer, + num_cols pls_integer, + desc_table sys.dbms_sql.desc_tab); + + procedure get_column_values(sql_cursor pls_integer, + num_cols pls_integer, + desc_table sys.dbms_sql.desc_tab, + is_key_col stmv_num_list, + lcr in out nocopy sys.lcr$_row_record, + cmd_type varchar2, + first_time boolean); + + procedure print_trace(mesg varchar2); + +end streams_mv_refresh; +/ + + +create or replace package streams_mv_lcr AUTHID CURRENT_USER as + -- applies an LCR to an MV during streams-based refresh + procedure process_lcr(lcr sys.lcr$_row_record); + + procedure print_lcr_cols(cols sys.lcr$_row_list); + procedure do_an_insert(lcr sys.lcr$_row_record); +end streams_mv_lcr; +/ + + +create or replace package body streams_mv_refresh_adm as + cursor mv_group is select sys_nc_rowinfo$ from stmv_reg; + +-- +-- returns primary key columns for a table, if they exist +-- +function get_pkcols(tabowner in varchar2, tabname in varchar2) + return stmv_column_list is + + pk_columns stmv_column_list := stmv_column_list(); + pkcol_array dbms_utility.uncl_array; -- 1-based plsql table + pk_name varchar2(30); + pk_type pls_integer; + pk_cols varchar2(32000); + pk_idx_name varchar2(30); + idx_cols varchar2(32000); + dummy pls_integer; + canon_pkcol varchar2(30); + +begin + streams_mv_refresh.print_trace('get_pkcols()+'); + + -- get pk cols as comma-separated list + sys.dbms_snapshot_utl.get_pk_constraint_info( + tabowner, tabname, pk_name, pk_type, pk_cols, pk_idx_name, idx_cols); + + if (pk_cols is null) then + return pk_columns; + end if; + + -- convert comma-separated list to collection + dbms_utility.comma_to_table(rtrim(pk_cols, ','), dummy, pkcol_array); + + -- move collection to collection of type stmv_column_list + for i in 1 .. pkcol_array.last loop + exit when pkcol_array(i) is null; + -- strip double quotes in pkcol_array(i) + dbms_utility.canonicalize(pkcol_array(i), canon_pkcol, 30); + pk_columns.extend; + pk_columns(pk_columns.last) := canon_pkcol; + end loop; + + streams_mv_refresh.print_trace('get_pkcols()-'); + return pk_columns; +end; + + +-- +-- get a table's key columns (PK or via api dbms_apply_adm.set_key_columns) +-- +function get_keycols(tabowner in varchar2, tabname in varchar2) + return stmv_column_list is + + key_cols stmv_column_list := stmv_column_list(); + + cursor key_columns(table_owner varchar2, table_name varchar2) is + select column_name + from dba_apply_key_columns + where object_owner = table_owner + and object_name = table_name + and apply_database_link is null; + +begin + streams_mv_refresh.print_trace('get_keycols()+'); + + -- first, see if the table has a PK constraint + key_cols := get_pkcols(tabowner, tabname); + + if (key_cols.count = 0) then + -- no PK, try and see if there are key columns defined + -- (via dbms_apply_adm.set_key_columns) + for rec in key_columns(tabowner, tabname) loop + key_cols.extend; + key_cols(key_cols.last) := rec.column_name; + end loop; + end if; + + streams_mv_refresh.print_trace('get_keycols()-'); + return key_cols; +end; + +-- +-- register an MV for streams-driven refresh +-- +procedure register_mv(mv_owner varchar2, + mv_name varchar2, + capture_name varchar2 := 'CAPTURE_MV_MASTER', + apply_name varchar2 := 'APPLY_MV_MASTER', + queue_name varchar2 := NULL, + instantiate boolean := FALSE, + use_streams_refresh boolean := FALSE, + mv_dml_handler varchar2 := NULL) is + + mycur mycurtyp; + mvinfo stmv_mv_t; + str_refresh pls_integer; + flags pls_integer := 0; + can_use_log varchar2(3); + updatable varchar2(3); + ref_method varchar2(15); -- rowid, pk, etc. + ref_type varchar2(10); -- complete, fast, never, etc. + ref_mode varchar2(10); -- demand, commit, never + mv_query varchar2(32000); + mastabs pls_integer; -- # master tables + has_obj pls_integer; -- MV with objects ? 1=yes, 0=no + has_oj pls_integer; -- MV with outer joins ? 1=yes, 0=no + cnt pls_integer; + select_pos pls_integer := 0; + select_start pls_integer := 0; + from_pos pls_integer := 0; + where_pos pls_integer := 0; + where_start pls_integer := 0; + tabowner varchar2(30); + tabname varchar2(30); + tabalias varchar2(30); + owner_name varchar2(80); -- table_owner.table_name + inst_scn number; -- instantiation SCN + tablist stmv_table_list := stmv_table_list(); + canon_mv_owner varchar2(30); + canon_mv_name varchar2(30); + canon_capture varchar2(30); + canon_apply varchar2(30); + canon_queue varchar2(30); + canon_hdlr varchar2(98); + key_cols stmv_column_list; + + -- MV metadata + check_mv varchar2(32000) := +'select refresh_method, can_use_log, updatable, type, refresh_mode, query + from dba_snapshots + where owner = :mv_owner + and name = :mv_name'; + + check_mv2 varchar2(32000) := +'select mastabs, decode(bitand(flag, 268435456), 0, 0, 1) has_obj, + decode(bitand(flag2, 256), 0, 0, 1) has_oj + from sys.exu9snap + where owner = :mv_owner + and name =:mv_name'; + + -- MV last refresh scn + get_refscn varchar2(32000) := +'select rscn + from sys.exu9snap + where owner = :mv_owner + and name =:mv_name'; + + -- MV master tables + mv_master_tables varchar2(32000) := +'select detail_owner, detail_relation, detail_alias + from dba_summary_detail_tables + where owner = :mv_owner + and summary_name = :mv_name'; + +begin + -- print param values + streams_mv_refresh.print_trace('register_mv()+'); + streams_mv_refresh.print_trace('mv_owner='||mv_owner); + streams_mv_refresh.print_trace('mv_name='||mv_name); + streams_mv_refresh.print_trace('capture_name='||capture_name); + streams_mv_refresh.print_trace('apply_name='||apply_name); + streams_mv_refresh.print_trace('queue_name='||queue_name); + if (instantiate) then + streams_mv_refresh.print_trace('instantiate=TRUE'); + else + streams_mv_refresh.print_trace('instantiate=FALSE'); + end if; + if (use_streams_refresh) then + streams_mv_refresh.print_trace('use_streams_refresh=TRUE'); + else + streams_mv_refresh.print_trace('use_streams_refresh=FALSE'); + end if; + streams_mv_refresh.print_trace('mv_dml_handler='||mv_dml_handler); + + -- canonicalize inputs + dbms_utility.canonicalize(mv_owner, canon_mv_owner, 30); + dbms_utility.canonicalize(mv_name, canon_mv_name, 30); + dbms_utility.canonicalize(capture_name, canon_capture, 30); + dbms_utility.canonicalize(apply_name, canon_apply, 30); + dbms_utility.canonicalize(queue_name, canon_queue, 30); + dbms_utility.canonicalize(mv_dml_handler, canon_hdlr, 30); + + -- make sure the apply process is down + select count(*) into cnt from dba_apply + where apply_name = canon_apply + and status = 'ENABLED'; + if (cnt > 0) then + raise_application_error(-20000, + 'Apply process must be disabled'); + end if; + + -- get queue_name from capture and apply process views if NULL + if (canon_queue is NULL) then + declare + apply_queue varchar2(30); + capture_queue varchar2(30); + begin + -- get queue for capture and apply + select queue_name into capture_queue + from dba_capture + where capture_name = canon_capture; + + select queue_name into apply_queue + from dba_apply + where apply_name = canon_apply; + + -- capture and apply must share the same queue + if apply_queue != capture_queue then + raise_application_error(-20000, + 'capture and apply must share the same queue'); + end if; + + canon_queue := capture_queue; + + exception + when NO_DATA_FOUND then + raise_application_error(-20000, 'must specify queue_name'); + end; + end if; + + -- + -- get MV metadata + -- + begin + execute immediate check_mv + into ref_method, can_use_log, updatable, ref_type, ref_mode, mv_query + using canon_mv_owner, canon_mv_name; + + execute immediate check_mv2 + into mastabs, has_obj, has_oj + using canon_mv_owner, canon_mv_name; + exception + when NO_DATA_FOUND then + raise_application_error(-20000, 'MV does not exist'); + end; + + streams_mv_refresh.print_trace('ref_method='||ref_method); + streams_mv_refresh.print_trace('can_use_log='||can_use_log); + streams_mv_refresh.print_trace('updatable='||updatable); + streams_mv_refresh.print_trace('ref_type='||ref_type); + streams_mv_refresh.print_trace('ref_mode='||ref_mode); + streams_mv_refresh.print_trace('mastabs='||mastabs); + streams_mv_refresh.print_trace('has_obj='||has_obj); + + -- for streams-based refresh, validate the MV + if (use_streams_refresh = TRUE) then + if (can_use_log = 'NO' or -- not fast refreshable + updatable = 'YES' or -- updatable MV + ref_mode = 'COMMIT' or -- on-commit MV + has_obj = 1 or -- MV with objects + -- not pk-based and not an MJV + (ref_method != 'PRIMARY KEY' and ref_method != 'JOIN VIEW') or + (ref_method = 'PRIMARY KEY' and mastabs > 1) or -- pk MV w/ >1 table + instr(upper(mv_query), 'SELECT', 1, 2) > 0 or -- nested queries + instr(upper(mv_query), 'FROM', 1, 2) > 0 or -- nested queries + instr(upper(mv_query), 'UNION') > 0 -- UNION clause + ) then + raise_application_error(-20000, + 'MV not supported for streams-based refresh'); + end if; + end if; + + -- get MV PK columns, else get key columns, else error + key_cols := get_keycols(canon_mv_owner, canon_mv_name); + if (key_cols.count = 0 and use_streams_refresh = TRUE) then + raise_application_error(-20000, + 'MV must have a PK or use dbms_apply_adm.set_key_columns()'); + end if; + if (key_cols.count > 0) then + for i in key_cols.first .. key_cols.last loop + streams_mv_refresh.print_trace('key_col='||key_cols(i)); + end loop; + end if; + + if (use_streams_refresh = TRUE) then + str_refresh := 1; + else + str_refresh := 0; + end if; + + -- check if an MJV + if (ref_method = 'JOIN VIEW') then + flags := flags + flg_mjv; + end if; + + -- MV has outerjoin predicates ? + if (has_oj = 1) then + flags := flags + flg_hasoj; + end if; + + -- + -- initialize MV metadata + -- + mvinfo := stmv_mv_t(canon_mv_owner, canon_mv_name, null, str_refresh, 0, + flags, stmv_column_list(), null, stmv_table_list(), + null); + + -- parse mv_query for select list and where clause + select_pos := instr(upper(mv_query), 'SELECT'); + select_start := select_pos + length('SELECT') + 1; + from_pos := instr(upper(mv_query), 'FROM'); + + -- copy select list to MV metadata object + mvinfo.select_list := + substr(mv_query, select_start, from_pos - select_start); + + -- copy where clause to MV metadata object by parsing the MV query + where_pos := instr(upper(mv_query), 'WHERE'); + if (where_pos != 0) then + where_start := where_pos + length('WHERE') + 1; + mvinfo.where_clause := substr(mv_query, where_start); + end if; + + -- get MV keycols + mvinfo.key_cols := key_cols; + + -- + -- get MV base tables + -- + open mycur for mv_master_tables using canon_mv_owner, canon_mv_name; + + streams_mv_refresh.print_trace('getting base tables'); + loop + fetch mycur into tabowner, tabname, tabalias; + exit when mycur%notfound; -- exit loop when last row is fetched + + streams_mv_refresh.print_trace('tabowner='||tabowner); + streams_mv_refresh.print_trace('tabname='||tabname); + streams_mv_refresh.print_trace('tabalias='||tabalias); + + -- store table information + tablist.extend; + tablist(tablist.last) := stmv_table_t(tabowner, tabname, tabalias, + stmv_column_list()); + + -- construct ""."" + owner_name := '"' || tabowner || '"."' || tabname || '"'; + + -- add apply rule + dbms_streams_adm.add_table_rules( + table_name => owner_name, + streams_type => 'apply', + streams_name => canon_apply, + queue_name => canon_queue, + include_tagged_lcr => true, + include_dml => true, + include_ddl => false, + source_database => streams_mv_refresh_adm.source_dbname); + + dbms_apply_adm.set_dml_handler( + object_name => owner_name, + object_type => 'TABLE', + operation_name => 'DEFAULT', + error_handler => false, + user_procedure => 'streams_mv_refresh.source_dml_handler', + apply_database_link => NULL, + apply_name => canon_apply); + + -- add capture rule + dbms_streams_adm.add_table_rules( + table_name => owner_name, + streams_type => 'capture', + streams_name => canon_capture, + queue_name => canon_queue, + include_tagged_lcr => true, + include_dml => true, + include_ddl => false, + inclusion_rule => true); + + end loop; + close mycur; + + -- capture rowids, too + dbms_capture_adm.include_extra_attribute(canon_capture, 'row_id', true); + + mvinfo.base_tabs := tablist; + + -- + -- get instantiation scn by refreshing MV or using current scn + -- (must be done after setting capture and apply table rules) + -- + if (instantiate = TRUE) then + -- construct ""."" + owner_name := '"' || canon_mv_owner || '"."' || canon_mv_name || '"'; + + -- refresh the MV + dbms_mview.refresh(owner_name); + + -- get the refresh scn + execute immediate get_refscn into inst_scn using + canon_mv_owner, canon_mv_name; + + else + -- use the current scn for the instantiation scn + inst_scn := dbms_flashback.get_system_change_number(); + end if; + + mvinfo.inst_scn := inst_scn; -- store instantiation scn + + -- for streams-based refresh, set MV to never refresh to prevent + -- user from refreshing MV using dbms_snapshot.refresh(), which + -- could cause incorrect results + owner_name := '"' || canon_mv_owner || '"."' || canon_mv_name || '"'; + if (use_streams_refresh = TRUE) then + execute immediate + 'alter materialized view '|| owner_name || ' never refresh'; + end if; + + -- + -- set table instantiation scn for all master tables + -- + open mycur for mv_master_tables using canon_mv_owner, canon_mv_name; + + loop + fetch mycur into tabowner, tabname, tabalias; + exit when mycur%notfound; -- exit loop when last row is fetched + + -- construct ""."" + owner_name := '"' || tabowner || '"."' || tabname || '"'; + + -- if table already has an instantiation scn registered, don't call + -- dbms_apply_adm.set_table_instantiation_scn() + select count(*) into cnt + from dba_apply_instantiated_objects + where source_object_owner = tabowner + and source_object_name = tabname + and source_object_type = 'TABLE' + and source_database = streams_mv_refresh_adm.source_dbname; + + if (cnt = 0) then + dbms_apply_adm.set_table_instantiation_scn( + source_object_name => owner_name, + source_database_name => streams_mv_refresh_adm.source_dbname, + instantiation_scn => inst_scn); + end if; + end loop; + + -- if user passed in an mv_dml_handler, then set up the MV for capture/apply + if (mv_dml_handler is not null) then + + -- construct ""."" + owner_name := '"' || canon_mv_owner || '"."' || canon_mv_name || '"'; + + inst_scn := dbms_flashback.get_system_change_number(); + + -- add apply rule + dbms_streams_adm.add_table_rules( + table_name => owner_name, + streams_type => 'apply', + streams_name => canon_apply, + queue_name => canon_queue, + include_tagged_lcr => true, + include_dml => true, + include_ddl => false, + source_database => streams_mv_refresh_adm.source_dbname); + + dbms_apply_adm.set_dml_handler( + object_name => owner_name, + object_type => 'TABLE', + operation_name => 'DEFAULT', + error_handler => false, + user_procedure => canon_hdlr, + apply_database_link => NULL, + apply_name => canon_apply); + + -- add capture rule + dbms_streams_adm.add_table_rules( + table_name => owner_name, + streams_type => 'capture', + streams_name => canon_capture, + queue_name => canon_queue, + include_tagged_lcr => true, + include_dml => true, + include_ddl => false, + inclusion_rule => true); + + -- if table already has an instantiation scn registered, don't call + -- dbms_apply_adm.set_table_instantiation_scn() + select count(*) into cnt + from dba_apply_instantiated_objects + where source_object_owner = canon_mv_owner + and source_object_name = canon_mv_name + and source_object_type = 'TABLE' + and source_database = streams_mv_refresh_adm.source_dbname; + + if (cnt = 0) then + dbms_apply_adm.set_table_instantiation_scn( + source_object_name => owner_name, + source_database_name => streams_mv_refresh_adm.source_dbname, + instantiation_scn => inst_scn); + end if; + + end if; + + -- + -- save MV registration metadata to disk + -- + insert into stmv_reg values (mvinfo); + commit; + + streams_mv_refresh.print_trace('register_mv()-'); +exception when others then + if mycur%isopen then + close mycur; + end if; + raise; +end; + + +-- +-- remove an MV from streams-driven refresh +-- +procedure unregister_mv(mv_owner varchar2, + mv_name varchar2, + capture_name varchar2 := 'CAPTURE_MV_MASTER', + apply_name varchar2 := 'APPLY_MV_MASTER') is + + mycur mycurtyp; + tabowner varchar2(30); + tabname varchar2(30); + owner_name varchar2(80); + cnt pls_integer; + canon_mv_owner varchar2(30); + canon_mv_name varchar2(30); + canon_capture varchar2(30); + canon_apply varchar2(30); + + -- all table rules associated with the specified capture, apply and table + cursor table_rules(capture_name varchar2, apply_name varchar2, + table_owner varchar2, table_name varchar2) is + select streams_name, streams_type, rule_owner, rule_name + from dba_streams_table_rules str + where streams_type = 'CAPTURE' + and streams_name = capture_name + and table_owner = table_rules.table_owner + and table_name = table_rules.table_name + union + select streams_name, streams_type, rule_owner, rule_name + from dba_streams_table_rules str + where streams_type = 'APPLY' + and streams_name = apply_name + and table_owner = table_rules.table_owner + and table_name = table_rules.table_name; + + -- select all master tables registered by this MV that is not used + -- by other registered MVs + mv_master_tables varchar2(32000) := +'select mt.table_owner, mt.table_name + from stmv_reg mv, table(mv.base_tabs) mt + where mv.mv_owner = :mv_owner + and mv.mv_name = :mv_name + and not exists + (select 1 + from stmv_reg mv2, table(mv2.base_tabs) mt2 + where not (mv2.mv_owner = mv.mv_owner + and mv2.mv_name = mv.mv_name) + and mt.table_owner = mt2.table_owner + and mt.table_name = mt2.table_name)'; + +begin + streams_mv_refresh.print_trace('unregister_mv()+'); + + -- canonicalize inputs + dbms_utility.canonicalize(mv_owner, canon_mv_owner, 30); + dbms_utility.canonicalize(mv_name, canon_mv_name, 30); + dbms_utility.canonicalize(capture_name, canon_capture, 30); + dbms_utility.canonicalize(apply_name, canon_apply, 30); + + -- make sure the apply process is down + select count(*) into cnt from dba_apply + where apply_name = canon_apply + and status = 'ENABLED'; + if (cnt > 0) then + raise_application_error(-20000, + 'Apply process must be disabled'); + end if; + + owner_name := '"' || canon_mv_owner || '"."' || canon_mv_name || '"'; + + -- remove MV DML handlers + dbms_apply_adm.set_dml_handler( + object_name => owner_name, + object_type => 'TABLE', + operation_name => 'DEFAULT', + error_handler => false, + user_procedure => NULL, + apply_database_link => NULL, + apply_name => canon_apply); + + -- remove all MV rules, if they exist + for rec in table_rules(canon_capture, canon_apply, + canon_mv_owner, canon_mv_name) loop + + -- construct ""."" + owner_name := '"' || rec.rule_owner || '"."' || rec.rule_name || '"'; + + dbms_streams_adm.remove_rule( + rule_name => owner_name, + streams_type => rec.streams_type, + streams_name => rec.streams_name); + end loop; + + -- + -- get MV base tables + -- + open mycur for mv_master_tables using canon_mv_owner, canon_mv_name; + + loop + fetch mycur into tabowner, tabname; + exit when mycur%notfound; -- exit loop when last row is fetched + + -- construct ""."" + owner_name := '"' || tabowner || '"."' || tabname || '"'; + + -- remove DML handlers + dbms_apply_adm.set_dml_handler( + object_name => owner_name, + object_type => 'TABLE', + operation_name => 'DEFAULT', + error_handler => false, + user_procedure => NULL, + apply_database_link => NULL, + apply_name => canon_apply); + + -- remove rules + for rec in table_rules(canon_capture, canon_apply, tabowner, tabname) loop + -- construct ""."" + owner_name := '"' || rec.rule_owner || '"."' || rec.rule_name || '"'; + + dbms_streams_adm.remove_rule( + rule_name => owner_name, + streams_type => rec.streams_type, + streams_name => rec.streams_name); + end loop; + end loop; + + -- delete MV from registration metadata + delete from stmv_reg + where mv_owner = canon_mv_owner + and mv_name = canon_mv_name; + + commit; + + streams_mv_refresh.print_trace('unregister_mv()-'); + +exception when others then + if mycur%isopen then + close mycur; + end if; + raise; +end; + + +-- +-- remove streams used for streams-driven refresh +-- +procedure remove_streams_mv_refresh( + capture_name varchar2 := 'CAPTURE_MV_MASTER', + apply_name varchar2 := 'APPLY_MV_MASTER') is + + owner_name varchar2(80); + inst_scn number; + db varchar2(128); + cnt pls_integer := 0; + canon_capture varchar2(30); + canon_apply varchar2(30); + capture_queue varchar2(30); + apply_queue varchar2(30); + + -- selects tables set up for MV refresh apply + cursor apply_tables(apply_name varchar2) is + select table_owner, table_name + from dba_streams_table_rules + where streams_type = 'APPLY' + and streams_name = apply_name; + + cursor instantiated_objects is + select source_object_owner table_owner, source_object_name table_name + from dba_apply_instantiated_objects + where SOURCE_OBJECT_TYPE = 'TABLE'; + +begin + streams_mv_refresh.print_trace('remove_streams_mv_refresh()+'); + + -- canonicalize inputs + dbms_utility.canonicalize(capture_name, canon_capture, 30); + dbms_utility.canonicalize(apply_name, canon_apply, 30); + + -- stop capture and apply + dbms_capture_adm.stop_capture(canon_capture); + dbms_apply_adm.stop_apply(canon_apply); + + -- get queue_name from capture process + begin + select queue_name into capture_queue + from dba_capture + where capture_name = canon_capture; + exception + when NO_DATA_FOUND then + raise_application_error(-20000, 'capture not found'); + end; + + -- get queue_name from apply process + begin + select queue_name into apply_queue + from dba_apply + where apply_name = canon_apply; + exception + when NO_DATA_FOUND then + raise_application_error(-20000, 'apply not found'); + end; + + -- capture and apply must share the same queue + if apply_queue != capture_queue then + raise_application_error(-20000, + 'capture and apply must share the same queue'); + end if; + + for rec in apply_tables(canon_apply) loop + -- construct ""."" + owner_name := '"' || rec.table_owner || '"."' || rec.table_name || '"'; + + -- remove dml handlers + dbms_apply_adm.set_dml_handler( + object_name => owner_name, + object_type => 'TABLE', + operation_name => 'DEFAULT', + error_handler => false, + user_procedure => NULL, + apply_database_link => NULL, + apply_name => canon_apply); + + end loop; + + -- remove capture and apply + dbms_apply_adm.drop_apply(canon_apply, true); + dbms_capture_adm.drop_capture(canon_capture, true); + + -- remove queues + dbms_streams_adm.remove_queue(capture_queue); + + -- if there are no apply processes left, remove any dangling + -- table instantiation scns + select count(*) into cnt + from dba_apply; + + if (cnt = 0) then + for rec in instantiated_objects loop + -- construct ""."" + owner_name := '"' || rec.table_owner || '"."' || rec.table_name || '"'; + + dbms_apply_adm.set_table_instantiation_scn( + source_object_name => owner_name, + source_database_name => streams_mv_refresh_adm.source_dbname, + instantiation_scn => null); + end loop; + else + -- other apply processes exist, so print a message to the caller + dbms_output.put_line('NOTE: Other apply processes exist so '|| + 'table instantiation scns were not removed.'); + dbms_output.put_line('To remove them, call ' || + 'dbms_apply_adm.set_table_instantiation_scn'); + dbms_output.put_line('Example:'); + dbms_output.put_line(' dbms_apply_adm.set_table_instantiation_scn('); + dbms_output.put_line(' source_object_name => ''tabowner.foo'','); + dbms_output.put_line(' source_database_name => db,'); + dbms_output.put_line(' instantiation_scn => null);'); + end if; + + -- delete any MV registration metadata + delete from stmv_reg; + commit; + + streams_mv_refresh.print_trace('remove_streams_mv_refresh()-'); + +end; + + +-- +-- package instantiation code +-- +begin + -- read in MV registration metadata + for rec in mv_group loop + reg_mvs.extend; + reg_mvs(reg_mvs.last) := rec.sys_nc_rowinfo$; + end loop; +end streams_mv_refresh_adm; +/ + + +create or replace package body streams_mv_refresh as + +first_in_session boolean := TRUE; -- do once per apply session + +-- +-- prints debug statements to the trace file +-- +procedure print_trace(mesg varchar2) is +begin + -- enable this line if you want tracing + --sys.dbms_system.ksdwrt(1, mesg); + + null; +end; + + +-- +-- returns list of registered MVs +-- +function get_mvs return stmv_mvs_t is +begin + return streams_mv_refresh_adm.reg_mvs; +end; + + +-- +-- determines an anydata value's datatype and binds it appropriately +-- +procedure bind_anydata(sql_cursor pls_integer, + name varchar2, + value sys.anydata) is + + tmp sys.anytype; + col_type pls_integer; + col_max_len pls_integer := 4000; + haslob boolean := FALSE; + +begin + print_trace('bind_anydata()+'); + + col_type := value.getType(tmp); + print_trace('col_type='||col_type); + + if col_type = 1 then + dbms_sql.bind_variable(sql_cursor, name, value.AccessChar, col_max_len); + elsif col_type = 2 then -- number + dbms_sql.bind_variable(sql_cursor, name, value.AccessNumber); + elsif col_type = DBMS_TYPES.TYPECODE_UROWID then -- rowid + -- anydata doesn't support rowid in 9i + dbms_sql.bind_variable(sql_cursor, name, value.AccessURowid); + elsif col_type = 12 then -- date + dbms_sql.bind_variable(sql_cursor, name, value.Accessdate); + elsif col_type = 23 then -- raw + dbms_sql.bind_variable_raw(sql_cursor, name, value.AccessRaw); + elsif col_type = 96 then + dbms_sql.bind_variable_char(sql_cursor, name, value.AccessChar, + col_max_len); + elsif col_type = DBMS_TYPES.TYPECODE_NCHAR then + dbms_sql.bind_variable_char(sql_cursor, name, value.AccessNChar, + col_max_len); + elsif col_type = 112 then -- clob + dbms_sql.bind_variable(sql_cursor, name, value.Accessclob); + haslob := true; + elsif col_type = DBMS_TYPES.TYPECODE_NCLOB then + dbms_sql.bind_variable(sql_cursor, name, value.Accessnclob); + haslob := true; + elsif col_type = 113 then -- blob + dbms_sql.bind_variable(sql_cursor, name, value.Accessblob); + haslob := true; + elsif col_type = 180 then -- timestamp + dbms_sql.bind_variable(sql_cursor, name, value.AccessTimestamp); + elsif col_type = 181 then -- timestamp with time zone + dbms_sql.bind_variable(sql_cursor, name, value.AccessTimestampTZ()); + elsif col_type=231 then -- timestamp with local time zone + dbms_sql.bind_variable(sql_cursor, name, value.AccessTimestampLTZ()); + elsif col_type = 182 then -- interval year to month + dbms_sql.bind_variable(sql_cursor, name, value.AccessIntervalYM()); + elsif col_type = 183 then -- interval day to second + dbms_sql.bind_variable(sql_cursor, name, value.AccessIntervalDS()); + end if; + + print_trace('bind_anydata()-'); +end; + + +-- +-- Given an MV, returns a comma-separated list of tables with a flashback +-- clause. Will be used for the FROM clause in a refresh query. +-- +function get_mvtab_list(mv_no pls_integer, + old_new varchar2, + null_check boolean) return varchar2 is + mvtab_list varchar2(32000); + flashback_clause varchar2(20); +begin + if (old_new = 'NEW') then + flashback_clause := ' AS OF SCN(:scn) '; + else + flashback_clause := ' AS OF SCN(:scn-1) '; + end if; + + for i in get_mvs()(mv_no).base_tabs.first .. + get_mvs()(mv_no).base_tabs.last loop + + -- add comma separator + if (i > get_mvs()(mv_no).base_tabs.first) then + mvtab_list := mvtab_list || ', '; + end if; + + mvtab_list := mvtab_list || '"' + || get_mvs()(mv_no).base_tabs(i).table_owner + || '"."' || get_mvs()(mv_no).base_tabs(i).table_name || '"' + || flashback_clause; + + if (get_mvs()(mv_no).base_tabs(i).table_alias is not null) then + mvtab_list := mvtab_list || '"' || + get_mvs()(mv_no).base_tabs(i).table_alias || '"'; + end if; + + end loop; + + if (not null_check) then + -- add rowid temp table + mvtab_list := mvtab_list || ', stmv_rid'; + end if; + + return mvtab_list; +end; + + +-- +-- constructs selection predicates to uniquely identify a row in a master table +-- +function append_tab_cond(mv_no pls_integer, + tab_no pls_integer, + delete_or_upsert varchar2, + null_check boolean := FALSE) return varchar2 is + + tab_cond varchar2(32000); + +begin + print_trace('append_tab_cond()+'); + + -- table alias or owner.table + if (get_mvs()(mv_no).base_tabs(tab_no).table_alias is not null) then + tab_cond := tab_cond || '"' || + get_mvs()(mv_no).base_tabs(tab_no).table_alias || '"'; + else + tab_cond := tab_cond || '"' || + get_mvs()(mv_no).base_tabs(tab_no).table_owner || '"."' || + get_mvs()(mv_no).base_tabs(tab_no).table_name || '"'; + end if; + + -- rowid column: check for null or rowid match + if (null_check) then + tab_cond := tab_cond ||'.' || streams_mv_refresh.rowid_col || ' is null '; + else + -- join with stmv_rid (rowid table) on rowid, table owner, table name, + -- and dml_type + tab_cond := tab_cond ||'.' || streams_mv_refresh.rowid_col || + ' = stmv_rid.rid '; + tab_cond := tab_cond || + 'and stmv_rid.table_owner = ' || '''' || + get_mvs()(mv_no).base_tabs(tab_no).table_owner || '''' || + ' and stmv_rid.table_name = ' || '''' || + get_mvs()(mv_no).base_tabs(tab_no).table_name || ''' '; + + if (delete_or_upsert = 'DELETE') then + tab_cond := tab_cond || 'and stmv_rid.dml_type in (2,4) '; + else + tab_cond := tab_cond || 'and stmv_rid.dml_type in (1,2) '; + end if; + end if; + + print_trace('append_tab_cond()-'); + + return tab_cond; +end; + + +-- +-- create flashback query relative to a base table in the MV query +-- +function create_query(delete_or_upsert varchar2, + mv_no pls_integer, + tab_no pls_integer, + null_check boolean := FALSE) return varchar2 is + + query varchar2(32000); + orig_where varchar2(32000); -- MV where clause + oldnew1 varchar2(5); + oldnew2 varchar2(5); + +begin + print_trace('create_query()+'); + + -- for deletes, get all MV rows removed due to the delete + -- otherwise, get all MV rows added due to the update/insert dml + if (delete_or_upsert = 'DELETE') then + oldnew1 := 'OLD'; + oldnew2 := 'NEW'; + else + oldnew1 := 'NEW'; + oldnew2 := 'OLD'; + end if; + + -- get original MV where clause + orig_where := get_mvs()(mv_no).where_clause; + if (orig_where is not null) then + orig_where := ' AND ' || orig_where; + end if; + + query := 'SELECT /*+ leading(stmv_rid) */ ' || + get_mvs()(mv_no).select_list || + ' FROM ' || get_mvtab_list(mv_no, oldnew1, null_check) || + ' WHERE ' || append_tab_cond(mv_no, tab_no, delete_or_upsert, + null_check) || orig_where || + ' MINUS ' || + 'SELECT /*+ leading(stmv_rid) */ ' || + get_mvs()(mv_no).select_list || + ' FROM ' || get_mvtab_list(mv_no, oldnew2, null_check) || + ' WHERE ' || append_tab_cond(mv_no,tab_no, delete_or_upsert, + null_check) || orig_where; + + print_trace('sql_stmt='||query); + print_trace('create_query()-'); + return query; +end create_query; + + +-- +-- find the next MV that has owner.name as a base table +-- mv_no, tab_no keeps track of current position in MV registration metadata +-- +function find_next_mv(owner varchar2, + name varchar2, + streams_refresh boolean, + mv_no in out nocopy pls_integer, + tab_no in out nocopy pls_integer) +return boolean is + + str_ref pls_integer; + +begin + print_trace('find_next_mv()+'); + + if (streams_refresh) then + str_ref := 1; + else + str_ref := 0; + end if; + + -- MVs can be registered for streams-based refresh or traditional refresh. + -- MV registration metadata keeps track of the refresh method registered. + if mv_no is null then + mv_no := get_mvs().first; + tab_no := get_mvs()(mv_no).base_tabs.first; + else + tab_no := get_mvs()(mv_no).base_tabs.next(tab_no); + if tab_no is null then + mv_no := get_mvs().next(mv_no); + if mv_no is not null then + tab_no := get_mvs()(mv_no).base_tabs.first; + end if; + end if; + end if; + + -- find next MV that has owner.name as a base table + while mv_no is not null loop + -- make sure MV stream_refresh flag = streams_refresh param + if (get_mvs()(mv_no).use_str_refresh = str_ref) then + while tab_no is not null loop + if (get_mvs()(mv_no).base_tabs(tab_no).table_owner = owner + and get_mvs()(mv_no).base_tabs(tab_no).table_name = name) then + + print_trace('found MV: '|| + get_mvs()(mv_no).mv_owner || '.' || get_mvs()(mv_no).mv_name); + print_trace('find_next_mv()-'); + return TRUE; + end if; + + tab_no := get_mvs()(mv_no).base_tabs.next(tab_no); + end loop; + end if; + + mv_no := get_mvs().next(mv_no); + if (mv_no is not null) then + tab_no := get_mvs()(mv_no).base_tabs.first; + end if; + + end loop; + + print_trace('find_next_mv()-'); + return FALSE; +end find_next_mv; + + +-- +-- +-- +procedure define_columns(sql_cursor pls_integer, + num_cols pls_integer, + desc_table sys.dbms_sql.desc_tab) is + + col_type pls_integer; + vcval varchar2(32000); + dateval date; + numval number; + rowidval rowid; + nvcval nvarchar2(15000); + rawval raw(2000); + charval char(2000); + ncval nchar(1000); + clobval clob; + blobval blob; + nclobval nclob; + -- tmval time(9); + -- tmtzval time(9) with time zone; + tmstpval timestamp(9); + tmstptzval timestamp(9) with time zone; + tmstpltzval timestamp(9) with local time zone; + ytomintval interval year(9) to month; + dtosintval interval day(9) to second(9); + haslob boolean := false; + +begin + for ctr in 1..num_cols loop + col_type := desc_table(ctr).col_type; + + if (col_type = 1) then + if (desc_table(ctr).col_charsetform != 2) then -- varchar2 + dbms_sql.define_column(sql_cursor,ctr,vcval, + desc_table(ctr).col_max_len); + else -- nvarchar2 + dbms_sql.define_column(sql_cursor,ctr,vcval, + desc_table(ctr).col_max_len); + end if; + elsif (col_type = 2) then -- number + dbms_sql.define_column(sql_cursor,ctr,numval); + elsif (col_type = 11) then -- rowid + dbms_sql.define_column_rowid(sql_cursor,ctr,rowidval); + elsif (col_type = 12) then -- date + dbms_sql.define_column(sql_cursor,ctr,dateval); + elsif (col_type = 23) then -- raw + dbms_sql.define_column_raw(sql_cursor,ctr,rawval, + desc_table(ctr).col_max_len); + elsif (col_type = 96) then + if (desc_table(ctr).col_charsetform != 2) then -- char + dbms_sql.define_column_char(sql_cursor,ctr,charval, + desc_table(ctr).col_max_len); + else -- nchar + dbms_sql.define_column_char(sql_cursor,ctr,ncval, + desc_table(ctr).col_max_len); + end if; + elsif (col_type = 112) then -- clob + if (desc_table(ctr).col_charsetform) != 2 then + dbms_sql.define_column(sql_cursor,ctr,clobval); + else + dbms_sql.define_column(sql_cursor,ctr,nclobval); + end if; + haslob := true; + elsif (col_type = 113) then -- blob + dbms_sql.define_column(sql_cursor,ctr,blobval); + haslob := true; +-- elsif (col_type = 178) then -- time +-- dbms_sql.define_column(sql_cursor,ctr,tmval); +-- elsif (col_type = 179) then -- time with time zone +-- dbms_sql.define_column(sql_cursor,ctr,tmtzval); + elsif (col_type = 180) then -- timestamp + dbms_sql.define_column(sql_cursor,ctr,tmstpval); + elsif (col_type = 181) then -- timestamp with time zone + dbms_sql.define_column(sql_cursor,ctr,tmstptzval); + elsif (col_type = 231) then -- timestamp with local time zone + dbms_sql.define_column(sql_cursor,ctr,tmstpltzval); + elsif (col_type = 182) then -- interval year to month + dbms_sql.define_column(sql_cursor,ctr,ytomintval); + elsif (col_type = 183) then -- interval day to second + dbms_sql.define_column(sql_cursor,ctr,dtosintval); + end if; + end loop; + +end; + + +-- +-- +-- +procedure get_column_values(sql_cursor pls_integer, + num_cols pls_integer, + desc_table sys.dbms_sql.desc_tab, + is_key_col stmv_num_list, + lcr in out nocopy sys.lcr$_row_record, + cmd_type varchar2, + first_time boolean) is + + col_type pls_integer; + col_name varchar2(32); + vcval varchar2(32000); + dateval date; + numval number; + rowidval rowid; + nvcval nvarchar2(15000); + rawval raw(2000); + charval char(2000); + ncval nchar(1000); + clobval clob; + blobval blob; + nclobval nclob; + -- tmval time(9); + -- tmtzval time(9) with time zone; + tmstpval timestamp(9); + tmstptzval timestamp(9) with time zone; + tmstpltzval timestamp(9) with local time zone; + ytomintval interval year(9) to month; + dtosintval interval day(9) to second(9); + myany sys.anydata; + is_key boolean; + +begin + -- build the lcr based upon the data type of + -- the column selected... + for ctr in 1..num_cols loop + col_type := desc_table(ctr).col_type; + col_name := '"' || desc_table(ctr).col_name || '"'; + is_key := (is_key_col(ctr) = 1); + + -- DELETE: only process key columns + if (cmd_type = 'DELETE' and not is_key) then + goto next_col; + end if; + + if (col_type = 1) then + if (desc_table(ctr).col_charsetform != 2) then -- varchar2 + dbms_sql.column_value(sql_cursor,ctr,vcval); + myany := Sys.AnyData.ConvertVarchar2(vcval); + else -- nvarchar2 + dbms_sql.column_value(sql_cursor,ctr,vcval); + myany := Sys.AnyData.ConvertNVarchar2(vcval); + end if; + elsif (col_type = 2) then -- number + dbms_sql.column_value(sql_cursor,ctr,numval); + myany := Sys.AnyData.ConvertNumber(numval); + elsif (col_type = 11) then -- rowid + dbms_sql.column_value_rowid(sql_cursor,ctr,rowidval); + -- in 10i, rowid will be supported; for now put in a char + print_trace('rowidval='||rowidval); + vcval := rowidval; + myany := Sys.AnyData.ConvertVarchar2(vcval); + elsif (col_type = 12) then -- date + dbms_sql.column_value(sql_cursor,ctr,dateval); + myany := Sys.AnyData.ConvertDate(dateval); + elsif (col_type = 23) then -- raw + dbms_sql.column_value_raw(sql_cursor,ctr,rawval); + myany := Sys.AnyData.ConvertRaw(rawval); + elsif (col_type = 96) then + if desc_table(ctr).col_charsetform != 2 then -- char + dbms_sql.column_value_char(sql_cursor,ctr,charval); + myany := Sys.AnyData.ConvertChar( -- trim charval to col_max_len + substr(charval, 1, desc_table(ctr).col_max_len)); + else -- nchar + dbms_sql.column_value_char(sql_cursor,ctr,ncval); + myany := Sys.AnyData.ConvertNchar( -- trim ncval to col_max_len + substr(ncval, 1, desc_table(ctr).col_max_len)); + end if; + elsif (col_type = 112) then -- clob + -- not supported for now + null; + elsif (col_type = 113) then -- blob + -- not supported for now + null; +-- elsif col_type = 178 then -- time +-- dbms_sql.column_value(sql_cursor,ctr,tmval); +-- -- anydata and time type??? +-- myany := Sys.AnyData.ConvertTimestamp(tmval); +-- elsif col_type = 179 then -- time with time zone +-- -- time type??? +-- dbms_sql.column_value(sql_cursor,ctr,tmtzval); +-- myany := Sys.AnyData.ConvertTimestampTZ(tmtzval); + elsif (col_type = 180) then -- timestamp + dbms_sql.column_value(sql_cursor,ctr,tmstpval); + myany := Sys.AnyData.ConvertTimestamp(tmstpval); + elsif (col_type = 181) then -- timestamp with time zone + dbms_sql.column_value(sql_cursor,ctr,tmstptzval); + myany := Sys.AnyData.ConvertTimestampTZ(tmstptzval); + elsif (col_type = 231) then -- timestamp with local timezone + dbms_sql.column_value(sql_cursor,ctr,tmstpltzval); + myany := Sys.AnyData.ConvertTimestampLTZ(tmstpltzval); + elsif (col_type = 182) then -- interval year to month + dbms_sql.column_value(sql_cursor,ctr,ytomintval); + myany := Sys.AnyData.ConvertIntervalYM(ytomintval); + elsif (col_type = 183) then -- interval day to second + dbms_sql.column_value(sql_cursor,ctr,dtosintval); + myany := Sys.AnyData.ConvertIntervalDS(dtosintval); + end if; + + if ((cmd_type = 'DELETE' or cmd_type = 'UPDATE') + and is_key) then + if (first_time) then + lcr.add_column('OLD', col_name, myany); + else + lcr.set_value('OLD', col_name, myany); + end if; + end if; + + if (cmd_type = 'INSERT' or cmd_type = 'UPDATE') then + if (first_time) then + lcr.add_column('NEW', col_name, myany); + else + lcr.set_value('NEW', col_name, myany); + end if; + end if; + + <> + null; + end loop; +end; + + +-- +-- for each row fetched from flashback query, creates and executes LCRs +-- +-- NOTE: no lobs in this version +procedure build_and_process_lcrs(sql_cursor pls_integer, + num_cols pls_integer, + desc_table sys.dbms_sql.desc_tab, + source_dbname varchar2, + cmd_type varchar2, + obj_owner varchar2, + obj_name varchar2, + key_cols stmv_column_list) is + + num_rows pls_integer; + lcr sys.lcr$_row_record; + is_key_col stmv_num_list := stmv_num_list(0); + first_time boolean := TRUE; + +begin + print_trace('build_and_process_lcrs()+'); + print_trace('cmd_type='||cmd_type); + print_trace('obj_owner='||obj_owner); + print_trace('obj_name='||obj_name); + + -- set up is_key_col array + -- initialize + is_key_col.extend(num_cols-1,1); + -- set elements that are key cols + for i in 1..num_cols loop + for j in key_cols.first .. key_cols.last loop + if (key_cols(j) = desc_table(i).col_name) then + is_key_col(i) := 1; + exit; + end if; + end loop; + end loop; + + -- execute the select statement + print_trace('before execute'); + num_rows := dbms_sql.execute(sql_cursor); + print_trace('after execute'); + + lcr := sys.lcr$_row_record.construct( + source_database_name=>source_dbname, + command_type=>cmd_type, + object_owner=>obj_owner, + object_name=>obj_name, + old_values=>NULL, + new_values=>NULL); + + -- loop until no more rows are returned + while dbms_sql.fetch_rows(sql_cursor) > 0 loop + print_trace('fetched row '); + + get_column_values(sql_cursor, num_cols, desc_table, is_key_col, + lcr, cmd_type, first_time); + + first_time := FALSE; + + streams_mv_lcr.process_lcr(lcr); + + end loop; + + print_trace('build_and_process_lcrs()-'); +end; + + +-- +-- +-- +procedure execute_delta_query(mv_idx pls_integer, + tab_idx pls_integer, + dml_type varchar2, + null_check boolean, + commit_scn number) is + + sql_stmt varchar2(32000); + sql_cursor pls_integer; + num_cols pls_integer; + desc_table sys.dbms_sql.desc_tab; + mv_owner varchar2(30); + mv_name varchar2(30); + key_cols stmv_column_list; + +begin + print_trace('execute_delta_query()+'); + + mv_owner := get_mvs()(mv_idx).mv_owner; + mv_name := get_mvs()(mv_idx).mv_name; + key_cols := get_mvs()(mv_idx).key_cols; + + sql_stmt := create_query(dml_type, mv_idx, tab_idx, null_check); + + print_trace('start parse and describe'); + sql_cursor := dbms_sql.open_cursor; + dbms_sql.parse(sql_cursor, sql_stmt, sys.dbms_sql.v7); + dbms_sql.describe_columns(sql_cursor, num_cols, desc_table); + print_trace('end parse and describe'); + + -- loop through the columns and do the define columns + print_trace('start define_columns'); + define_columns(sql_cursor, num_cols, desc_table); + print_trace('end define_columns'); + + -- bind the scn variable once + dbms_sql.bind_variable(sql_cursor, streams_mv_refresh.scn_bind, commit_scn); + + if (null_check) then + build_and_process_lcrs( + sql_cursor, + num_cols, + desc_table, + streams_mv_refresh_adm.source_dbname, + dml_type, + mv_owner, + mv_name, + key_cols); + else + print_trace('start process rowids'); + + build_and_process_lcrs( + sql_cursor, + num_cols, + desc_table, + streams_mv_refresh_adm.source_dbname, + dml_type, + mv_owner, + mv_name, + key_cols); + + print_trace('end process rowids'); + end if; + + dbms_sql.close_cursor(sql_cursor); + + print_trace('execute_delta_query()-'); +exception + when others then + if dbms_sql.is_open(sql_cursor) then + dbms_sql.close_cursor(sql_cursor); + end if; + raise; +end; + + +-- +-- adds rowid value to the rowid collection +-- +procedure add_to_rowid_coll(tab_rowid IN urowid, + rowid_coll IN OUT NOCOPY rowid_list) is + + found boolean := FALSE; + +begin + print_trace('add_to_rowid_coll()+'); + + -- see if rowid already exists in collection + if (rowid_coll.count > 0) then + for i in rowid_coll.first..rowid_coll.last loop + if (tab_rowid = rowid_coll(i)) then + found := TRUE; + exit; + end if; + end loop; + end if; + + -- new rowid: add to collection + if (found = FALSE) then + print_trace('new rowid'); + rowid_coll.extend; + rowid_coll(rowid_coll.last) := tab_rowid; + end if; + + print_trace('add_to_rowid_coll()-'); +end; + + +-- +-- adds to table collection that keeps track of DMLs and associated rowids +-- done to a table during a transaction +-- +procedure add_to_table_coll(tab_owner IN varchar2, + tab_name IN varchar2, + tab_dmltype IN pls_integer, + tab_rowid IN urowid, + tab_coll IN OUT NOCOPY txn_tab_list) is + + found boolean := FALSE; + +begin + print_trace('add_to_table_coll()+'); + + -- see if name already exists in table collection + if (tab_coll.count > 0) then + for i in tab_coll.first..tab_coll.last loop + if (tab_owner = tab_coll(i).table_owner and + tab_name = tab_coll(i).table_name) then + found := TRUE; + if (tab_dmltype is not null) then + if (bitand(tab_coll(i).dmltypes, tab_dmltype) = 0) then + tab_coll(i).dmltypes := tab_coll(i).dmltypes + tab_dmltype; + end if; + if (tab_rowid is not null) then + if (tab_dmltype = streams_mv_refresh.delete_dml or + tab_dmltype = streams_mv_refresh.update_dml) then + + add_to_rowid_coll(tab_rowid, tab_coll(i).delete_rowids); + + end if; + if (tab_dmltype = streams_mv_refresh.insert_dml or + tab_dmltype = streams_mv_refresh.update_dml) then + + add_to_rowid_coll(tab_rowid, tab_coll(i).insert_rowids); + + end if; + end if; + end if; + exit; + end if; + end loop; + end if; + + -- new table: add to collection + if (found = FALSE) then + print_trace('new table'); + tab_coll.extend; + tab_coll(tab_coll.last).table_owner := tab_owner; + tab_coll(tab_coll.last).table_name := tab_name; + tab_coll(tab_coll.last).dmltypes := tab_dmltype; + tab_coll(tab_coll.last).delete_rowids := rowid_list(); + tab_coll(tab_coll.last).insert_rowids := rowid_list(); + -- add rowid + if (tab_rowid is not null) then + if (tab_dmltype = streams_mv_refresh.delete_dml or + tab_dmltype = streams_mv_refresh.update_dml) then + + print_trace('adding delete rowid'); + tab_coll(tab_coll.last).delete_rowids:= rowid_list(tab_rowid); + + end if; + if (tab_dmltype = streams_mv_refresh.insert_dml or + tab_dmltype = streams_mv_refresh.update_dml) then + + print_trace('adding insert rowid'); + tab_coll(tab_coll.last).insert_rowids:= rowid_list(tab_rowid); + + end if; + end if; + end if; + + print_trace('add_to_table_coll()-'); +end; + + +-- +-- DML handler +-- +procedure source_dml_handler(lcr_anydata sys.anydata) is + + lcr sys.lcr$_row_record; + t pls_integer; + stmv_i pls_integer := null; -- iterator + tab_i pls_integer := null; -- iterator + commit_scn number := null; + dml_type varchar2(10); + dml_code pls_integer; + ridany sys.anydata; + ridval urowid; + object_owner varchar2(30); + object_name varchar2(30); + +BEGIN + print_trace('source_dml_handler()+'); + + t := lcr_anydata.getObject(lcr); + + commit_scn := lcr.get_commit_scn(); + print_trace('commit_scn='||commit_scn); + + -- get rowid from the lcr, if it exists + ridany := lcr.get_extra_attribute('row_id'); + + object_owner := lcr.get_object_owner; + object_name := lcr.get_object_name; + + print_trace('table=' || object_owner || '.' || object_name); + + if (first_in_session) then + -- do_enq_message('SET CONSTRAINTS ALL DEFERRED;'); + first_in_session := FALSE; + end if; + + -- + -- dbms_mview.refresh() codepath + -- + print_trace('processing MVs for dbms_mview.refresh()'); + + while (find_next_mv(object_owner, object_name, FALSE, + stmv_i, tab_i)) loop + + print_trace('MV=' || get_mvs()(stmv_i).mv_owner || '.' || + get_mvs()(stmv_i).mv_name); + + -- skip this MV if commit scn of this LCR <= the MV's instantiation scn + if (commit_scn > get_mvs()(stmv_i).inst_scn) then + + add_to_table_coll(get_mvs()(stmv_i).mv_owner, + get_mvs()(stmv_i).mv_name, + NULL, NULL, streams_mv_refresh.txn_mvs); + end if; + end loop; + + -- + -- streams refresh codepath + -- + print_trace('processing MVs for streams-based refresh'); + + stmv_i := null; + tab_i := null; + -- store table and lcr rowid if there is some MV dependent on the table + if find_next_mv(object_owner, object_name, TRUE, + stmv_i, tab_i) then + + -- need rowid for streams refresh + if (ridany is null) then + raise_application_error(-20000, + 'supplemental logging missing for rowid on ' || + object_owner || '.' || object_name); + end if; + ridval := ridany.AccessURowid; + print_trace('ridval='||ridval); + + dml_type := lcr.get_command_type; + print_trace('command_type=' || dml_type); + + if (dml_type = 'INSERT') then + dml_code := streams_mv_refresh.insert_dml; + elsif (dml_type = 'UPDATE') then + dml_code := streams_mv_refresh.update_dml; + elsif (dml_type = 'DELETE') then + dml_code := streams_mv_refresh.delete_dml; + else + dml_code := 0; + end if; + + -- add table to collection for commit-time processing + add_to_table_coll(object_owner, object_name, + dml_code, NULL, streams_mv_refresh.txn_tabs); + + print_trace('inserting into stmv_rid: '); + print_trace('table_owner='||object_owner); + print_trace('table_name='||object_name); + print_trace('dml_type='||dml_code); + print_trace('rid='||ridval); + + -- add rowid to temporary table for later processing + insert into stmv_rid (table_owner, table_name, dml_type, rid) + values (object_owner, object_name, dml_code, ridval); + end if; + + print_trace('source_dml_handler()-'); + +end; + +-- +-- autonmous block to create a scheduler job (this api commits) +-- +procedure create_scheduler_job(str varchar2) is + pragma autonomous_transaction; +begin + -- submit the refresh job + dbms_scheduler.create_job( + job_name => dbms_scheduler.generate_job_name, + job_type => 'PLSQL_BLOCK', + job_action => str, + start_date => sysdate, + enabled => TRUE); +end; + +-- +-- pre-commit handler +-- +procedure source_commit_hdlr(commit_scn number) is + l_jobnum pls_integer; + str varchar2(32000); + mvlist varchar2(32000); + is_first boolean := TRUE; + ref_scn number; -- refresh SCN + stmv_i pls_integer := null; -- iterator + tab_i pls_integer := null; -- iterator + dml_type varchar2(10); + is_mjv boolean; + is_ojmjv boolean; + tab_owner varchar2(30); + tab_name varchar2(30); + has_deletes boolean; + has_inserts boolean; + + -- MV last refresh scn + get_refscn varchar2(32000) := +'select rscn from sys.exu9snap + where owner = :mv_owner and name =:mv_name'; + +begin + print_trace('source_commit_hdlr()+'); + print_trace('commit_scn='||commit_scn); + + -- + -- dbms_mview.refresh() + -- + -- create comma-separated list of table owners and table names + if (streams_mv_refresh.txn_mvs.count > 0) then + + print_trace('processing MVs for dbms_mview.refresh()'); + + for i in streams_mv_refresh.txn_mvs.first.. + streams_mv_refresh.txn_mvs.last loop + + print_trace('MV=' || streams_mv_refresh.txn_mvs(i).table_owner || '.' || + streams_mv_refresh.txn_mvs(i).table_name); + + -- get the refresh scn + execute immediate get_refscn into ref_scn + using streams_mv_refresh.txn_mvs(i).table_owner, + streams_mv_refresh.txn_mvs(i).table_name; + + -- don't refresh the MV if it is current (this could happen if there + -- were any interim refreshes to the MV) + if (commit_scn >= ref_scn) then + -- add table to the list + if not is_first then + mvlist := mvlist || ','; + end if; + mvlist := mvlist || '"' || + streams_mv_refresh.txn_mvs(i).table_owner || '"."' || + streams_mv_refresh.txn_mvs(i).table_name || '"'; + is_first := FALSE; + end if; + end loop; + + -- submit a refresh job + str := + 'begin + dbms_mview.refresh(list=>''' || mvlist || ''',' || + 'atomic_refresh=>FALSE); + end;'; + + create_scheduler_job(str); + + -- reset mv_owners, mv_names collections + streams_mv_refresh.txn_mvs.delete; + end if; + + -- + -- streams-based refresh + -- + if (streams_mv_refresh.txn_tabs.count > 0) then + print_trace('processing MVs for streams-based refresh'); + + -- loop through all tables and DMLs done in the transaction + for i in streams_mv_refresh.txn_tabs.first.. + streams_mv_refresh.txn_tabs.last loop + + tab_owner := streams_mv_refresh.txn_tabs(i).table_owner; + tab_name := streams_mv_refresh.txn_tabs(i).table_name; + + -- determine if deletes or inserts were done (updates are considered + -- a delete followed by and insert) + has_deletes := (bitand(streams_mv_refresh.txn_tabs(i).dmltypes, + streams_mv_refresh.delete_dml) = + streams_mv_refresh.delete_dml + or + bitand(streams_mv_refresh.txn_tabs(i).dmltypes, + streams_mv_refresh.update_dml) = + streams_mv_refresh.update_dml); + + has_inserts := (bitand(streams_mv_refresh.txn_tabs(i).dmltypes, + streams_mv_refresh.insert_dml) = + streams_mv_refresh.insert_dml + or + bitand(streams_mv_refresh.txn_tabs(i).dmltypes, + streams_mv_refresh.update_dml) = + streams_mv_refresh.update_dml); + + print_trace('table=' || tab_owner || '.' || tab_name); + + while find_next_mv(tab_owner, tab_name, TRUE, stmv_i, tab_i) loop + + print_trace('MV=' || get_mvs()(stmv_i).mv_owner || '.' || + get_mvs()(stmv_i).mv_name); + + print_trace('MV inst_scn=' || get_mvs()(stmv_i).inst_scn); + if (commit_scn > get_mvs()(stmv_i).inst_scn) then + + print_trace('mv_flags='||get_mvs()(stmv_i).flags); + -- determine if an MJV + is_mjv := bitand(get_mvs()(stmv_i).flags, + streams_mv_refresh_adm.flg_mjv) = + streams_mv_refresh_adm.flg_mjv; + + -- determine if an outerjoin MJV + is_ojmjv := bitand(get_mvs()(stmv_i).flags, + streams_mv_refresh_adm.flg_mjv + + streams_mv_refresh_adm.flg_hasoj) = + streams_mv_refresh_adm.flg_mjv + + streams_mv_refresh_adm.flg_hasoj; + + -- join row processing + if (has_deletes) then + print_trace('delete phase: joins'); + + execute_delta_query(stmv_i, tab_i, 'DELETE', FALSE, commit_scn); + end if; + + if (has_inserts) then + print_trace('insert phase: joins'); + + if (is_mjv) then + dml_type := 'INSERT'; +-- dml_type := 'UPDATE'; + else + dml_type := 'INSERT'; + end if; + + execute_delta_query(stmv_i, tab_i, dml_type, FALSE, commit_scn); + end if; + + -- outer-join MJVs: take care of anti-join rows + if (is_ojmjv) then + + print_trace('is_ojmjv=true'); + + -- if INSERT or UPDATE was done, delete antijoins + if (has_inserts) then + print_trace('delete phase: antijoins'); + + execute_delta_query(stmv_i, tab_i, 'DELETE', TRUE, commit_scn); + end if; + + -- if DELETE or UPDATE was done, insert antijoins + if (has_deletes) then + print_trace('insert phase: antijoins'); + + execute_delta_query(stmv_i, tab_i, 'UPDATE', TRUE, commit_scn); + end if; + end if; + end if; + end loop; + + end loop; + + -- reset tab_owners, tab_names collections + streams_mv_refresh.txn_tabs.delete; + + end if; + + print_trace('source_commit_hdlr()-'); +end; + +end streams_mv_refresh; +/ + + +create or replace package body streams_mv_lcr as + +-- print LCR columns for debugging +procedure print_lcr_cols(cols sys.lcr$_row_list) is + col_type pls_integer; + tmp sys.anytype; + +begin + streams_mv_refresh.print_trace('print_lcr_cols()+'); + + -- make sure cols collection is non-empty + if (cols.count = 0) then + return; + end if; + + for i in cols.first..cols.last loop + streams_mv_refresh.print_trace('colname='||cols(i).column_name); + + col_type := cols(i).data.getType(tmp); + + if col_type = 1 then -- varchar2 + streams_mv_refresh.print_trace('colval='||cols(i).data.accessvarchar2); + elsif col_type = 2 then -- number + streams_mv_refresh.print_trace('colval='||cols(i).data.accessnumber); + else + streams_mv_refresh.print_trace('colval='||cols(i).data.accessvarchar2); + end if; + end loop; + + streams_mv_refresh.print_trace('print_lcr_cols()-'); +end; + + +-- +-- convert UPDATE LCR to an INSERT +-- +procedure do_an_insert(lcr sys.lcr$_row_record) is + tmp sys.anydata; + mv_no pls_integer; + i pls_integer; + found boolean := FALSE; + lcr_new sys.lcr$_row_record; + newvals sys.lcr$_row_list := sys.lcr$_row_list(); +begin + streams_mv_refresh.print_trace('do_an_insert()+'); + + if ( lcr.get_command_type = 'UPDATE' ) then + newvals := lcr.get_values('NEW', 'N'); + + -- double-quote all column names + for i in newvals.first..newvals.last loop + newvals(i).column_name := '"' || newvals(i).column_name || '"'; + end loop; + + lcr_new := sys.lcr$_row_record.construct( + source_database_name=>lcr.get_source_database_name, + command_type=>'INSERT', + object_owner=>lcr.get_object_owner, + object_name=>lcr.get_object_name, + old_values=>NULL, + new_values=>newvals); + + streams_mv_refresh.print_trace('printing newvals:'); +-- streams_mv_lcr.print_lcr_cols(newvals); + + lcr_new.execute(false); + end if; + + streams_mv_refresh.print_trace('do_an_insert()-'); +end; + + +-- +-- apply the LCR +-- +procedure process_lcr(lcr sys.lcr$_row_record) is + + -- new exception raised during apply to replace ora-1403 + row_does_not_exist exception; + pragma exception_init(row_does_not_exist, -26787); + +begin + streams_mv_refresh.print_trace('process_lcr()+'); + + -- this function may be customized to call a different procedure + begin + dbms_mview.set_i_am_a_refresh(true); -- allows the MV to be updated + lcr.execute(false); + streams_mv_refresh.print_trace('applied LCR'); + dbms_mview.set_i_am_a_refresh(false); + + exception + when DUP_VAL_ON_INDEX then + streams_mv_refresh.print_trace('DUP_VAL_ON_INDEX, type='|| + lcr.get_command_type); + + when NO_DATA_FOUND or row_does_not_exist then + streams_mv_refresh.print_trace('NO_DATA_FOUND, type='|| + lcr.get_command_type); + do_an_insert(lcr); + when others then + raise; + end; + + streams_mv_refresh.print_trace('process_lcr()-'); +end; + +end streams_mv_lcr; +/ + +-- Procedure for verifying results +create or replace procedure verify_tables(tab1 in varchar2, + tab2 in varchar2, + max_time in integer default 3600) + authid current_user as + + tab2_sql varchar2(32000); + tab1_sql varchar2(32000); + diff_sql varchar2(32000); + cur integer; + ret integer; + num_rows integer; + slept integer := 0; + wait_for_convergence boolean := true; + +begin + dbms_output.enable ( 10000 ) ; + + tab1_sql := 'select * from ' || tab1; + + tab2_sql := 'select * from ' || tab2; + +-- diff_sql is the query that should return 0 rows if the snapshot rows +-- have converged + diff_sql := '(' || + tab1_sql || + ' minus ' || + tab2_sql || + ')' || + ' union ' || + '(' || + tab2_sql || + ' minus ' || + tab1_sql || + ')' ; + + +-- get the no. of rows returned by diff_sql. + cur := dbms_sql.open_cursor; + dbms_sql.parse(cur, + 'select count(*) from ( ' || diff_sql || ' )', dbms_sql.v7); + sys.dbms_sql.define_column(cur, 1, num_rows); + begin + ret := dbms_sql.execute_and_fetch(cur); + dbms_sql.column_value(cur,1,num_rows); + exception when others then + if dbms_sql.is_open(cur) then + dbms_sql.close_cursor(cur); + end if; + dbms_output.put_line ('-- error while counting rows in diff_sql'); + raise; + end; + +while (wait_for_convergence) loop + ret := dbms_sql.execute_and_fetch(cur); + dbms_sql.column_value(cur,1,num_rows); + +-- begin num_rows if + if num_rows = 0 then + dbms_output.put_line( + '---------------------------------------------------------------------------' + ); + dbms_output.put_line('-- Tables/views '||tab1 ||' and '||tab2 || ' are identical'); + dbms_output.put_line( + '---------------------------------------------------------------------------' + ); + wait_for_convergence := false; + else + dbms_lock.sleep(3); + slept := slept + 3; + if (slept >= max_time ) then + dbms_output.put_line( + '---------------------------------------------------------------------------' + ); + dbms_output.put_line('-- WARNING: maximum wait time of '|| slept ||' seconds exceeded'); + dbms_output.put_line('-- Tables/views '||tab1 ||' and '||tab2 || ' are NOT identical'); + dbms_output.put_line('-- Check trace files to determine what is going wrong'); + dbms_output.put_line( + '---------------------------------------------------------------------------' + ); + wait_for_convergence := false; + end if; + end if; +end loop; + dbms_sql.close_cursor(cur); + +end; +/ + +create or replace public synonym verify_tables for verify_tables; +grant execute on verify_tables to public; diff --git a/strmqp1.sql b/strmqp1.sql new file mode 100644 index 0000000..bd8a060 --- /dev/null +++ b/strmqp1.sql @@ -0,0 +1,1098 @@ +Rem +Rem $Header: strmqp1.sql 23-jun-2006.15:31:45 wesmith Exp $ +Rem +Rem strmqp1.sql +Rem +Rem Copyright (c) 2006, Oracle. All rights reserved. +Rem +Rem NAME +Rem strmqp1.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem wesmith 06/23/06 - register_query: add parameter queue_name +Rem wesmith 06/12/06 - register_query: add include_extra_attribute() +Rem wesmith 01/19/06 - Created +Rem + +---------------------- +-- supporting objects +---------------------- + +-- master table metadata +create or replace type stq_table_t as object ( + table_owner varchar2(30), /* base table owner */ + table_name varchar2(30), /* base table name */ + refresh_query varchar2(4000), /* refresh query used by the dml handler */ + commit_query varchar2(4000) /* refresh query used by the pre-commit hdlr */ +) +/ +create or replace type stq_table_list is table of stq_table_t +/ + +-- query metadata +create or replace type stq_query_t as object ( + query_owner varchar2(30), /* query table owner */ + query_name varchar2(30), /* query table name */ + inst_scn number, /* query table instantiation scn */ + key_cols stmv_column_list, /* query table key columns */ + base_tabs stq_table_list /* MV base tables */ +) +/ +create or replace type stq_queries_t is table of stq_query_t +/ + +-- store streams query registration metadata +create table stq_reg of stq_query_t (primary key(query_owner, query_name)) + nested table key_cols store as stq_qry_keycol_st + nested table base_tabs store as stq_tab_st; + + +------------ +-- packages +------------ +create or replace package streams_qry_refresh_adm AUTHID CURRENT_USER as + type mycurtyp IS REF cursor; + reg_qrys stq_queries_t := stq_queries_t(); + + -- constants + source_dbname constant varchar2(256) := dbms_standard.database_name; + + -- sets up a query for streams-driven refresh + procedure register_query(query_owner varchar2, + query_name varchar2, + base_tables stq_table_list, + capture_name varchar2 :='CAPTURE_QRY_MASTER', + apply_name varchar2 :='APPLY_QRY_MASTER', + queue_name varchar2 := NULL); + + -- removes a query from streams-driven refresh + procedure unregister_query(query_owner varchar2, + query_name varchar2, + capture_name varchar2 := 'CAPTURE_QRY_MASTER', + apply_name varchar2 := 'APPLY_QRY_MASTER'); + + -- removes streams configuration for streams-driven query refresh + procedure remove_streams_qry_refresh( + capture_name varchar2 := 'CAPTURE_QRY_MASTER', + apply_name varchar2 := 'APPLY_QRY_MASTER'); + +end streams_qry_refresh_adm; +/ + + +-- +create or replace package streams_qry_refresh AUTHID CURRENT_USER as + + -- collection of table owners, names in a transaction + txn_tabs streams_mv_refresh.txn_tab_list := + streams_mv_refresh.txn_tab_list(); + + -- dml types + insert_dml constant pls_integer := 1; + update_dml constant pls_integer := 2; + delete_dml constant pls_integer := 4; + + rowid_col constant varchar2(5) := 'ROWID'; + scn_bind constant varchar2(5) := 'SCN'; + rowid_bind constant varchar2(5) := 'RID'; + + -- dml handler used by streams-driven refresh + procedure source_dml_handler(lcr_anydata in sys.anydata); + + -- pre-commit handler used by streams-driven refresh + procedure source_commit_hdlr(commit_scn number); + + procedure print_trace(mesg varchar2); +end streams_qry_refresh; +/ + + +-- +create or replace package streams_qry_lcr AUTHID CURRENT_USER as + -- applies an LCR to an MV during streams-based refresh + procedure process_lcr(lcr sys.lcr$_row_record); +end streams_qry_lcr; +/ + + +-- +create or replace package body streams_qry_refresh_adm as + + cursor query_reg is select sys_nc_rowinfo$ from stq_reg; + +-- +-- register a query for streams-driven refresh +-- +procedure register_query(query_owner varchar2, + query_name varchar2, + base_tables stq_table_list, + capture_name varchar2 := 'CAPTURE_QRY_MASTER', + apply_name varchar2 := 'APPLY_QRY_MASTER', + queue_name varchar2 := NULL) is + + canon_qry_owner varchar2(30); + canon_qry_name varchar2(30); + canon_tab_owner varchar2(30); + canon_tab_name varchar2(30); + canon_capture varchar2(30); + canon_apply varchar2(30); + canon_queue varchar2(30); + owner_name varchar2(80); -- table_owner.table_name + qryinfo stq_query_t := NULL; + cnt pls_integer; + select_pos pls_integer := 0; + select_start pls_integer := 0; + inst_scn number; -- instantiation SCN + key_cols stmv_column_list; + + canon_schema varchar2(30); + canon_part1 varchar2(30); + canon_part2 varchar2(30); + canon_dblink varchar2(128); + canon_part1_type number; + object_number number; + +begin + streams_qry_refresh.print_trace('register_query()+'); + streams_qry_refresh.print_trace('query_owner='||query_owner); + streams_qry_refresh.print_trace('query_name='||query_name); + streams_qry_refresh.print_trace('capture_name='||capture_name); + streams_qry_refresh.print_trace('apply_name='||apply_name); + streams_qry_refresh.print_trace('queue_name='||queue_name); + + -- canonicalize inputs + dbms_utility.canonicalize(query_owner, canon_qry_owner, 30); + dbms_utility.canonicalize(query_name, canon_qry_name, 30); + dbms_utility.canonicalize(capture_name, canon_capture, 30); + dbms_utility.canonicalize(apply_name, canon_apply, 30); + dbms_utility.canonicalize(queue_name, canon_queue, 30); + + -- make sure the apply process is down + select count(*) into cnt from dba_apply + where apply_name = canon_apply + and status = 'ENABLED'; + if (cnt > 0) then + raise_application_error(-20000, 'Apply process must be disabled'); + end if; + + -- get queue_name from capture and apply process views if NULL + if (canon_queue is NULL) then + declare + apply_queue varchar2(30); + capture_queue varchar2(30); + begin + -- get queue for capture and apply + select queue_name into capture_queue + from dba_capture + where capture_name = canon_capture; + + select queue_name into apply_queue + from dba_apply + where apply_name = canon_apply; + + -- capture and apply must share the same queue + if apply_queue != capture_queue then + raise_application_error(-20000, + 'capture and apply must share the same queue'); + end if; + + canon_queue := capture_queue; + + exception + when NO_DATA_FOUND then + raise_application_error(-20000, 'must specify queue_name'); + end; + end if; + + -- + -- make sure base_tables is not empty + -- + if (base_tables is null or base_tables.count = 0) then + raise_application_error(-20000, + 'base_tables collection must not be empty'); + end if; + + -- + -- error if query registration metadata already exists + -- + select count(*) into cnt + from stq_reg + where query_owner = canon_qry_owner + and query_name = canon_qry_name; + if (cnt > 0) then + owner_name := '"' || canon_qry_owner || '"."' || canon_qry_name || '"'; + raise_application_error(-20000, + 'Query ' || owner_name || ' already registered'); + end if; + + -- + -- check that tables exist + -- + -- construct ""."" + owner_name := '"' || canon_qry_owner || '"."' || canon_qry_name || '"'; + dbms_utility.name_resolve(owner_name, 2, canon_schema, canon_part1, + canon_part2, canon_dblink, canon_part1_type, object_number); + + for i in base_tables.first .. base_tables.last loop + dbms_utility.canonicalize(base_tables(i).table_owner, canon_tab_owner, 30); + dbms_utility.canonicalize(base_tables(i).table_name, canon_tab_name, 30); + owner_name := '"' || canon_tab_owner || '"."' || canon_tab_name || '"'; + + dbms_utility.name_resolve(owner_name, 2, canon_schema, canon_part1, + canon_part2, canon_dblink, canon_part1_type, object_number); + end loop; + + -- + -- validate refresh query: + -- begins with select + -- has :rid, :scn binds + for i in base_tables.first .. base_tables.last loop + dbms_utility.canonicalize(base_tables(i).table_owner, canon_tab_owner, 30); + dbms_utility.canonicalize(base_tables(i).table_name, canon_tab_name, 30); + owner_name := '"' || canon_tab_owner || '"."' || canon_tab_name || '"'; + + if (instr(upper(base_tables(i).refresh_query), 'SELECT') != 1 or + instr(upper(base_tables(i).refresh_query), ':RID') = 0 or + instr(upper(base_tables(i).refresh_query), ':SCN') = 0) then + raise_application_error(-20000, + 'Refresh query for ' || owner_name || ' has errors'); + end if; + end loop; + + -- get query key columns + key_cols := streams_mv_refresh_adm.get_keycols(canon_qry_owner, + canon_qry_name); + if (key_cols.count = 0) then + raise_application_error(-20000, + 'query table must have a PK or use dbms_apply_adm.set_key_columns()'); + end if; + if (key_cols.count > 0) then + for i in key_cols.first .. key_cols.last loop + streams_qry_refresh.print_trace('key_col='||key_cols(i)); + end loop; + end if; + + -- + -- initialize query metadata + -- + qryinfo := stq_query_t(canon_qry_owner, canon_qry_name, null, + stmv_column_list(), stq_table_list()); + -- get table keycols + qryinfo.key_cols := key_cols; + + -- store table information + qryinfo.base_tabs := base_tables; + + -- process all base tables + for i in base_tables.first .. base_tables.last loop + dbms_utility.canonicalize(base_tables(i).table_owner, canon_tab_owner, 30); + dbms_utility.canonicalize(base_tables(i).table_name, canon_tab_name, 30); + + -- save canonicalized tab owner/name in query metadata + qryinfo.base_tabs(i).table_owner := canon_tab_owner; + qryinfo.base_tabs(i).table_name := canon_tab_name; + + -- construct ""."" + owner_name := '"' || canon_tab_owner || '"."' || canon_tab_name || '"'; + + -- add apply rule + dbms_streams_adm.add_table_rules( + table_name => owner_name, + streams_type => 'apply', + streams_name => canon_apply, + queue_name => canon_queue, + include_tagged_lcr => true, + include_dml => true, + include_ddl => false, + source_database => streams_qry_refresh_adm.source_dbname); + + dbms_apply_adm.set_dml_handler( + object_name => owner_name, + object_type => 'TABLE', + operation_name => 'DEFAULT', + error_handler => false, + user_procedure => 'streams_qry_refresh.source_dml_handler', + apply_database_link => NULL, + apply_name => canon_apply); + + -- add capture rule + dbms_streams_adm.add_table_rules( + table_name => owner_name, + streams_type => 'capture', + streams_name => canon_capture, + queue_name => canon_queue, + include_tagged_lcr => true, + include_dml => true, + include_ddl => false, + inclusion_rule => true); + + end loop; + + -- capture rowids, too + dbms_capture_adm.include_extra_attribute(canon_capture, 'row_id', true); + + -- TODO: instantiate query table + -- + -- get instantiation scn by using current scn + -- (must be done after setting capture and apply table rules) + -- + inst_scn := dbms_flashback.get_system_change_number(); + + -- set instantiation scn + for i in base_tables.first .. base_tables.last loop + dbms_utility.canonicalize(base_tables(i).table_owner, canon_tab_owner, 30); + dbms_utility.canonicalize(base_tables(i).table_name, canon_tab_name, 30); + + -- construct ""."" + owner_name := '"' || canon_tab_owner || '"."' || canon_tab_name || '"'; + + -- if table already has an instantiation scn registered, don't call + -- dbms_apply_adm.set_table_instantiation_scn() + select count(*) into cnt + from dba_apply_instantiated_objects + where source_object_owner = canon_tab_owner + and source_object_name = canon_tab_name + and source_object_type = 'TABLE' + and source_database = streams_qry_refresh_adm.source_dbname; + + if (cnt = 0) then + dbms_apply_adm.set_table_instantiation_scn( + source_object_name => owner_name, + source_database_name => streams_qry_refresh_adm.source_dbname, + instantiation_scn => inst_scn); + end if; + end loop; + + qryinfo.inst_scn := inst_scn; + + -- + -- save query registration metadata to disk + -- + insert into stq_reg values(qryinfo); + commit; + + streams_qry_refresh.print_trace('register_query()-'); + +end; + + +-- +-- remove a query from streams-driven refresh +-- +procedure unregister_query(query_owner varchar2, + query_name varchar2, + capture_name varchar2 := 'CAPTURE_QRY_MASTER', + apply_name varchar2 := 'APPLY_QRY_MASTER') is + + mycur mycurtyp; + tabowner varchar2(30); + tabname varchar2(30); + owner_name varchar2(80); + cnt pls_integer; + canon_qry_owner varchar2(30); + canon_qry_name varchar2(30); + canon_capture varchar2(30); + canon_apply varchar2(30); + + -- all table rules associated with the specified capture, apply and table + cursor table_rules(capture_name varchar2, apply_name varchar2, + table_owner varchar2, table_name varchar2) is + select streams_name, streams_type, rule_owner, rule_name + from dba_streams_table_rules str + where streams_type = 'CAPTURE' + and streams_name = capture_name + and table_owner = table_rules.table_owner + and table_name = table_rules.table_name + union + select streams_name, streams_type, rule_owner, rule_name + from dba_streams_table_rules str + where streams_type = 'APPLY' + and streams_name = apply_name + and table_owner = table_rules.table_owner + and table_name = table_rules.table_name; + + -- select all master tables registered by this query that is not used + -- by other registered queries + qry_base_tables varchar2(1000) := +'select bt.table_owner, bt.table_name + from stq_reg q, table(q.base_tabs) bt + where q.query_owner = :qry_owner + and q.query_name = :qry_name + and not exists + (select 1 + from stq_reg q2, table(q2.base_tabs) bt2 + where not (q2.query_owner = q.query_owner + and q2.query_name = q.query_name) + and bt.table_owner = bt2.table_owner + and bt.table_name = bt2.table_name)'; + +begin + streams_qry_refresh.print_trace('unregister_query()+'); + + -- canonicalize inputs + dbms_utility.canonicalize(query_owner, canon_qry_owner, 30); + dbms_utility.canonicalize(query_name, canon_qry_name, 30); + dbms_utility.canonicalize(capture_name, canon_capture, 30); + dbms_utility.canonicalize(apply_name, canon_apply, 30); + + -- make sure the apply process is down + select count(*) into cnt from dba_apply + where apply_name = canon_apply + and status = 'ENABLED'; + if (cnt > 0) then + raise_application_error(-20000, + 'Apply process must be disabled'); + end if; + + owner_name := '"' || canon_qry_owner || '"."' || canon_qry_name || '"'; + + -- + -- get query base tables + -- + open mycur for qry_base_tables using canon_qry_owner, canon_qry_name; + + loop + fetch mycur into tabowner, tabname; + exit when mycur%notfound; -- exit loop when last row is fetched + + -- construct ""."" + owner_name := '"' || tabowner || '"."' || tabname || '"'; + + -- remove DML handlers + dbms_apply_adm.set_dml_handler( + object_name => owner_name, + object_type => 'TABLE', + operation_name => 'DEFAULT', + error_handler => false, + user_procedure => NULL, + apply_database_link => NULL, + apply_name => canon_apply); + + -- remove rules + for rec in table_rules(canon_capture, canon_apply, tabowner, tabname) loop + -- construct ""."" + owner_name := '"' || rec.rule_owner || '"."' || rec.rule_name || '"'; + + dbms_streams_adm.remove_rule( + rule_name => owner_name, + streams_type => rec.streams_type, + streams_name => rec.streams_name); + end loop; + end loop; + + -- delete query from registration metadata + delete from stq_reg + where query_owner = canon_qry_owner + and query_name = canon_qry_name; + + commit; + + streams_qry_refresh.print_trace('unregister_query()-'); + +exception when others then + if mycur%isopen then + close mycur; + end if; + raise; +end; + + +-- +-- remove streams used for streams-driven refresh +-- +procedure remove_streams_qry_refresh( + capture_name varchar2 := 'CAPTURE_QRY_MASTER', + apply_name varchar2 := 'APPLY_QRY_MASTER') is + + owner_name varchar2(80); + inst_scn number; + db varchar2(128); + cnt pls_integer := 0; + canon_capture varchar2(30); + canon_apply varchar2(30); + capture_queue varchar2(30); + apply_queue varchar2(30); + + -- selects tables set up for query refresh apply + cursor apply_tables(apply_name varchar2) is + select table_owner, table_name + from dba_streams_table_rules + where streams_type = 'APPLY' + and streams_name = apply_name; + + cursor instantiated_objects is + select source_object_owner table_owner, source_object_name table_name + from dba_apply_instantiated_objects + where SOURCE_OBJECT_TYPE = 'TABLE'; + +begin + streams_qry_refresh.print_trace('remove_streams_qry_refresh()+'); + + -- canonicalize inputs + dbms_utility.canonicalize(capture_name, canon_capture, 30); + dbms_utility.canonicalize(apply_name, canon_apply, 30); + + -- stop capture and apply + dbms_capture_adm.stop_capture(canon_capture); + dbms_apply_adm.stop_apply(canon_apply); + + -- get queue_name from capture process + begin + select queue_name into capture_queue + from dba_capture + where capture_name = canon_capture; + exception + when NO_DATA_FOUND then + raise_application_error(-20000, 'capture not found'); + end; + + -- get queue_name from apply process + begin + select queue_name into apply_queue + from dba_apply + where apply_name = canon_apply; + exception + when NO_DATA_FOUND then + raise_application_error(-20000, 'apply not found'); + end; + + -- capture and apply must share the same queue + if apply_queue != capture_queue then + raise_application_error(-20000, + 'capture and apply must share the same queue'); + end if; + + for rec in apply_tables(canon_apply) loop + -- construct ""."" + owner_name := '"' || rec.table_owner || '"."' || rec.table_name || '"'; + + -- remove dml handlers + dbms_apply_adm.set_dml_handler( + object_name => owner_name, + object_type => 'TABLE', + operation_name => 'DEFAULT', + error_handler => false, + user_procedure => NULL, + apply_database_link => NULL, + apply_name => canon_apply); + + end loop; + + -- remove capture and apply + dbms_apply_adm.drop_apply(canon_apply, true); + dbms_capture_adm.drop_capture(canon_capture, true); + + -- remove queues + dbms_streams_adm.remove_queue(capture_queue); + + -- if there are no apply processes left, remove any dangling + -- table instantiation scns + select count(*) into cnt + from dba_apply; + + if (cnt = 0) then + for rec in instantiated_objects loop + -- construct ""."" + owner_name := '"' || rec.table_owner || '"."' || rec.table_name || '"'; + + dbms_apply_adm.set_table_instantiation_scn( + source_object_name => owner_name, + source_database_name => streams_qry_refresh_adm.source_dbname, + instantiation_scn => null); + end loop; + else + -- other apply processes exist, so print a message to the caller + dbms_output.put_line('NOTE: Other apply processes exist so '|| + 'table instantiation scns were not removed.'); + dbms_output.put_line('To remove them, call ' || + 'dbms_apply_adm.set_table_instantiation_scn'); + dbms_output.put_line('Example:'); + dbms_output.put_line(' dbms_apply_adm.set_table_instantiation_scn('); + dbms_output.put_line(' source_object_name => ''tabowner.foo'','); + dbms_output.put_line(' source_database_name => db,'); + dbms_output.put_line(' instantiation_scn => null);'); + end if; + + -- delete any query registration metadata + delete from stq_reg; + commit; + + streams_qry_refresh.print_trace('remove_streams_qry_refresh()-'); + +end; + +-- +-- package instantiation code +-- +begin + -- read in query registration metadata + for rec in query_reg loop + reg_qrys.extend; + reg_qrys(reg_qrys.last) := rec.sys_nc_rowinfo$; + end loop; +end streams_qry_refresh_adm; +/ + + +-- +create or replace package body streams_qry_refresh as + +-- +-- prints debug statements to the trace file +-- +procedure print_trace(mesg varchar2) is +begin + -- enable this line if you want tracing + --sys.dbms_system.ksdwrt(1, mesg); + + null; +end; + + +-- +-- returns list of registered queries +-- +function get_qrys return stq_queries_t is +begin + return streams_qry_refresh_adm.reg_qrys; +end; + + +-- +-- create flashback query relative to a base table in the query +-- +function create_query(delete_or_upsert varchar2, + qry_no pls_integer, + tab_no pls_integer, + is_commit_query boolean) return varchar2 is + + query_after varchar2(32000); -- query at commit scn + query varchar2(32000); + prev_pos number :=1; + cur_pos number; + +begin + print_trace('create_query()+'); + + if (is_commit_query) then + query_after := + get_qrys()(qry_no).base_tabs(tab_no).commit_query; + else + query_after := + get_qrys()(qry_no).base_tabs(tab_no).refresh_query; + end if; + + -- replace all instances of ':SCN' with ':SCN-1' + -- to create a query which will get the 'before' image + while (true) loop + cur_pos := instr(upper(query_after), ':SCN', prev_pos); + + if (cur_pos = 0) then + exit; + end if; + + query := query || substr(query_after, prev_pos, cur_pos + 4 - prev_pos) + || '-1'; + prev_pos := cur_pos +4; + end loop; + + query := query || substr(query_after, prev_pos); + + if (delete_or_upsert = 'DELETE') then + query := query || ' MINUS ' || query_after; + else + query := query_after || ' MINUS ' || query; + end if; + + print_trace('sql_stmt='||query); + print_trace('create_query()-'); + return query; + +end create_query; + + +-- +-- find the next query that has owner.name as a base table +-- qry_no, tab_no keeps track of current position in query +-- registration metadata +-- +function find_next_qry(owner varchar2, + name varchar2, + qry_no in out pls_integer, + tab_no in out pls_integer) return boolean is + +begin + print_trace('find_next_qry()+'); + + if qry_no is null then + qry_no := get_qrys().first; + tab_no := get_qrys()(qry_no).base_tabs.first; + else + tab_no := get_qrys()(qry_no).base_tabs.next(tab_no); + if tab_no is null then + qry_no := get_qrys().next(qry_no); + if qry_no is not null then + tab_no := get_qrys()(qry_no).base_tabs.first; + end if; + end if; + end if; + + -- find next query that has owner.name as a base table + while qry_no is not null loop + while tab_no is not null loop + if (get_qrys()(qry_no).base_tabs(tab_no).table_owner = owner + and + get_qrys()(qry_no).base_tabs(tab_no).table_name = name) then + + print_trace('found query: '|| get_qrys()(qry_no).query_owner || '.' || + get_qrys()(qry_no).query_name); + print_trace('find_next_qry()-'); + return TRUE; + end if; + + tab_no := get_qrys()(qry_no).base_tabs.next(tab_no); + end loop; + + qry_no := get_qrys().next(qry_no); + if (qry_no is not null) then + tab_no := get_qrys()(qry_no).base_tabs.first; + end if; + + end loop; + + print_trace('find_next_qry()-'); + return FALSE; +end find_next_qry; + + +-- +-- for each row fetched from flashback query, creates and executes LCRs +-- +-- NOTE: no lobs in this version +procedure build_and_process_lcrs(sql_cursor pls_integer, + num_cols pls_integer, + desc_table sys.dbms_sql.desc_tab, + source_dbname varchar2, + cmd_type varchar2, + obj_owner varchar2, + obj_name varchar2, + key_cols stmv_column_list) is + + num_rows number; + lcr sys.lcr$_row_record; + is_key_col stmv_num_list := stmv_num_list(0); + first_time boolean := TRUE; + +begin + print_trace('build_and_process_lcrs()+'); + print_trace('cmd_type='||cmd_type); + print_trace('obj_owner='||obj_owner); + print_trace('obj_name='||obj_name); + + -- set up is_key_col array + -- initialize + is_key_col.extend(num_cols-1,1); + -- set elements that are key cols + for i in 1..num_cols loop + for j in key_cols.first .. key_cols.last loop + if (key_cols(j) = desc_table(i).col_name) then + is_key_col(i) := 1; + exit; + end if; + end loop; + end loop; + + -- execute the select statement + num_rows := dbms_sql.execute(sql_cursor); + + lcr := sys.lcr$_row_record.construct( + source_database_name=>source_dbname, + command_type=>cmd_type, + object_owner=>obj_owner, + object_name=>obj_name, + old_values=>NULL, + new_values=>NULL); + + -- loop until no more rows are returned + while dbms_sql.fetch_rows(sql_cursor) > 0 loop + print_trace('fetched row'); + + streams_mv_refresh.get_column_values(sql_cursor, num_cols, desc_table, + is_key_col, lcr, cmd_type, + first_time); + + first_time := FALSE; + + streams_qry_lcr.process_lcr(lcr); + + end loop; + + print_trace('build_and_process_lcrs()-'); +end; + + +-- +-- +-- +procedure execute_delta_query(qry_idx pls_integer, + tab_idx pls_integer, + dml_type varchar2, + is_commit_query boolean, + commit_scn number, + rowids streams_mv_refresh.rowid_list) +is + + sql_stmt varchar2(32000); + sql_cursor pls_integer; + num_cols pls_integer; + desc_table sys.dbms_sql.desc_tab; + query_owner varchar2(30); + query_name varchar2(30); + key_cols stmv_column_list; + +begin + print_trace('execute_delta_query()+'); + + query_owner := get_qrys()(qry_idx).query_owner; + query_name := get_qrys()(qry_idx).query_name; + key_cols := get_qrys()(qry_idx).key_cols; + + sql_stmt := create_query(dml_type, qry_idx, tab_idx, is_commit_query); + sql_cursor := dbms_sql.open_cursor; + dbms_sql.parse(sql_cursor, sql_stmt, sys.dbms_sql.v7); + dbms_sql.describe_columns(sql_cursor, num_cols, desc_table); + + -- loop through the columns and do the define columns + streams_mv_refresh.define_columns(sql_cursor, num_cols, desc_table); + + -- bind the scn variable once + dbms_sql.bind_variable(sql_cursor, streams_qry_refresh.scn_bind, commit_scn); + + if (is_commit_query) then + build_and_process_lcrs( + sql_cursor, + num_cols, + desc_table, + streams_qry_refresh_adm.source_dbname, + dml_type, + query_owner, + query_name, + key_cols); + else + for i in rowids.first .. rowids.last loop + dbms_sql.bind_variable(sql_cursor, streams_qry_refresh.rowid_bind, + rowids(i)); + build_and_process_lcrs( + sql_cursor, + num_cols, + desc_table, + streams_qry_refresh_adm.source_dbname, + dml_type, + query_owner, + query_name, + key_cols); + + end loop; + end if; + + dbms_sql.close_cursor(sql_cursor); + print_trace('execute_delta_query()-'); + +exception + when others then + if dbms_sql.is_open(sql_cursor) then + dbms_sql.close_cursor(sql_cursor); + end if; + raise; +end; + + +-- +-- DML handler +-- +procedure source_dml_handler(lcr_anydata sys.anydata) is + + lcr sys.lcr$_row_record; + t pls_integer; + qry_i pls_integer := null; -- iterator + tab_i pls_integer := null; -- iterator + commit_scn number := null; + dml_type varchar2(10); + dml_code pls_integer; + ridval sys.anydata; + +BEGIN + print_trace('source_dml_handler()+'); + + t := lcr_anydata.getObject(lcr); + commit_scn := lcr.get_commit_scn(); + ridval := lcr.get_extra_attribute('row_id'); + if (ridval is null) then + raise_application_error(-20000, + 'supplemental logging missing for rowid on ' || + lcr.get_object_owner || '.' || lcr.get_object_name); + end if; + + print_trace('commit_scn='||commit_scn); + + -- + -- streams refresh codepath + -- + while find_next_qry(lcr.get_object_owner, lcr.get_object_name, + qry_i, tab_i) loop + -- skip this query if commit scn of this LCR <= the query's instantiation + -- scn + print_trace('query inst_scn=' || get_qrys()(qry_i).inst_scn); + if (commit_scn > get_qrys()(qry_i).inst_scn) then + + dml_type := lcr.get_command_type; + print_trace('command_type='||dml_type); + + if (dml_type = 'INSERT') then + dml_code := streams_qry_refresh.insert_dml; + elsif (dml_type = 'UPDATE') then + dml_code := streams_qry_refresh.update_dml; + elsif (dml_type = 'DELETE') then + dml_code := streams_qry_refresh.delete_dml; + else + dml_code := 0; + end if; + + -- add table to collection for commit-time processing + streams_mv_refresh.add_to_table_coll(lcr.get_object_owner, + lcr.get_object_name, + dml_code, + ridval.AccessURowid, + streams_qry_refresh.txn_tabs); + end if; + end loop; + + print_trace('source_dml_handler()-'); +end; + + +-- +-- pre-commit handler +-- +procedure source_commit_hdlr(commit_scn number) is + + qry_i pls_integer := null; -- iterator + tab_i pls_integer := null; -- iterator + lcr sys.lcr$_row_record; + dml_type pls_integer; + tab_owner varchar2(30); + tab_name varchar2(30); + has_deletes boolean; + has_inserts boolean; + +begin + print_trace('source_commit_hdlr()+'); + + -- streams-based refresh + if (streams_qry_refresh.txn_tabs.count > 0) then + print_trace('commit_scn='||commit_scn); + + for i in streams_qry_refresh.txn_tabs.first.. + streams_qry_refresh.txn_tabs.last loop + + tab_owner := streams_qry_refresh.txn_tabs(i).table_owner; + tab_name := streams_qry_refresh.txn_tabs(i).table_name; + has_deletes := streams_qry_refresh.txn_tabs(i).delete_rowids.count > 0; + has_inserts := streams_qry_refresh.txn_tabs(i).insert_rowids.count > 0; + + print_trace('table=' || tab_owner || '.' || tab_name); + + while find_next_qry(tab_owner, tab_name, qry_i, tab_i) loop + + print_trace('qry=' || get_qrys()(qry_i).query_owner || '.' || + get_qrys()(qry_i).query_name); + + print_trace('qry inst_scn=' || get_qrys()(qry_i).inst_scn); + if (commit_scn > get_qrys()(qry_i).inst_scn) then + + print_trace('delete phase:'); + if (has_deletes) then + execute_delta_query(qry_i, tab_i, 'DELETE', FALSE, commit_scn, + streams_qry_refresh.txn_tabs(i).delete_rowids); + end if; + if (has_inserts) then + execute_delta_query(qry_i, tab_i, 'DELETE', FALSE, commit_scn, + streams_qry_refresh.txn_tabs(i).insert_rowids); + end if; + + print_trace('insert phase:'); + if (has_deletes) then + execute_delta_query(qry_i, tab_i, 'UPDATE', FALSE, commit_scn, + streams_qry_refresh.txn_tabs(i).delete_rowids); + end if; + if (has_inserts) then + execute_delta_query(qry_i, tab_i, 'UPDATE', FALSE, commit_scn, + streams_qry_refresh.txn_tabs(i).insert_rowids); + end if; + + if (get_qrys()(qry_i).base_tabs(tab_i).commit_query is not null) then + print_trace('delete phase: commit_query'); + execute_delta_query(qry_i, tab_i, 'DELETE', TRUE, commit_scn,NULL); + + print_trace('insert phase: commit_query'); + execute_delta_query(qry_i, tab_i, 'UPDATE', TRUE, commit_scn,NULL); + end if; + end if; + end loop; + + end loop; + + -- reset tab_owners, tab_names collections + streams_qry_refresh.txn_tabs.delete; + + end if; + + print_trace('source_commit_hdlr()-'); +end; + +end streams_qry_refresh; +/ + +create or replace package body streams_qry_lcr as + +-- +-- apply the LCR +-- +procedure process_lcr(lcr sys.lcr$_row_record) is + + -- new exception raised during apply to replace ora-1403 + row_does_not_exist exception; + pragma exception_init(row_does_not_exist, -26787); + +begin + streams_qry_refresh.print_trace('process_lcr()+'); + + -- this function may be customized to call a different procedure + begin + lcr.execute(true); + streams_qry_refresh.print_trace('applied LCR'); + + exception + when DUP_VAL_ON_INDEX then + streams_qry_refresh.print_trace('DUP_VAL_ON_INDEX, type='|| + lcr.get_command_type); + + when NO_DATA_FOUND or row_does_not_exist then + streams_qry_refresh.print_trace('NO_DATA_FOUND, type='|| + lcr.get_command_type); + streams_mv_lcr.do_an_insert(lcr); + when others then + raise; + end; + + streams_qry_refresh.print_trace('process_lcr()-'); +end; + +end streams_qry_lcr; +/ diff --git a/strmqry1.sql b/strmqry1.sql new file mode 100644 index 0000000..6cf8c3e --- /dev/null +++ b/strmqry1.sql @@ -0,0 +1,507 @@ +Rem +Rem $Header: rdbms/demo/strmqry1.sql /main/6 2009/06/30 03:03:52 snalla Exp $ +Rem +Rem strmqry1.sql +Rem +Rem Copyright (c) 2006, 2009, Oracle and/or its affiliates. +Rem All rights reserved. +Rem +Rem NAME +Rem strmqry1.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem snalla 06/23/09 - fix ORA-01940: cannot drop a user that is +Rem currently connected +Rem davzhang 09/27/06 - grant create view explicitly +Rem wesmith 06/23/06 - register_query: add parameter queue_name +Rem wesmith 06/12/06 - move include_extra_attribute() call +Rem liwong 05/15/06 - sync capture cleanup +Rem wesmith 01/19/06 - Created +Rem + +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 10000 +SET SERVEROUTPUT ON + +COLUMN SRC_LONG_CNAME FORMAT A15 +COLUMN SCHEMA_NAME FORMAT A15 +COLUMN OBJECT_NAME FORMAT A15 +COLUMN STREAMS_TYPE HEADING 'STREAMS_TYPE' FORMAT A19 + +variable site1 varchar2(80); + +-- grant necessary privileges for streams admin +connect system/manager + +drop user stradm cascade; +grant dba to stradm identified by stradm; +grant execute on SYS.DBMS_SYSTEM to stradm; +begin + dbms_streams_auth.grant_admin_privilege( + grantee => 'stradm', + grant_privileges => true); +end; +/ + +-- create user for queries +drop user sqst cascade; +grant connect, resource to sqst identified by sqst; +grant create materialized view, create view to sqst; + +connect sqst/sqst + +-- create base tables and load +set echo off +@strmmv2s.sql +set echo on + +-- subquery (1 level) +create view orders_v (o_id, c_id, ol_num) as +select o.o_id, o.c_id, o.ol_num from sqst.orders o + where exists + (select c.c_id from sqst.customer c + where c.zip >= 19555 and o.c_id = c.c_id); + +create table orders_mv as +select o.o_id, o.c_id, o.ol_num from sqst.orders o + where exists + (select c.c_id from sqst.customer c + where c.zip >= 19555 and o.c_id = c.c_id); + +alter table orders_mv add primary key (o_id); + +-- another subquery (2-levels) +create view oline_v (ol_id, o_id, i_id) as + select ol.ol_id, ol.o_id, ol.i_id from sqst.order_line ol + where exists + (select o.o_id from sqst.orders o + where ol.o_id = o.o_id + and exists + (select c.c_id from sqst.customer c + where c.zip >= 19555 and o.c_id = c.c_id)); + +create table oline_mv as + select ol.ol_id, ol.o_id, ol.i_id from sqst.order_line ol + where exists + (select o.o_id from sqst.orders o + where ol.o_id = o.o_id + and exists + (select c.c_id from sqst.customer c + where c.zip >= 19555 and o.c_id = c.c_id)); + +alter table oline_mv add primary key (ol_id); + +-- join view +create view orders_v2 as +select o.o_id, o.c_id, o.ol_num, o.rowid o_rid, c.zip, c.rowid c_rid +from sqst.orders o, sqst.customer c +where o.c_id = c.c_id(+) and c.zip(+) >= 19555; + +create table orders_mv2 as +select o.o_id, o.c_id, o.ol_num, o.rowid o_rid, c.zip, c.rowid c_rid +from sqst.orders o, sqst.customer c +where o.c_id = c.c_id(+) and c.zip(+) >= 19555; + +-- aggregate +create view sales_region_v as +select s.region, sum(s.amt) sales +from sqst.sales s +group by s.region; + +create table sales_region_mv as +select s.region, sum(s.amt) sales +from sqst.sales s +group by s.region; + + +-- create supporting objects and packages for streams refresh metadata +connect stradm/stradm +set echo off +@strmmvp2 +@strmqp1 +set echo on + +-- +-- streams setup +-- +begin + dbms_streams_adm.set_up_queue + (queue_user => 'stradm', queue_name => 'QRY_MASTER_Q', + queue_table => 'QRY_MASTER_QT'); +end; +/ + +begin + streams_qry_refresh_adm.register_query( + query_owner=>'SQST', query_name=>'ORDERS_MV', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER', + queue_name=>'QRY_MASTER_Q', + base_tables=> +stq_table_list( + stq_table_t('SQST', 'ORDERS', + 'select o.o_id, o.c_id, o.ol_num from sqst.orders as of scn(:scn) o + where exists + (select c.c_id from sqst.customer as of scn(:scn) c + where c.zip >= 19555 and o.c_id = c.c_id) + and o.rowid = :rid', null), + stq_table_t('SQST', 'customer', + 'select o.o_id, o.c_id, o.ol_num from sqst.orders as of scn(:scn) o + where exists + (select c.c_id from sqst.customer as of scn(:scn) c + where c.zip >= 19555 + and o.c_id = c.c_id + and c.rowid = :rid)', null))); +end; +/ + +-- need set_key_columns for this query table since there is no pk +exec dbms_apply_adm.set_key_columns('SQST.ORDERS_MV2', 'o_rid, c_rid'); + +-- register queries for streams refresh +begin + streams_qry_refresh_adm.register_query( + query_owner=>'SQST', query_name=>'ORDERS_MV2', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER', + base_tables=> +stq_table_list( + stq_table_t('SQST', 'ORDERS', + 'select o.o_id, o.c_id, o.ol_num, o.rowid o_rid, c.zip, c.rowid c_rid + from sqst.orders as of scn(:scn) o, sqst.customer as of scn(:scn) c + where o.c_id = c.c_id(+) and c.zip(+) >= 19555 + and o.rowid = :rid', null), + stq_table_t('SQST', 'customer', + 'select o.o_id, o.c_id, o.ol_num, o.rowid o_rid, c.zip, c.rowid c_rid + from sqst.orders as of scn(:scn) o, sqst.customer as of scn(:scn) c + where o.c_id = c.c_id(+) and c.zip(+) >= 19555 + and c.rowid = :rid', + 'select o.o_id, o.c_id, o.ol_num, o.rowid o_rid, c.zip, c.rowid c_rid + from sqst.orders as of scn(:scn) o, sqst.customer as of scn(:scn) c + where not exists (select 1 from sqst.customer as of scn(:scn) c + where o.c_id = c.c_id and c.zip >= 19555) + and o.c_id = c.c_id(+) and c.zip(+) >= 19555 + and c.rowid is null'))); +end; +/ + +begin + streams_qry_refresh_adm.register_query( + query_owner=>'SQST', query_name=>'OLINE_MV', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER', + base_tables=> +stq_table_list( + stq_table_t('SQST', 'ORDER_LINE', + 'select ol.ol_id, ol.o_id, ol.i_id from sqst.order_line as of scn(:scn) ol + where exists + (select o.o_id from sqst.orders as of scn(:scn) o + where ol.o_id = o.o_id + and exists + (select c.c_id from sqst.customer as of scn(:scn) c + where c.zip >= 19555 and o.c_id = c.c_id)) + and ol.rowid = :rid', null), + stq_table_t('SQST', 'orders', + 'select ol.ol_id, ol.o_id, ol.i_id from sqst.order_line as of scn(:scn) ol + where exists + (select o.o_id from sqst.orders as of scn(:scn) o + where ol.o_id = o.o_id + and exists + (select c.c_id from sqst.customer as of scn(:scn) c + where c.zip >= 19555 and o.c_id = c.c_id) + and o.rowid = :rid)', null), + stq_table_t('SQST', 'CUSTOMER', + 'select ol.ol_id, ol.o_id, ol.i_id from sqst.order_line as of scn(:scn) ol + where exists + (select o.o_id from sqst.orders as of scn(:scn) o + where ol.o_id = o.o_id + and exists + (select c.c_id from sqst.customer as of scn(:scn) c + where c.zip >= 19555 + and o.c_id = c.c_id + and c.rowid = :rid))', null))); +end; +/ + +-- need set_key_columns for this query table since there is no pk +exec dbms_apply_adm.set_key_columns('SQST.sales_region_mv', 'region'); + +begin + streams_qry_refresh_adm.register_query( + query_owner=>'SQST', query_name=>'sales_region_mv', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER', + base_tables=> +stq_table_list( + stq_table_t('SQST', 'sales', + 'select s.region, sum(s.amt) sales + from sqst.sales as of scn(:scn) s, sqst.sales as of scn(:scn) s2 + where s.region = s2.region and s2.rowid = :rid + group by s.region', + null))); +end; +/ + + +connect stradm/stradm +exec dbms_capture_adm.start_capture('CAPTURE'); + +exec dbms_apply_adm.set_parameter('APPLY_MV_MASTER','DISABLE_ON_ERROR','N'); + +-- assign precommit handler to apply process +begin + dbms_apply_adm.alter_apply( + apply_name => 'APPLY_MV_MASTER', + precommit_handler => 'streams_qry_refresh.source_commit_hdlr'); +end; +/ +exec dbms_apply_adm.start_apply('APPLY_MV_MASTER'); + +-- check streams metadata +select apply_name, status from dba_apply order by apply_name; +select capture_name, status from dba_capture order by 1,2; + +select streams_type, streams_name, table_owner, table_name, + rule_owner, rule_name +from dba_streams_table_rules +where streams_name in ('CAPTURE', 'APPLY_MV_MASTER') +order by streams_type, streams_name, table_owner, table_name; + +select source_object_owner, source_object_name, source_database, + instantiation_scn +from dba_apply_instantiated_objects +order by source_database, source_object_owner, source_object_name; + +select object_owner, object_name, operation_name, user_procedure +from dba_apply_dml_handlers +where apply_name = 'APPLY_MV_MASTER' +order by object_owner, object_name, operation_name; + +-- check query registration metadata +select query_owner, query_name from stq_reg order by query_owner, query_name; + +-- do some DMLs +connect sqst/sqst +set serveroutput on +update customer set zip = 0; +update order_line set i_id = 101 where ol_id < 800; +insert into sales values('West', 100); +insert into sales values('East', 50); +commit; + +-- wait for streams to finish +set timing on +exec verify_tables('orders_v','orders_mv'); +exec verify_tables('orders_v2','orders_mv2'); +exec verify_tables('oline_v','oline_mv'); +exec verify_tables('sales_region_v','sales_region_mv'); +set timing off + +-- 0 rows expected +select o_id, c_id, ol_num from orders_mv order by o_id; +select ol_id, o_id, i_id from oline_mv order by ol_id; + +select region, sales from sales_region_mv order by region; + +update customer set zip = 19555 where c_id > 5; +update order_line set i_id = 61 where ol_id >= 800; +-- update primary key +update order_line set ol_id = 599 where ol_id = 522; +commit; +update sales set amt=null where region='West' and amt = 100; +insert into sales values('East', 150); +commit; + +-- wait for streams to finish +set timing on +exec verify_tables('orders_v','orders_mv'); +exec verify_tables('orders_v2','orders_mv2'); +exec verify_tables('oline_v','oline_mv'); +exec verify_tables('sales_region_v','sales_region_mv'); +set timing off + +select o_id, c_id, ol_num from orders_mv order by o_id; +select ol_id, o_id, i_id from oline_mv order by ol_id; +select region, sales from sales_region_mv order by region; + +update customer set zip = -19555 where zip > 19455; +commit; +update sales set amt=250 where region='East' and amt=150; +commit; + +-- wait for streams to finish +set timing on +exec verify_tables('orders_v','orders_mv'); +exec verify_tables('orders_v2','orders_mv2'); +exec verify_tables('oline_v','oline_mv'); +exec verify_tables('sales_region_v','sales_region_mv'); +set timing off + +--0 rows +select o_id, c_id, ol_num from orders_mv order by o_id; +--0 rows +select ol_id, o_id, i_id from oline_mv order by ol_id; + +select region, sales from sales_region_mv order by region; + +update customer set zip = 19556 where zip = -19555; +commit; +delete from sales; +commit; + +-- wait for streams to finish +set timing on +exec verify_tables('orders_v','orders_mv'); +exec verify_tables('orders_v2','orders_mv2'); +exec verify_tables('oline_v','oline_mv'); +exec verify_tables('sales_region_v','sales_region_mv'); +set timing off + +select o_id, c_id, ol_num from orders_mv order by o_id; +select ol_id, o_id, i_id from oline_mv order by ol_id; +select region, sales from sales_region_mv order by region; + +delete from order_line where o_id = 71; +delete from orders where c_id = 6; +delete from customer where c_id = 9; +commit; + +-- wait for streams to finish +set timing on +exec verify_tables('orders_v','orders_mv'); +exec verify_tables('orders_v2','orders_mv2'); +exec verify_tables('oline_v','oline_mv'); +set timing off + +select o_id, c_id, ol_num from orders_mv order by o_id; +select ol_id, o_id, i_id from oline_mv order by ol_id; +select region, sales from sales_region_mv order by region; + +insert into customer (c_id, zip) values (101, 29555); +insert into orders (o_id, c_id, ol_num) values (1001, 101, 11); +insert into orders (o_id, c_id, ol_num) values (1002, 101, 11); +delete from orders where o_id < 22; +update orders set c_id = 7 where c_id = 5; +update order_line set o_id = 2 where o_id = 82; +commit; + +-- wait for streams to finish +set timing on +exec verify_tables('orders_v','orders_mv'); +exec verify_tables('orders_v2','orders_mv2'); +exec verify_tables('oline_v','oline_mv'); +set timing off + +select o_id, c_id, ol_num from orders_mv order by o_id; +select ol_id, o_id, i_id from oline_mv order by ol_id; +select region, sales from sales_region_mv order by region; + +-- Cleanup +connect stradm/stradm +exec dbms_apply_adm.stop_apply('APPLY_MV_MASTER'); + +-- unregister one query +begin + streams_qry_refresh_adm.unregister_query( + query_owner=>'SQST', query_name=>'OLINE_MV', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER'); +end; +/ + +-- check streams metadata +select streams_type, streams_name, table_owner, table_name, + rule_owner, rule_name +from dba_streams_table_rules +where streams_name in ('CAPTURE', 'APPLY_MV_MASTER') +order by streams_type, streams_name, table_owner, table_name; + +select source_object_owner, source_object_name, source_database, + instantiation_scn +from dba_apply_instantiated_objects +order by source_database, source_object_owner, source_object_name; + +select object_owner, object_name, operation_name, user_procedure +from dba_apply_dml_handlers +where apply_name = 'APPLY_MV_MASTER' +order by object_owner, object_name, operation_name; + +select query_owner, query_name from stq_reg order by query_owner, query_name; + +-- unregister more queries +begin + streams_qry_refresh_adm.unregister_query( + query_owner=>'SQST', query_name=>'ORDERS_MV', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER'); +end; +/ +begin + streams_qry_refresh_adm.unregister_query( + query_owner=>'SQST', query_name=>'ORDERS_MV2', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER'); +end; +/ +begin + streams_qry_refresh_adm.unregister_query( + query_owner=>'SQST', query_name=>'sales_region_mv', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER'); +end; +/ + +-- check streams metadata +select streams_type, streams_name, table_owner, table_name, + rule_owner, rule_name +from dba_streams_table_rules +where streams_name in ('CAPTURE', 'APPLY_MV_MASTER') +order by streams_type, streams_name, table_owner, table_name; + +select source_object_owner, source_object_name, source_database, + instantiation_scn +from dba_apply_instantiated_objects +order by source_database, source_object_owner, source_object_name; + +select object_owner, object_name, operation_name, user_procedure +from dba_apply_dml_handlers +where apply_name = 'APPLY_MV_MASTER' +order by object_owner, object_name, operation_name; + +select query_owner, query_name from stq_reg order by query_owner, query_name; + +-- remove streams configuration +begin + streams_qry_refresh_adm.remove_streams_qry_refresh( + 'CAPTURE', 'APPLY_MV_MASTER'); +end; +/ + +select 1 from dba_capture where capture_name = 'CAPTURE'; +select 1 from dba_apply where apply_name = 'APPLY_MV_MASTER'; + +select streams_type, streams_name, table_owner, table_name, + rule_owner, rule_name +from dba_streams_table_rules +where streams_name in ('CAPTURE', 'APPLY_MV_MASTER'); + +select source_object_owner, source_object_name, source_database, + instantiation_scn +from dba_apply_instantiated_objects +order by source_database, source_object_owner, source_object_name; + +select object_owner, object_name, operation_name, user_procedure +from dba_apply_dml_handlers +where apply_name = 'APPLY_MV_MASTER' +order by object_owner, object_name, operation_name; + +-- cleanup +connect system/manager +set serveroutput on +exec wait_session ('stradm'); +drop user stradm cascade ; +exec wait_session ('sqst'); +drop user sqst cascade ; diff --git a/strmqry1README.txt b/strmqry1README.txt new file mode 100644 index 0000000..60de75a --- /dev/null +++ b/strmqry1README.txt @@ -0,0 +1,273 @@ +/ +/ $Header: strmqry1README.txt 08-sep-2006.14:04:24 wesmith Exp $ +/ +/ strmqry1README.txt +/ +/ Copyright (c) 2006, Oracle. All Rights Reserved. +/ +/ NAME +/ strmqry1README.txt - +/ +/ DESCRIPTION +/ +/ +/ NOTES +/ +/ +/ MODIFIED (MM/DD/YY) +/ wesmith 06/23/06 - register_query: add parameter queue_name +/ wesmith 01/24/06 - Creation +/ + +register_query +-------------- +for streams-based refresh of arbitrary queries that may not be +fast-refreshable as an MV. + + +APIs +---- + +-- sets up a query for streams-driven refresh +procedure register_query(query_owner varchar2, + query_name varchar2, + base_tables stq_table_list, + capture_name varchar2 := 'CAPTURE_QRY_MASTER', + apply_name varchar2 := 'APPLY_QRY_MASTER', + queue_name varchar2 := NULL) + + + +Parameters +---------- +query_owner, query_name: query to register (actually the container table + for the query, which must exist) + +base_tables: collection of base tables referenced in the query, along with + the queries required to incrementally maintain the query with respect + to each base table. This parameter is of type stq_table_list which is + a nested table of the type stq_table_t: + +create or replace type stq_table_list is table of stq_table_t +/ + +create or replace type stq_table_t as object ( + table_owner varchar2(30), /* base table owner */ + table_name varchar2(30), /* base table name */ + refresh_query varchar2(4000), /* query used by the pre-commit handler */ + commit_query varchar2(4000) /* query used by the pre-commit handler */ +) +/ + +For each base table in the query, create a stq_table_t element. +refresh_query and commit_query will be used by the pre-commit handler to +incrementally maintain the query. + +capture_name: + name of the capture process to use. It is recommended to specify a capture + that does not already exist. + +apply_name: + name of the apply process to use. It is recommended to specify an apply + that does not already exist. + +queue_name: + name of the streams queue associated with the capture and apply process. + If NULL, then the queue_name is derived from the capture process + metadata, if it exists. + + +Notes: + +- base_tables collection element: +refresh_query and commit_query are both derived from the orignal query. +Both should have a flashback expression, 'as of scn(:scn)', for each table +in the original query. + +In addition, refresh_query should contain an additional rowid match +predicate 'and ..rowid = :rid', where +. is the current base table. In some cases, +the base table must be added again to the original query in order to +match the rowid (ex: query with aggregates). + +refresh_query is used to incrementally maintain the registered query +on a per-LCR basis. + +commit_query is used to incrementally maintain the registered query +on a per-transaction basis. A commit_query is required for certain +types of queries that cannot be properly maintained with just +a refresh_query. For example, a query with outer joins will need to +delete anti-join rows no longer in the query, and/or insert anti-join rows +that are new to the query. These queries require a 'rowid is null' +predicate instead of a rowid match predicate. + +- refresh algorithm +If a user transaction modifies a table that a registered query references, +then for each LCR for that table, the pre-commit handler constructs the +following queries: + +a. refresh_query (binds: scn=-1, rid=) + minus + refresh_query (binds: scn=, rid=) + +These are rows that no longer exist in the query. DELETE LCRs will be +constructed and executed on the query table. + +b. refresh_query (binds: scn=, rid=) + minus + refresh_query (binds: scn=-1, rid=) + +These are rows that are new to the query. UPDATE LCRs will be +constructed and executed (upsert performed) on the query table. + +If a commit_query was registered for a table that was modified in the +transaction, the pre-commit handler constructs the following +queries: + +a. commit_query (binds: scn=-1) + minus + commit_query (binds: scn=) + +These are rows that no longer exist in the query. DELETE LCRs will be +constructed and executed on the query table. + +b. commit_query (binds: scn=) + minus + commit_query (binds: scn=-1) + +These are rows that are new to the query. UPDATE LCRs will be +constructed and executed (upsert performed) on the query table. + + +Examples: + +1. subquery +create table customer( + c_id number primary key, + zip number, + c_name varchar(30)); + +create table orders( + o_id number primary key, + c_id number, + ol_num number default 0); + +-- query table +create table orders_mv as +select o.o_id, o.c_id, o.ol_num from sqst.orders o + where exists + (select c.c_id from sqst.customer c + where c.zip >= 19555 and o.c_id = c.c_id); + +alter table orders_mv add primary key (o_id); + +begin + streams_qry_refresh_adm.register_query( + query_owner=>'SQST', query_name=>'ORDERS_MV', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER', + base_tables=> +stq_table_list( + stq_table_t('SQST', 'ORDERS', + 'select o.o_id, o.c_id, o.ol_num from sqst.orders as of scn(:scn) o + where exists + (select c.c_id from sqst.customer as of scn(:scn) c + where c.zip >= 19555 and o.c_id = c.c_id) + and o.rowid = :rid', null), + stq_table_t('SQST', 'customer', + 'select o.o_id, o.c_id, o.ol_num from sqst.orders as of scn(:scn) o + where exists + (select c.c_id from sqst.customer as of scn(:scn) c + where c.zip >= 19555 + and o.c_id = c.c_id + and c.rowid = :rid)', null))); +end; +/ + +Notes: +- no commit_query needed for this query + + +2. join + +-- query table +create table orders_mv2 as +select o.o_id, o.c_id, o.ol_num, o.rowid o_rid, c.zip, c.rowid c_rid +from sqst.orders o, sqst.customer c +where o.c_id = c.c_id(+) and c.zip(+) >= 19555; + +-- need set_key_columns for this query table since there is no pk +exec dbms_apply_adm.set_key_columns('SQST.ORDERS_MV2', 'o_rid, c_rid'); + +begin + streams_qry_refresh_adm.register_query( + query_owner=>'SQST', query_name=>'ORDERS_MV2', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER', + base_tables=> +stq_table_list( + stq_table_t('SQST', 'ORDERS', + 'select o.o_id, o.c_id, o.ol_num, o.rowid o_rid, c.zip, c.rowid c_rid + from sqst.orders as of scn(:scn) o, sqst.customer as of scn(:scn) c + where o.c_id = c.c_id(+) and c.zip(+) >= 19555 + and o.rowid = :rid', + 'select o.o_id, o.c_id, o.ol_num, o.rowid o_rid, c.zip, c.rowid c_rid + from sqst.orders as of scn(:scn) o, sqst.customer as of scn(:scn) c + where o.c_id = c.c_id(+) and c.zip(+) >= 19555 + and o.rowid is null'), + stq_table_t('SQST', 'customer', + 'select o.o_id, o.c_id, o.ol_num, o.rowid o_rid, c.zip, c.rowid c_rid + from sqst.orders as of scn(:scn) o, sqst.customer as of scn(:scn) c + where o.c_id = c.c_id(+) and c.zip(+) >= 19555 + and c.rowid = :rid', + 'select o.o_id, o.c_id, o.ol_num, o.rowid o_rid, c.zip, c.rowid c_rid + from sqst.orders as of scn(:scn) o, sqst.customer as of scn(:scn) c + where o.c_id = c.c_id(+) and c.zip(+) >= 19555 + and c.rowid is null'))); +end; +/ + +Notes: +- a commit query is required for this join query with outer joins to + deal with new/old antijoin rows in the query. For example, if there is + no customer row with matching c_id for an order row, there will be an + antijoin row for that o_id. If a row with matching c_id is now inserted + into customer, the antijoin row must be replaced with a join row. + Since c_rid is null for the antijoin row, it cannot be handled by + refresh_query (which uses rowid match predicate) and therefore must be + done by commit_query. + + +3. aggregate +create table sales (region varchar2(10), amt number); + +-- query table +create table sales_region_mv as +select s.region, sum(s.amt) sales +from sqst.sales s +group by s.region; + +-- need set_key_columns for this query table since there is no pk +exec dbms_apply_adm.set_key_columns('SQST.sales_region_mv', 'region'); + +begin + streams_qry_refresh_adm.register_query( + query_owner=>'SQST', query_name=>'sales_region_mv', + capture_name=>'CAPTURE', apply_name=>'APPLY_MV_MASTER', + base_tables=> +stq_table_list( + stq_table_t('SQST', 'sales', + 'select s.region, sum(s.amt) sales + from sqst.sales as of scn(:scn) s, sqst.sales as of scn(:scn) s2 + where s.region = s2.region and s2.rowid = :rid + group by s.region', + null))); +end; +/ + +Notes: +- another join of sales is required to add a rowid match predicate, + where the join clause is on the grouping columns for sales (region) +- no additional aggregates is required (count(*), count(sales)) as would + be if an MV is created using the query. +- no commit_query is required for this query + + diff --git a/summit2.sql b/summit2.sql new file mode 100644 index 0000000..0c400de --- /dev/null +++ b/summit2.sql @@ -0,0 +1,1286 @@ +rem +rem $Header: summit2.sql 27-jun-2000.12:30:22 slari Exp $ +rem +rem Copyright (c) 1991, 2000 Oracle Corporation. All rights reserved. +rem +rem NAME +rem summit2.sql - +rem DESCRIPTION +rem +rem RETURNS +rem +rem FUNCTION +rem Create and populate tables and sequences to support the Summit +rem Sporting Goods business scenario. These objects and data are used +rem in several Oracle classes and demonstration files. +rem +rem MODIFIED (MM/DD/YY) +rem slari 06/27/00 - b1138912: remove duplicate contents +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem GDURHAM Mar 15, 1993 -- Created + +set feedback off +prompt Creating and populating tables and sequences. Please wait. + +rem Create sequences. +rem Starting values for sequences begin at the existing maxima for +rem existing primary key values, plus increments. + +CREATE SEQUENCE s_customer_id + MINVALUE 1 + MAXVALUE 9999999 + INCREMENT BY 1 + START WITH 216 + NOCACHE + NOORDER + NOCYCLE; +CREATE SEQUENCE s_dept_id + MINVALUE 1 + MAXVALUE 9999999 + INCREMENT BY 1 + START WITH 51 + NOCACHE + NOORDER + NOCYCLE; +CREATE SEQUENCE s_emp_id + MINVALUE 1 + MAXVALUE 9999999 + INCREMENT BY 1 + START WITH 26 + NOCACHE + NOORDER + NOCYCLE; +CREATE SEQUENCE s_image_id + MINVALUE 1 + MAXVALUE 9999999 + INCREMENT BY 1 + START WITH 1981 + NOCACHE + NOORDER + NOCYCLE; +CREATE SEQUENCE s_longtext_id + MINVALUE 1 + MAXVALUE 9999999 + INCREMENT BY 1 + START WITH 1369 + NOCACHE + NOORDER + NOCYCLE; +CREATE SEQUENCE s_ord_id + MINVALUE 1 + MAXVALUE 9999999 + INCREMENT BY 1 + START WITH 113 + NOCACHE + NOORDER + NOCYCLE; +CREATE SEQUENCE s_product_id + MINVALUE 1 + MAXVALUE 9999999 + INCREMENT BY 1 + START WITH 50537 + NOCACHE + NOORDER + NOCYCLE; +CREATE SEQUENCE s_region_id + MINVALUE 1 + MAXVALUE 9999999 + INCREMENT BY 1 + START WITH 6 + NOCACHE + NOORDER + NOCYCLE; +CREATE SEQUENCE s_warehouse_id + MINVALUE 1 + MAXVALUE 9999999 + INCREMENT BY 1 + START WITH 10502 + NOCACHE + NOORDER + NOCYCLE; + + +rem Create and populate tables. + +CREATE TABLE s_customer +(id NUMBER(7) + CONSTRAINT s_customer_id_nn NOT NULL, + name VARCHAR2(50) + CONSTRAINT s_customer_name_nn NOT NULL, + phone VARCHAR2(25), + address VARCHAR2(400), + city VARCHAR2(30), + state VARCHAR2(20), + country VARCHAR2(30), + zip_code VARCHAR2(75), + credit_rating VARCHAR2(9), + sales_rep_id NUMBER(7), + region_id NUMBER(7), + comments VARCHAR2(255), + CONSTRAINT s_customer_id_pk PRIMARY KEY (id), + CONSTRAINT s_customer_credit_rating_ck + CHECK (credit_rating IN ('EXCELLENT', 'GOOD', 'POOR'))); + +INSERT INTO s_customer VALUES ( + 201, 'Unisports', '55-2066101', + '72 Via Bahia', 'Sao Paolo', NULL, 'Brazil', NULL, + 'EXCELLENT', 12, 2, NULL); +INSERT INTO s_customer VALUES ( + 202, 'OJ Atheletics', '81-20101', + '6741 Takashi Blvd.', 'Osaka', NULL, 'Japan', NULL, + 'POOR', 14, 4, NULL); +INSERT INTO s_customer VALUES ( + 203, 'Delhi Sports', '91-10351', + '11368 Chanakya', 'New Delhi', NULL, 'India', NULL, + 'GOOD', 14, 4, NULL); +INSERT INTO s_customer VALUES ( + 204, 'Womansport', '1-206-104-0103', + '281 King Street', 'Seattle', 'Washington', 'USA', NULL, + 'EXCELLENT', 11, 1, NULL); +INSERT INTO s_customer VALUES ( + 205, 'Kam''s Sporting Goods', '852-3692888', + '15 Henessey Road', 'Hong Kong', NULL, NULL, NULL, + 'EXCELLENT', 15, 4, NULL); +INSERT INTO s_customer VALUES ( + 206, 'Sportique', '33-2257201', + '172 Rue de Rivoli', 'Cannes', NULL, 'France', NULL, + 'EXCELLENT', 15, 5, NULL); +INSERT INTO s_customer VALUES ( + 207, 'Sweet Rock Sports', '234-6036201', + '6 Saint Antoine', 'Lagos', NULL, 'Nigeria', NULL, + 'GOOD', NULL, 3, NULL); +INSERT INTO s_customer VALUES ( + 208, 'Muench Sports', '49-527454', + '435 Gruenestrasse', 'Stuttgart', NULL, 'Germany', NULL, + 'GOOD', 15, 5, NULL); +INSERT INTO s_customer VALUES ( + 209, 'Beisbol Si!', '809-352689', + '792 Playa Del Mar', 'San Pedro de Macon''s', NULL, 'Dominican Republic', + NULL, 'EXCELLENT', 11, 1, NULL); +INSERT INTO s_customer VALUES ( + 210, 'Futbol Sonora', '52-404562', + '3 Via Saguaro', 'Nogales', NULL, 'Mexico', NULL, + 'EXCELLENT', 12, 2, NULL); +INSERT INTO s_customer VALUES ( + 211, 'Kuhn''s Sports', '42-111292', + '7 Modrany', 'Prague', NULL, 'Czechoslovakia', NULL, + 'EXCELLENT', 15, 5, NULL); +INSERT INTO s_customer VALUES ( + 212, 'Hamada Sport', '20-1209211', + '57A Corniche', 'Alexandria', NULL, 'Egypt', NULL, + 'EXCELLENT', 13, 3, NULL); +INSERT INTO s_customer VALUES ( + 213, 'Big John''s Sports Emporium', '1-415-555-6281', + '4783 18th Street', 'San Francisco', 'CA', 'USA', NULL, + 'EXCELLENT', 11, 1, NULL); +INSERT INTO s_customer VALUES ( + 214, 'Ojibway Retail', '1-716-555-7171', + '415 Main Street', 'Buffalo', 'NY', 'USA', NULL, + 'POOR', 11, 1, NULL); +INSERT INTO s_customer VALUES ( + 215, 'Sporta Russia', '7-3892456', + '6000 Yekatamina', 'Saint Petersburg', NULL, 'Russia', NULL, + 'POOR', 15, 5, NULL); +COMMIT; + + +CREATE TABLE s_dept +(id NUMBER(7) + CONSTRAINT s_dept_id_nn NOT NULL, + name VARCHAR2(25) + CONSTRAINT s_dept_name_nn NOT NULL, + region_id NUMBER(7), + CONSTRAINT s_dept_id_pk PRIMARY KEY (id), + CONSTRAINT s_dept_name_region_id_uk UNIQUE (name, region_id)); + +INSERT INTO s_dept VALUES ( + 10, 'Finance', 1); +INSERT INTO s_dept VALUES ( + 31, 'Sales', 1); +INSERT INTO s_dept VALUES ( + 32, 'Sales', 2); +INSERT INTO s_dept VALUES ( + 33, 'Sales', 3); +INSERT INTO s_dept VALUES ( + 34, 'Sales', 4); +INSERT INTO s_dept VALUES ( + 35, 'Sales', 5); +INSERT INTO s_dept VALUES ( + 41, 'Operations', 1); +INSERT INTO s_dept VALUES ( + 42, 'Operations', 2); +INSERT INTO s_dept VALUES ( + 43, 'Operations', 3); +INSERT INTO s_dept VALUES ( + 44, 'Operations', 4); +INSERT INTO s_dept VALUES ( + 45, 'Operations', 5); +INSERT INTO s_dept VALUES ( + 50, 'Administration', 1); +COMMIT; + + +CREATE TABLE s_emp +(id NUMBER(7) + CONSTRAINT s_emp_id_nn NOT NULL, + last_name VARCHAR2(25) + CONSTRAINT s_emp_last_name_nn NOT NULL, + first_name VARCHAR2(25), + userid VARCHAR2(8), + start_date DATE, + comments VARCHAR2(255), + manager_id NUMBER(7), + title VARCHAR2(25), + dept_id NUMBER(7), + salary NUMBER(11, 2), + commission_pct NUMBER(4, 2), + CONSTRAINT s_emp_id_pk PRIMARY KEY (id), + CONSTRAINT s_emp_userid_uk UNIQUE (userid), + CONSTRAINT s_emp_commission_pct_ck + CHECK (commission_pct IN (10, 12.5, 15, 17.5, 20))); + +INSERT INTO s_emp VALUES ( + 1, 'Velasquez', 'Carmen', 'cvelasqu', + to_date('03-MAR-90 8:30', 'dd-mon-yy hh24:mi'), NULL, NULL, 'President', + 50, 2500, NULL); +INSERT INTO s_emp VALUES ( + 2, 'Ngao', 'LaDoris', 'lngao', + '08-MAR-90', NULL, 1, 'VP, Operations', + 41, 1450, NULL); +INSERT INTO s_emp VALUES ( + 3, 'Nagayama', 'Midori', 'mnagayam', + '17-JUN-91', NULL, 1, 'VP, Sales', + 31, 1400, NULL); +INSERT INTO s_emp VALUES ( + 4, 'Quick-To-See', 'Mark', 'mquickto', + '07-APR-90', NULL, 1, 'VP, Finance', + 10, 1450, NULL); +INSERT INTO s_emp VALUES ( + 5, 'Ropeburn', 'Audry', 'aropebur', + '04-MAR-90', NULL, 1, 'VP, Administration', + 50, 1550, NULL); +INSERT INTO s_emp VALUES ( + 6, 'Urguhart', 'Molly', 'murguhar', + '18-JAN-91', NULL, 2, 'Warehouse Manager', + 41, 1200, NULL); +INSERT INTO s_emp VALUES ( + 7, 'Menchu', 'Roberta', 'rmenchu', + '14-MAY-90', NULL, 2, 'Warehouse Manager', + 42, 1250, NULL); +INSERT INTO s_emp VALUES ( + 8, 'Biri', 'Ben', 'bbiri', + '07-APR-90', NULL, 2, 'Warehouse Manager', + 43, 1100, NULL); +INSERT INTO s_emp VALUES ( + 9, 'Catchpole', 'Antoinette', 'acatchpo', + '09-FEB-92', NULL, 2, 'Warehouse Manager', + 44, 1300, NULL); +INSERT INTO s_emp VALUES ( + 10, 'Havel', 'Marta', 'mhavel', + '27-FEB-91', NULL, 2, 'Warehouse Manager', + 45, 1307, NULL); +INSERT INTO s_emp VALUES ( + 11, 'Magee', 'Colin', 'cmagee', + '14-MAY-90', NULL, 3, 'Sales Representative', + 31, 1400, 10); +INSERT INTO s_emp VALUES ( + 12, 'Giljum', 'Henry', 'hgiljum', + '18-JAN-92', NULL, 3, 'Sales Representative', + 32, 1490, 12.5); +INSERT INTO s_emp VALUES ( + 13, 'Sedeghi', 'Yasmin', 'ysedeghi', + '18-FEB-91', NULL, 3, 'Sales Representative', + 33, 1515, 10); +INSERT INTO s_emp VALUES ( + 14, 'Nguyen', 'Mai', 'mnguyen', + '22-JAN-92', NULL, 3, 'Sales Representative', + 34, 1525, 15); +INSERT INTO s_emp VALUES ( + 15, 'Dumas', 'Andre', 'adumas', + '09-OCT-91', NULL, 3, 'Sales Representative', + 35, 1450, 17.5); +INSERT INTO s_emp VALUES ( + 16, 'Maduro', 'Elena', 'emaduro', + '07-FEB-92', NULL, 6, 'Stock Clerk', + 41, 1400, NULL); +INSERT INTO s_emp VALUES ( + 17, 'Smith', 'George', 'gsmith', + '08-MAR-90', NULL, 6, 'Stock Clerk', + 41, 940, NULL); +INSERT INTO s_emp VALUES ( + 18, 'Nozaki', 'Akira', 'anozaki', + '09-FEB-91', NULL, 7, 'Stock Clerk', + 42, 1200, NULL); +INSERT INTO s_emp VALUES ( + 19, 'Patel', 'Vikram', 'vpatel', + '06-AUG-91', NULL, 7, 'Stock Clerk', + 42, 795, NULL); +INSERT INTO s_emp VALUES ( + 20, 'Newman', 'Chad', 'cnewman', + '21-JUL-91', NULL, 8, 'Stock Clerk', + 43, 750, NULL); +INSERT INTO s_emp VALUES ( + 21, 'Markarian', 'Alexander', 'amarkari', + '26-MAY-91', NULL, 8, 'Stock Clerk', + 43, 850, NULL); +INSERT INTO s_emp VALUES ( + 22, 'Chang', 'Eddie', 'echang', + '30-NOV-90', NULL, 9, 'Stock Clerk', + 44, 800, NULL); +INSERT INTO s_emp VALUES ( + 23, 'Patel', 'Radha', 'rpatel', + '17-OCT-90', NULL, 9, 'Stock Clerk', + 34, 795, NULL); +INSERT INTO s_emp VALUES ( + 24, 'Dancs', 'Bela', 'bdancs', + '17-MAR-91', NULL, 10, 'Stock Clerk', + 45, 860, NULL); +INSERT INTO s_emp VALUES ( + 25, 'Schwartz', 'Sylvie', 'sschwart', + '09-MAY-91', NULL, 10, 'Stock Clerk', + 45, 1100, NULL); +COMMIT; + + +CREATE TABLE s_image +(id NUMBER(7) + CONSTRAINT s_image_id_nn NOT NULL, + format VARCHAR2(25), + use_filename VARCHAR2(1), + filename VARCHAR2(255), + image LONG RAW, + CONSTRAINT s_image_id_pk + PRIMARY KEY (id), + CONSTRAINT s_image_format_ck + CHECK (format in ('JFIFF', 'JTIFF')), + CONSTRAINT s_image_use_filename_ck + CHECK (use_filename in ('Y', 'N'))); + +INSERT INTO s_image VALUES ( + 1001, 'JTIFF', 'Y', 'bunboot.tif', NULL); +INSERT INTO s_image VALUES ( + 1002, 'JTIFF', 'Y', 'aceboot.tif', NULL); +INSERT INTO s_image VALUES ( + 1003, 'JTIFF', 'Y', 'proboot.tif', NULL); +INSERT INTO s_image VALUES ( + 1011, 'JTIFF', 'Y', 'bunpole.tif', NULL); +INSERT INTO s_image VALUES ( + 1012, 'JTIFF', 'Y', 'acepole.tif', NULL); +INSERT INTO s_image VALUES ( + 1013, 'JTIFF', 'Y', 'propole.tif', NULL); +INSERT INTO s_image VALUES ( + 1291, 'JTIFF', 'Y', 'gpbike.tif', NULL); +INSERT INTO s_image VALUES ( + 1296, 'JTIFF', 'Y', 'himbike.tif', NULL); +INSERT INTO s_image VALUES ( + 1829, 'JTIFF', 'Y', 'safthelm.tif', NULL); +INSERT INTO s_image VALUES ( + 1381, 'JTIFF', 'Y', 'probar.tif', NULL); +INSERT INTO s_image VALUES ( + 1382, 'JTIFF', 'Y', 'curlbar.tif', NULL); +INSERT INTO s_image VALUES ( + 1119, 'JTIFF', 'Y', 'baseball.tif', NULL); +INSERT INTO s_image VALUES ( + 1223, 'JTIFF', 'Y', 'chaphelm.tif', NULL); +INSERT INTO s_image VALUES ( + 1367, 'JTIFF', 'Y', 'grglove.tif', NULL); +INSERT INTO s_image VALUES ( + 1368, 'JTIFF', 'Y', 'alglove.tif', NULL); +INSERT INTO s_image VALUES ( + 1369, 'JTIFF', 'Y', 'stglove.tif', NULL); +INSERT INTO s_image VALUES ( + 1480, 'JTIFF', 'Y', 'cabbat.tif', NULL); +INSERT INTO s_image VALUES ( + 1482, 'JTIFF', 'Y', 'pucbat.tif', NULL); +INSERT INTO s_image VALUES ( + 1486, 'JTIFF', 'Y', 'winbat.tif', NULL); +COMMIT; + + +CREATE TABLE s_inventory +(product_id NUMBER(7) + CONSTRAINT s_inventory_product_id_nn NOT NULL, + warehouse_id NUMBER(7) + CONSTRAINT s_inventory_warehouse_id_nn NOT NULL, + amount_in_stock NUMBER(9), + reorder_point NUMBER(9), + max_in_stock NUMBER(9), + out_of_stock_explanation VARCHAR2(255), + restock_date DATE, + CONSTRAINT s_inventory_prodid_warid_pk + PRIMARY KEY (product_id, warehouse_id)); + +INSERT INTO s_inventory VALUES ( + 10011, 101, 650, 625, 1100, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 10012, 101, 600, 560, 1000, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 10013, 101, 400, 400, 700, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 10021, 101, 500, 425, 740, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 10022, 101, 300, 200, 350, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 10023, 101, 400, 300, 525, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20106, 101, 993, 625, 1000, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20108, 101, 700, 700, 1225, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20201, 101, 802, 800, 1400, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20510, 101, 1389, 850, 1400, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20512, 101, 850, 850, 1450, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30321, 101, 2000, 1500, 2500, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30326, 101, 2100, 2000, 3500, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30421, 101, 1822, 1800, 3150, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30426, 101, 2250, 2000, 3500, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30433, 101, 650, 600, 1050, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 32779, 101, 2120, 1250, 2200, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 32861, 101, 505, 500, 875, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 40421, 101, 578, 350, 600, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 40422, 101, 0, 350, 600, 'Phenomenal sales...', '08-FEB-93'); +INSERT INTO s_inventory VALUES ( + 41010, 101, 250, 250, 437, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41020, 101, 471, 450, 750, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41050, 101, 501, 450, 750, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41080, 101, 400, 400, 700, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41100, 101, 350, 350, 600, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50169, 101, 2530, 1500, 2600, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50273, 101, 233, 200, 350, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50417, 101, 518, 500, 875, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50418, 101, 244, 100, 275, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50419, 101, 230, 120, 310, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50530, 101, 669, 400, 700, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50532, 101, 0, 100, 175, 'Wait for Spring.', '12-APR-93'); +INSERT INTO s_inventory VALUES ( + 50536, 101, 173, 100, 175, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20106, 201, 220, 150, 260, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20108, 201, 166, 150, 260, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20201, 201, 320, 200, 350, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20510, 201, 175, 100, 175, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20512, 201, 162, 100, 175, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30321, 201, 96, 80, 140, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30326, 201, 147, 120, 210, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30421, 201, 102, 80, 140, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30426, 201, 200, 120, 210, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30433, 201, 130, 130, 230, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 32779, 201, 180, 150, 260, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 32861, 201, 132, 80, 140, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50169, 201, 225, 220, 385, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50273, 201, 75, 60, 100, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50417, 201, 82, 60, 100, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50418, 201, 98, 60, 100, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50419, 201, 77, 60, 100, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50530, 201, 62, 60, 100, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50532, 201, 67, 60, 100, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50536, 201, 97, 60, 100, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20510, 301, 69, 40, 100, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20512, 301, 28, 20, 50, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30321, 301, 85, 80, 140, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30421, 301, 102, 80, 140, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30433, 301, 35, 20, 35, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 32779, 301, 102, 95, 175, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 32861, 301, 57, 50, 100, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 40421, 301, 70, 40, 70, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 40422, 301, 65, 40, 70, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41010, 301, 59, 40, 70, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41020, 301, 61, 40, 70, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41050, 301, 49, 40, 70, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41080, 301, 50, 40, 70, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41100, 301, 42, 40, 70, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20510, 401, 88, 50, 100, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20512, 401, 75, 75, 140, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30321, 401, 102, 80, 140, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30326, 401, 113, 80, 140, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30421, 401, 85, 80, 140, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30426, 401, 135, 80, 140, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30433, 401, 0, 100, 175, 'A defective shipment was sent to Hong Kong ' || + 'and needed to be returned. The soonest ACME can turn this around is ' || + 'early February.', '07-SEP-92'); +INSERT INTO s_inventory VALUES ( + 32779, 401, 135, 100, 175, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 32861, 401, 250, 150, 250, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 40421, 401, 47, 40, 70, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 40422, 401, 50, 40, 70, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41010, 401, 80, 70, 220, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41020, 401, 91, 70, 220, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41050, 401, 169, 70, 220, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41080, 401, 100, 70, 220, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41100, 401, 75, 70, 220, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50169, 401, 240, 200, 350, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50273, 401, 224, 150, 280, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50417, 401, 130, 120, 210, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50418, 401, 156, 100, 175, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50419, 401, 151, 150, 280, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50530, 401, 119, 100, 175, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50532, 401, 233, 200, 350, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 50536, 401, 138, 100, 175, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 10012, 10501, 300, 300, 525, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 10013, 10501, 314, 300, 525, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 10022, 10501, 502, 300, 525, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 10023, 10501, 500, 300, 525, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20106, 10501, 150, 100, 175, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20108, 10501, 222, 200, 350, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20201, 10501, 275, 200, 350, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20510, 10501, 57, 50, 87, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 20512, 10501, 62, 50, 87, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30321, 10501, 194, 150, 275, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30326, 10501, 277, 250, 440, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30421, 10501, 190, 150, 275, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30426, 10501, 423, 250, 450, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 30433, 10501, 273, 200, 350, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 32779, 10501, 280, 200, 350, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 32861, 10501, 288, 200, 350, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 40421, 10501, 97, 80, 140, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 40422, 10501, 90, 80, 140, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41010, 10501, 151, 140, 245, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41020, 10501, 224, 140, 245, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41050, 10501, 157, 140, 245, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41080, 10501, 159, 140, 245, NULL, NULL); +INSERT INTO s_inventory VALUES ( + 41100, 10501, 141, 140, 245, NULL, NULL); +COMMIT; + + +CREATE TABLE s_item +(ord_id NUMBER(7) + CONSTRAINT s_item_ord_id_nn NOT NULL, + item_id NUMBER(7) + CONSTRAINT s_item_item_id_nn NOT NULL, + product_id NUMBER(7) + CONSTRAINT s_item_product_id_nn NOT NULL, + price NUMBER(11, 2), + quantity NUMBER(9), + quantity_shipped NUMBER(9), + CONSTRAINT s_item_ordid_itemid_pk PRIMARY KEY (ord_id, item_id), + CONSTRAINT s_item_ordid_prodid_uk UNIQUE (ord_id, product_id)); + +INSERT INTO s_item VALUES ( + 100, 1, 10011, 135, 500, 500); +INSERT INTO s_item VALUES ( + 100, 2, 10013, 380, 400, 400); +INSERT INTO s_item VALUES ( + 100, 3, 10021, 14, 500, 500); +INSERT INTO s_item VALUES ( + 100, 5, 30326, 582, 600, 600); +INSERT INTO s_item VALUES ( + 100, 7, 41010, 8, 250, 250); +INSERT INTO s_item VALUES ( + 100, 6, 30433, 20, 450, 450); +INSERT INTO s_item VALUES ( + 100, 4, 10023, 36, 400, 400); +INSERT INTO s_item VALUES ( + 101, 1, 30421, 16, 15, 15); +INSERT INTO s_item VALUES ( + 101, 3, 41010, 8, 20, 20); +INSERT INTO s_item VALUES ( + 101, 5, 50169, 4.29, 40, 40); +INSERT INTO s_item VALUES ( + 101, 6, 50417, 80, 27, 27); +INSERT INTO s_item VALUES ( + 101, 7, 50530, 45, 50, 50); +INSERT INTO s_item VALUES ( + 101, 4, 41100, 45, 35, 35); +INSERT INTO s_item VALUES ( + 101, 2, 40422, 50, 30, 30); +INSERT INTO s_item VALUES ( + 102, 1, 20108, 28, 100, 100); +INSERT INTO s_item VALUES ( + 102, 2, 20201, 123, 45, 45); +INSERT INTO s_item VALUES ( + 103, 1, 30433, 20, 15, 15); +INSERT INTO s_item VALUES ( + 103, 2, 32779, 7, 11, 11); +INSERT INTO s_item VALUES ( + 104, 1, 20510, 9, 7, 7); +INSERT INTO s_item VALUES ( + 104, 4, 30421, 16, 35, 35); +INSERT INTO s_item VALUES ( + 104, 2, 20512, 8, 12, 12); +INSERT INTO s_item VALUES ( + 104, 3, 30321, 1669, 19, 19); +INSERT INTO s_item VALUES ( + 105, 1, 50273, 22.89, 16, 16); +INSERT INTO s_item VALUES ( + 105, 3, 50532, 47, 28, 28); +INSERT INTO s_item VALUES ( + 105, 2, 50419, 80, 13, 13); +INSERT INTO s_item VALUES ( + 106, 1, 20108, 28, 46, 46); +INSERT INTO s_item VALUES ( + 106, 4, 50273, 22.89, 75, 75); +INSERT INTO s_item VALUES ( + 106, 5, 50418, 75, 98, 98); +INSERT INTO s_item VALUES ( + 106, 6, 50419, 80, 27, 27); +INSERT INTO s_item VALUES ( + 106, 2, 20201, 123, 21, 21); +INSERT INTO s_item VALUES ( + 106, 3, 50169, 4.29, 125, 125); +INSERT INTO s_item VALUES ( + 107, 1, 20106, 11, 50, 50); +INSERT INTO s_item VALUES ( + 107, 3, 20201, 115, 130, 130); +INSERT INTO s_item VALUES ( + 107, 5, 30421, 16, 55, 55); +INSERT INTO s_item VALUES ( + 107, 4, 30321, 1669, 75, 75); +INSERT INTO s_item VALUES ( + 107, 2, 20108, 28, 22, 22); +INSERT INTO s_item VALUES ( + 108, 1, 20510, 9, 9, 9); +INSERT INTO s_item VALUES ( + 108, 6, 41080, 35, 50, 50); +INSERT INTO s_item VALUES ( + 108, 7, 41100, 45, 42, 42); +INSERT INTO s_item VALUES ( + 108, 5, 32861, 60, 57, 57); +INSERT INTO s_item VALUES ( + 108, 2, 20512, 8, 18, 18); +INSERT INTO s_item VALUES ( + 108, 4, 32779, 7, 60, 60); +INSERT INTO s_item VALUES ( + 108, 3, 30321, 1669, 85, 85); +INSERT INTO s_item VALUES ( + 109, 1, 10011, 140, 150, 150); +INSERT INTO s_item VALUES ( + 109, 5, 30426, 18.25, 500, 500); +INSERT INTO s_item VALUES ( + 109, 7, 50418, 75, 43, 43); +INSERT INTO s_item VALUES ( + 109, 6, 32861, 60, 50, 50); +INSERT INTO s_item VALUES ( + 109, 4, 30326, 582, 1500, 1500); +INSERT INTO s_item VALUES ( + 109, 2, 10012, 175, 600, 600); +INSERT INTO s_item VALUES ( + 109, 3, 10022, 21.95, 300, 300); +INSERT INTO s_item VALUES ( + 110, 1, 50273, 22.89, 17, 17); +INSERT INTO s_item VALUES ( + 110, 2, 50536, 50, 23, 23); +INSERT INTO s_item VALUES ( + 111, 1, 40421, 65, 27, 27); +INSERT INTO s_item VALUES ( + 111, 2, 41080, 35, 29, 29); +INSERT INTO s_item VALUES ( + 97, 1, 20106, 9, 1000, 1000); +INSERT INTO s_item VALUES ( + 97, 2, 30321, 1500, 50, 50); +INSERT INTO s_item VALUES ( + 98, 1, 40421, 85, 7, 7); +INSERT INTO s_item VALUES ( + 99, 1, 20510, 9, 18, 18); +INSERT INTO s_item VALUES ( + 99, 2, 20512, 8, 25, 25); +INSERT INTO s_item VALUES ( + 99, 3, 50417, 80, 53, 53); +INSERT INTO s_item VALUES ( + 99, 4, 50530, 45, 69, 69); +INSERT INTO s_item VALUES ( + 112, 1, 20106, 11, 50, 50); +COMMIT; + + +CREATE TABLE s_longtext +(id NUMBER(7) + CONSTRAINT s_longtext_id_nn NOT NULL, + use_filename VARCHAR2(1), + filename VARCHAR2(255), + text VARCHAR2(2000), + CONSTRAINT s_longtext_id_pk PRIMARY KEY (id), + CONSTRAINT s_longtext_use_filename_ck + CHECK (use_filename in ('Y', 'N'))); + +INSERT INTO s_longtext VALUES ( + 1017, 'N', NULL, + 'Protective knee pads for any number of physical activities including ' || + 'bicycling and skating (4-wheel, in-line, and ice). Also provide ' || + 'support for stress activities such as weight-lifting. Velcro belts ' || + 'allow easy adjustment for any size and snugness of fit. Hardened ' || + 'plastic shell comes in a variety of colors, so you can buy a pair to ' || + 'match every outfit. Can also be worn at the beach to cover ' || + 'particularly ugly knees.'); +INSERT INTO s_longtext VALUES ( + 1019, 'N', NULL, + 'Protective elbow pads for any number of physical activities including ' || + 'bicycling and skating (4-wheel, in-line, and ice). Also provide ' || + 'support for stress activities such as weight-lifting. Velcro belts ' || + 'allow easy adjustment for any size and snugness of fit. Hardened ' || + 'plastic shell comes in a variety of colors, so you can buy a pair to ' || + 'match every outfit.'); +INSERT INTO s_longtext VALUES ( + 1037, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 1039, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 1043, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 1286, 'N', NULL, + 'Don''t slack off--try the Slaker Water Bottle. With its 1 quart ' || + 'capacity, this is the only water bottle you''ll need. It''s ' || + 'lightweight, durable, and guaranteed for life to be leak proof. It ' || + 'comes with a convenient velcro strap so it ' || + 'can be conveniently attached to your bike or other sports equipment.'); +INSERT INTO s_longtext VALUES ( + 1368, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 517, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 518, 'N', NULL, + 'Perfect for the beginner. Rear entry (easy to put on with only one ' || + 'buckle), weight control adjustment on side of boot for easy access, ' || + 'comes in a wide variety of colors to match every outfit.'); +INSERT INTO s_longtext VALUES ( + 519, 'N', NULL, + 'If you have mastered the basic techniques you are ready for the Ace Ski ' || + 'Boot. This intermediate boot comes as a package with self adjustable ' || + 'bindings that will adapt to your skill and speed. The boot is designed ' || + 'for extra grip on slopes and jumps.'); +INSERT INTO s_longtext VALUES ( + 520, 'N', NULL, + 'The Pro ski boot is an advanced boot that combines high tech and ' || + 'comfort. It''s made of fibre that will mould to your foot with body ' || + 'heat. If you''re after perfection, don''t look any further: this is it!'); +INSERT INTO s_longtext VALUES ( + 527, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 528, 'N', NULL, + 'Lightweight aluminum pole, comes in a variety of sizes and neon ' || + 'colors. Comfortable adjustable straps.'); +INSERT INTO s_longtext VALUES ( + 529, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 530, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 557, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 587, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 607, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 613, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 615, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 676, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 708, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 780, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 828, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 833, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 924, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 925, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 926, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 927, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 928, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 929, NULL, NULL, NULL); +INSERT INTO s_longtext VALUES ( + 933, 'N', NULL, + 'The widest, strongest, and knobbiest tires for mountain bike ' || + 'enthusiasts. Guaranteed to withstand pummelling that will reduce most ' || + 'bicycles (except for the Himalayan) to scrap iron. These tires can ' || + 'carry you to places where nobody would want to bicycle. Sizes to ' || + 'fit all makes of mountain bike including wide and super wide rims. ' || + 'Steel-banded radial models are also available by direct factory order.'); +INSERT INTO s_longtext VALUES ( + 940, NULL, NULL, NULL); +COMMIT; + + +CREATE TABLE s_ord +(id NUMBER(7) + CONSTRAINT s_ord_id_nn NOT NULL, + customer_id NUMBER(7) + CONSTRAINT s_ord_customer_id_nn NOT NULL, + date_ordered DATE, + date_shipped DATE, + sales_rep_id NUMBER(7), + total NUMBER(11, 2), + payment_type VARCHAR2(6), + order_filled VARCHAR2(1), + CONSTRAINT s_ord_id_pk PRIMARY KEY (id), + CONSTRAINT s_ord_payment_type_ck + CHECK (payment_type in ('CASH', 'CREDIT')), + CONSTRAINT s_ord_order_filled_ck + CHECK (order_filled in ('Y', 'N'))); + +INSERT INTO s_ord VALUES ( + 100, 204, '31-AUG-92', '10-SEP-92', + 11, 601100, 'CREDIT', 'Y'); +INSERT INTO s_ord VALUES ( + 101, 205, '31-AUG-92', '15-SEP-92', + 14, 8056.6, 'CREDIT', 'Y'); +INSERT INTO s_ord VALUES ( + 102, 206, '01-SEP-92', '08-SEP-92', + 15, 8335, 'CREDIT', 'Y'); +INSERT INTO s_ord VALUES ( + 103, 208, '02-SEP-92', '22-SEP-92', + 15, 377, 'CASH', 'Y'); +INSERT INTO s_ord VALUES ( + 104, 208, '03-SEP-92', '23-SEP-92', + 15, 32430, 'CREDIT', 'Y'); +INSERT INTO s_ord VALUES ( + 105, 209, '04-SEP-92', '18-SEP-92', + 11, 2722.24, 'CREDIT', 'Y'); +INSERT INTO s_ord VALUES ( + 106, 210, '07-SEP-92', '15-SEP-92', + 12, 15634, 'CREDIT', 'Y'); +INSERT INTO s_ord VALUES ( + 107, 211, '07-SEP-92', '21-SEP-92', + 15, 142171, 'CREDIT', 'Y'); +INSERT INTO s_ord VALUES ( + 108, 212, '07-SEP-92', '10-SEP-92', + 13, 149570, 'CREDIT', 'Y'); +INSERT INTO s_ord VALUES ( + 109, 213, '08-SEP-92', '28-SEP-92', + 11, 1020935, 'CREDIT', 'Y'); +INSERT INTO s_ord VALUES ( + 110, 214, '09-SEP-92', '21-SEP-92', + 11, 1539.13, 'CASH', 'Y'); +INSERT INTO s_ord VALUES ( + 111, 204, '09-SEP-92', '21-SEP-92', + 11, 2770, 'CASH', 'Y'); +INSERT INTO s_ord VALUES ( + 97, 201, '28-AUG-92', '17-SEP-92', + 12, 84000, 'CREDIT', 'Y'); +INSERT INTO s_ord VALUES ( + 98, 202, '31-AUG-92', '10-SEP-92', + 14, 595, 'CASH', 'Y'); +INSERT INTO s_ord VALUES ( + 99, 203, '31-AUG-92', '18-SEP-92', + 14, 7707, 'CREDIT', 'Y'); +INSERT INTO s_ord VALUES ( + 112, 210, '31-AUG-92', '10-SEP-92', + 12, 550, 'CREDIT', 'Y'); +COMMIT; + + +CREATE TABLE s_product +(id NUMBER(7) + CONSTRAINT s_product_id_nn NOT NULL, + name VARCHAR2(50) + CONSTRAINT s_product_name_nn NOT NULL, + short_desc VARCHAR2(255), + longtext_id NUMBER(7), + image_id NUMBER(7), + suggested_whlsl_price NUMBER(11, 2), + whlsl_units VARCHAR2(25), + CONSTRAINT s_product_id_pk PRIMARY KEY (id), + CONSTRAINT s_product_name_uk UNIQUE (name)); + +INSERT INTO s_product VALUES ( + 10011, 'Bunny Boot', + 'Beginner''s ski boot', + 518, 1001, + 150, NULL); +INSERT INTO s_product VALUES ( + 10012, 'Ace Ski Boot', + 'Intermediate ski boot', + 519, 1002, + 200, NULL); +INSERT INTO s_product VALUES ( + 10013, 'Pro Ski Boot', + 'Advanced ski boot', + 520, 1003, + 410, NULL); +INSERT INTO s_product VALUES ( + 10021, 'Bunny Ski Pole', + 'Beginner''s ski pole', + 528, 1011, + 16.25, NULL); +INSERT INTO s_product VALUES ( + 10022, 'Ace Ski Pole', + 'Intermediate ski pole', + 529, 1012, + 21.95, NULL); +INSERT INTO s_product VALUES ( + 10023, 'Pro Ski Pole', + 'Advanced ski pole', + 530, 1013, + 40.95, NULL); +INSERT INTO s_product VALUES ( + 20106, 'Junior Soccer Ball', + 'Junior soccer ball', + 613, NULL, + 11, NULL); +INSERT INTO s_product VALUES ( + 20108, 'World Cup Soccer Ball', + 'World cup soccer ball', + 615, NULL, + 28, NULL); +INSERT INTO s_product VALUES ( + 20201, 'World Cup Net', + 'World cup net', + 708, NULL, + 123, NULL); +INSERT INTO s_product VALUES ( + 20510, 'Black Hawk Knee Pads', + 'Knee pads, pair', + 1017, NULL, + 9, NULL); +INSERT INTO s_product VALUES ( + 20512, 'Black Hawk Elbow Pads', + 'Elbow pads, pair', + 1019, NULL, + 8, NULL); +INSERT INTO s_product VALUES ( + 30321, 'Grand Prix Bicycle', + 'Road bicycle', + 828, 1291, + 1669, NULL); +INSERT INTO s_product VALUES ( + 30326, 'Himalaya Bicycle', + 'Mountain bicycle', + 833, 1296, + 582, NULL); +INSERT INTO s_product VALUES ( + 30421, 'Grand Prix Bicycle Tires', + 'Road bicycle tires', + 927, NULL, + 16, NULL); +INSERT INTO s_product VALUES ( + 30426, 'Himalaya Tires', + 'Mountain bicycle tires', + 933, NULL, + 18.25, NULL); +INSERT INTO s_product VALUES ( + 30433, 'New Air Pump', + 'Tire pump', + 940, NULL, + 20, NULL); +INSERT INTO s_product VALUES ( + 32779, 'Slaker Water Bottle', + 'Water bottle', + 1286, NULL, + 7, NULL); +INSERT INTO s_product VALUES ( + 32861, 'Safe-T Helmet', + 'Bicycle helmet', + 1368, 1829, + 60, NULL); +INSERT INTO s_product VALUES ( + 40421, 'Alexeyer Pro Lifting Bar', + 'Straight bar', + 928, 1381, + 65, NULL); +INSERT INTO s_product VALUES ( + 40422, 'Pro Curling Bar', + 'Curling bar', + 929, 1382, + 50, NULL); +INSERT INTO s_product VALUES ( + 41010, 'Prostar 10 Pound Weight', + 'Ten pound weight', + 517, NULL, + 8, NULL); +INSERT INTO s_product VALUES ( + 41020, 'Prostar 20 Pound Weight', + 'Twenty pound weight', + 527, NULL, + 12, NULL); +INSERT INTO s_product VALUES ( + 41050, 'Prostar 50 Pound Weight', + 'Fifty pound weight', + 557, NULL, + 25, NULL); +INSERT INTO s_product VALUES ( + 41080, 'Prostar 80 Pound Weight', + 'Eighty pound weight', + 587, NULL, + 35, NULL); +INSERT INTO s_product VALUES ( + 41100, 'Prostar 100 Pound Weight', + 'One hundred pound weight', + 607, NULL, + 45, NULL); +INSERT INTO s_product VALUES ( + 50169, 'Major League Baseball', + 'Baseball', + 676, 1119, + 4.29, NULL); +INSERT INTO s_product VALUES ( + 50273, 'Chapman Helmet', + 'Batting helmet', + 780, 1223, + 22.89, NULL); +INSERT INTO s_product VALUES ( + 50417, 'Griffey Glove', + 'Outfielder''s glove', + 924, 1367, + 80, NULL); +INSERT INTO s_product VALUES ( + 50418, 'Alomar Glove', + 'Infielder''s glove', + 925, 1368, + 75, NULL); +INSERT INTO s_product VALUES ( + 50419, 'Steinbach Glove', + 'Catcher''s glove', + 926, 1369, + 80, NULL); +INSERT INTO s_product VALUES ( + 50530, 'Cabrera Bat', + 'Thirty inch bat', + 1037, 1480, + 45, NULL); +INSERT INTO s_product VALUES ( + 50532, 'Puckett Bat', + 'Thirty-two inch bat', + 1039, 1482, + 47, NULL); +INSERT INTO s_product VALUES ( + 50536, 'Winfield Bat', + 'Thirty-six inch bat', + 1043, 1486, + 50, NULL); +COMMIT; + + +CREATE TABLE s_region +(id NUMBER(7) + CONSTRAINT s_region_id_nn NOT NULL, + name VARCHAR2(50) + CONSTRAINT s_region_name_nn NOT NULL, + CONSTRAINT s_region_id_pk PRIMARY KEY (id), + CONSTRAINT s_region_name_uk UNIQUE (name)); + +INSERT INTO s_region VALUES ( + 1, 'North America'); +INSERT INTO s_region VALUES ( + 2, 'South America'); +INSERT INTO s_region VALUES ( + 3, 'Africa / Middle East'); +INSERT INTO s_region VALUES ( + 4, 'Asia'); +INSERT INTO s_region VALUES ( + 5, 'Europe'); +COMMIT; + + +CREATE TABLE s_title +(title VARCHAR2(25) + CONSTRAINT s_title_title_nn NOT NULL, + CONSTRAINT s_title_title_pk PRIMARY KEY (title)); + +INSERT INTO s_title VALUES ('President'); +INSERT INTO s_title VALUES ('Sales Representative'); +INSERT INTO s_title VALUES ('Stock Clerk'); +INSERT INTO s_title VALUES ('VP, Administration'); +INSERT INTO s_title VALUES ('VP, Finance'); +INSERT INTO s_title VALUES ('VP, Operations'); +INSERT INTO s_title VALUES ('VP, Sales'); +INSERT INTO s_title VALUES ('Warehouse Manager'); +COMMIT; + + +CREATE TABLE s_warehouse +(id NUMBER(7) + CONSTRAINT s_warehouse_id_nn NOT NULL, + region_id NUMBER(7) + CONSTRAINT s_warehouse_region_id_nn NOT NULL, + address LONG, + city VARCHAR2(30), + state VARCHAR2(20), + country VARCHAR2(30), + zip_code VARCHAR2(75), + phone VARCHAR2(25), + manager_id NUMBER(7), + CONSTRAINT s_warehouse_id_pk PRIMARY KEY (id)); + +INSERT INTO s_warehouse VALUES ( + 101, 1, + '283 King Street', + 'Seattle', 'WA', 'USA', + NULL, + NULL, 6); +INSERT INTO s_warehouse VALUES ( + 10501, 5, + '5 Modrany', + 'Bratislava', NULL, 'Czechozlovakia', + NULL, + NULL, 10); +INSERT INTO s_warehouse VALUES ( + 201, 2, + '68 Via Centrale', + 'Sao Paolo', NULL, 'Brazil', + NULL, + NULL, 7); +INSERT INTO s_warehouse VALUES ( + 301, 3, + '6921 King Way', + 'Lagos', NULL, 'Nigeria', + NULL, + NULL, 8); +INSERT INTO s_warehouse VALUES ( + 401, 4, + '86 Chu Street', + 'Hong Kong', NULL, NULL, + NULL, + NULL, 9); +COMMIT; + + +rem Add foreign key constraints. + +ALTER TABLE s_dept + ADD CONSTRAINT s_dept_region_id_fk + FOREIGN KEY (region_id) REFERENCES s_region (id); +ALTER TABLE s_emp + ADD CONSTRAINT s_emp_manager_id_fk + FOREIGN KEY (manager_id) REFERENCES s_emp (id); +ALTER TABLE s_emp + ADD CONSTRAINT s_emp_dept_id_fk + FOREIGN KEY (dept_id) REFERENCES s_dept (id); +ALTER TABLE s_emp + ADD CONSTRAINT s_emp_title_fk + FOREIGN KEY (title) REFERENCES s_title (title); +ALTER TABLE s_customer + ADD CONSTRAINT s_sales_rep_id_fk + FOREIGN KEY (sales_rep_id) REFERENCES s_emp (id); +ALTER TABLE s_customer + ADD CONSTRAINT s_customer_region_id_fk + FOREIGN KEY (region_id) REFERENCES s_region (id); +ALTER TABLE s_ord + ADD CONSTRAINT s_ord_customer_id_fk + FOREIGN KEY (customer_id) REFERENCES s_customer (id); +ALTER TABLE s_ord + ADD CONSTRAINT s_ord_sales_rep_id_fk + FOREIGN KEY (sales_rep_id) REFERENCES s_emp (id); +ALTER TABLE s_product + ADD CONSTRAINT s_product_image_id_fk + FOREIGN KEY (image_id) REFERENCES s_image (id); +ALTER TABLE s_product + ADD CONSTRAINT s_product_longtext_id_fk + FOREIGN KEY (longtext_id) REFERENCES s_longtext (id); +ALTER TABLE s_item + ADD CONSTRAINT s_item_ord_id_fk + FOREIGN KEY (ord_id) REFERENCES s_ord (id); +ALTER TABLE s_item + ADD CONSTRAINT s_item_product_id_fk + FOREIGN KEY (product_id) REFERENCES s_product (id); +ALTER TABLE s_warehouse + ADD CONSTRAINT s_warehouse_manager_id_fk + FOREIGN KEY (manager_id) REFERENCES s_emp (id); +ALTER TABLE s_warehouse + ADD CONSTRAINT s_warehouse_region_id_fk + FOREIGN KEY (region_id) REFERENCES s_region (id); +ALTER TABLE s_inventory + ADD CONSTRAINT s_inventory_product_id_fk + FOREIGN KEY (product_id) REFERENCES s_product (id); +ALTER TABLE s_inventory + ADD CONSTRAINT s_inventory_warehouse_id_fk + FOREIGN KEY (warehouse_id) REFERENCES s_warehouse (id); + +prompt Tables and sequences created and populated. +set feedback on diff --git a/tyevdemo.sql b/tyevdemo.sql new file mode 100644 index 0000000..51a4672 --- /dev/null +++ b/tyevdemo.sql @@ -0,0 +1,354 @@ +Rem +Rem $Header: tyevdemo.sql 01-may-2001.14:30:34 hyeh Exp $ +Rem +Rem tyevdemo.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem tyevdemo.sql - Demonstrate Type Evolution feature +Rem +Rem DESCRIPTION +Rem Demonstrate Type Evolution feature +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem hyeh 05/01/01 - fix query format +Rem hyeh 04/10/01 - Merged hyeh_inh_tyev_demos +Rem hyeh 04/10/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +COLUMN constraint_nm FORMAT A20 +COLUMN index_nm FORMAT A20 +SET ECHO ON + +connect system/manager +drop user tyevdemo1 cascade; + +grant connect, resource to tyevdemo1 identified by tyevdemo1; + +connect tyevdemo1/tyevdemo1 + +-- create some types and tables +create type type1 as object (c1 number, c2 number, c3 number); +/ +show errors +create type type2 as object (c2 varchar2(10), c3 number, c4 char(10), + member function mf1 (in1 varchar2) return number); +/ +show errors + +create type body type2 as + member function mf1 (in1 varchar2) return number as + begin + if in1 is null then + return length(self.c2); + end if; + return length(self.c2) + length(in1); + end; +end; +/ +show errors + +create type type3 as object (c1 ref type2, c2 varchar2(10)); +/ +show errors +create type type4 as object (c1 type2, c2 varchar2(10)); +/ +show errors +create type nttype1 as table of char(6); +/ +show errors +create type vatype1 as varray(7) of ref type2; +/ +show errors +create type nttype2 as table of type4; +/ +show errors + +create table otb1 of type1; +create table rtb1 (c1 type1, c2 number); +create table otb2 of type2 (constraint opk2 primary key (c2)); + +create table rtb2 (c1 type2, c2 vatype1, c3 number, c4 nttype2, + constraint rpk2 primary key (c1.c2)) + nested table c4 store as rtb2_c4, + varray c2 store as lob rtb2_c2 (index rlobix2_c2); +create index rix2 on rtb2 (c1.c4, c1.c2); + +insert into otb1 values (1,1,1); +insert into rtb1 select value(p), 1 from otb1 p; + +insert into otb2 values ('abcdefghij',1,'abcdefghij'); +insert into rtb2 values + (type2('abcdefghij',1,'abcdefghij'), null, 1,nttype2(type4(null,null))); + +update rtb2 p set p.c2=vatype1(null,null,null,null,null,null,null); +update table (select c4 from rtb2) e + set value(e)=type4((select value(p) from otb2 p), 'a'); + +declare + vref ref type2; + va1 vatype1; + va_cnt integer; +begin + select c2 into va1 from rtb2; + select ref(a) into vref from otb2 a; + va1 := vatype1(vref,null,null,null,null,null,null); + update rtb2 set c2 = va1; +end; +/ + +/*******************/ +/* Add/Drop Method */ +/*******************/ + +alter type type2 + add order member function om (in1 type2) return number, + add static procedure sp1 (in1 type2), + drop member function mf1 (in1 varchar2) return number, + add member function mf1 (in2 varchar2) return varchar2 + cascade; + +create or replace type body type2 as + member function mf1 (in2 varchar2) return varchar2 as + begin + if in2 is null then + return self.c2; + end if; + return (self.c2 || in2); + end; + + order member function om (in1 type2) return number as + begin + return (self.c3 - in1.c3); + end; + + static procedure sp1 (in1 type2) as + begin + dbms_output.put_line('in1.c3 = '||in1.c3); + end; +end; +/ +show errors + +desc type2 + +/* populate tables */ +update table(select c4 from rtb2) e + set value(e) = type4((select value(p) from otb2 p), '1a2b3c'); + +select * from otb1; +select * from rtb1; +select * from otb2; +select c1, c3, c4 from rtb2; +select deref(column_value) from table(select c2 from rtb2) order by 1; +select value(e) from table(select c4 from rtb2) e; + +select substr(constraint_name,1,20) constraint_nm, constraint_type, + TABLE_NAME, STATUS, INDEX_NAME,INVALID, VIEW_RELATED + from user_constraints order by 3,1; + +select substr(index_name,1,20) index_nm, index_type, table_name + from user_indexes + order by 3, 1; + +/********************/ +/* Modify attribute */ +/********************/ +/* can't increase length of fixed variable */ +alter type type2 modify attribute (c4 char(13)) cascade; +alter type type2 modify attribute (c2 varchar2(13)) cascade; + +/* workaround - reconnect */ +connect tyevdemo1/tyevdemo1 + +alter type type2 modify attribute (c2 varchar2(25)) invalidate; + +desc otb2 +desc rtb2 +desc type2 + +select * from otb2; +select c3 from rtb2; + +/******************/ +/* Drop attribute */ +/******************/ + +alter type type1 drop attribute(c2) cascade not including table data; +alter type type2 drop attribute(c2) cascade not including table data; + +connect tyevdemo1/tyevdemo1 + +/* fix type2 body not to refer to dropped attribute */ +create or replace type body type2 as + member function mf1 (in2 varchar2) return varchar2 as + begin + if in2 is null then + return self.c4; + end if; + return (self.c4 || in2); + end; + + order member function om (in1 type2) return number as + begin + return (self.c3 - in1.c3); + end; + + static procedure sp1 (in1 type2) as + begin + dbms_output.put_line('in1.c3 = '||in1.c3); + end; +end; +/ +show errors + +select * from otb1; +select * from rtb1; +select * from otb2; + +select c1, c3, c4 from rtb2; +select deref(column_value) from table(select c2 from rtb2) order by 1; + +select substr(constraint_name,1,20) constraint_nm, constraint_type, + TABLE_NAME, STATUS, INDEX_NAME,INVALID, VIEW_RELATED + from user_constraints order by 3,1; + +select substr(index_name,1,20) index_nm, index_type, table_name + from user_indexes + order by 3, 1; + +alter type type1 drop attribute(c3) invalidate; + +select * from otb1; +select c2 from rtb1; + +/* should get get ORA-22337 */ +select * from rtb1; + +/* reconnect to get new defn */ +connect tyevdemo1/tyevdemo1 +select * from rtb1; + +/******************/ +/* Add attribute */ +/******************/ + +alter table rtb1 upgrade; + +alter type type1 add attribute (c2 date) cascade; + +connect tyevdemo1/tyevdemo1 +desc otb1 +desc rtb1 +desc type1 + +alter type type1 drop attribute (c2) cascade; + +/* should get get ORA-22337 */ +select * from rtb1; + +connect tyevdemo1/tyevdemo1 +/* get new defn */ +desc type1 +select * from rtb1; + +alter type type1 add attribute (c3 clob) invalidate; + +/******************/ +/* Upgrade table */ +/******************/ + +alter table otb1 upgrade not including data; +alter table rtb1 upgrade not including data; + +select c2 from rtb1; +select * from otb1; + +update rtb1 set c2=c2; +update rtb1 set c1=c1; + +alter table rtb1 drop (c1); +alter table rtb1 add (c1 type1); +alter table rtb1 upgrade including data; +select * from otb1; + +connect tyevdemo1/tyevdemo1 +desc type1 +desc type2 + +update otb2 p set value(p)=value(p); + +select * from otb2; +select p.c1.c2 from rtb2 p; + +alter table rtb2 drop (c1); +select deref(column_value) from table(select c2 from rtb2 where c3=1) + order by 1; + +select p.column_value.c2 c2 + from table(select c2 from rtb2 where c3=1) p; + +truncate table rtb2; + +set serveroutput on +-- show objects depend on types +exec dbms_utility.get_dependency('type','tyevdemo1','type1'); +exec dbms_utility.get_dependency('type','tyevdemo1','type2'); +exec dbms_utility.get_dependency('type','tyevdemo1','type3'); +exec dbms_utility.get_dependency('type','tyevdemo1','nttype1'); +exec dbms_utility.get_dependency('type','tyevdemo1','vatype1'); + +/********************************************************/ +/* demonstrate type evolution with inheritance features */ +/********************************************************/ +connect tyevdemo1/tyevdemo1 + +alter table rtb1 drop (c1); +alter table rtb1 add (nc1 type1); + +insert into rtb1 values + (10, type1(10, empty_clob())); + +/* change type1 to not final */ +alter type type1 not final cascade; +alter type type1 + add attribute (c10 char(6)) cascade not including table data; +alter type type1 + add map member function mm1 return char cascade; + +/* create subtype */ + +create or replace type type1s under type1 (c11 nttype1); +/ +show errors + +/* override map method */ +alter type type1s + add overriding map member function mm1 return char; + +/* column rtb1.nc1 remains not substitutable */ +insert into rtb1 values + (1, type1s(1,empty_clob(),null,'a')); + +/* create table with substitutable column */ +create table rtb1s (c1 number, c2 type1, c3 date) + nested table treat(c2 as type1s).c11 store as rtb1s_c2_c11; +insert into rtb1s + select c2, type1s(p.nc1.c1, p.nc1.c3, p.nc1.c10, nttype1('A','B','C')), + to_date('08/21/2000','MM/DD/YYYY') from rtb1 p; + +select * from rtb1s order by c1; + +connect system/manager +drop user tyevdemo1 cascade; + diff --git a/ulcase.sh b/ulcase.sh new file mode 100644 index 0000000..495343e --- /dev/null +++ b/ulcase.sh @@ -0,0 +1,122 @@ +#!/bin/sh +# +# $Header: ulcase.sh 06-sep-2007.13:54:17 jstenois Exp $ +# +# ulcase.sh +# +# Copyright (c) 1999, 2007, Oracle. All rights reserved. +# +# NAME +# ulcase.sh - run sqlldr demos +# +# DESCRIPTION +# Shell script to run sqlldr demos. +# Please append to script as more ulcase* demos are added. +# +# MODIFIED (MM/DD/YY) +# jstenois 09/06/07 - remove password from demo script +# krich 01/26/04 - adding case study 11 +# cmlim 07/20/99 - create shell script for running all sqlldr demos +# cmlim 07/20/99 - Creation +# + +echo " " +echo "- This script runs through all of the SQL Loader demos." +echo "- It uses SQLPlus to create the necessary objects and then" +echo "- calls SQL Loader to load data. This script uses schema" +echo "- SCOTT for all of the tests. Whenever the script executes" +echo "- SQLPlus or SQL Loader utilities, it will prompt you for" +echo "- password of the SCOTT user. You will need to enter this" +echo "- password every time for the script to continue. The" +echo "- default password for user SCOTT is TIGER." +echo " " + +# CASE1 +echo " " +echo " Starting case 1" +echo " Calling SQL Plus to do setup for case 1" +sqlplus scott @ulcase1 +echo " Calling SQL Loader to load data for case 1" +sqlldr scott ulcase1.ctl + +# CASE2 +echo " " +echo " Starting case 2" +echo " Calling SQL Loader to load data for case 2" +sqlldr scott ulcase2 + +# CASE3 +echo " " +echo " Starting case 3" +echo " Calling SQL Plus to do setup for case 3" +sqlplus scott @ulcase3 +echo " Calling SQL Loader to load data for case 3" +sqlldr scott ulcase3 + +# CASE4 +echo " " +echo " Starting case 4" +echo " Calling SQL Plus to do setup for case 4" +sqlplus scott @ulcase4 +echo " Calling SQL Loader to load data for case 4" +sqlldr scott ulcase4 + +# CASE5 +echo " " +echo " Starting case 5" +echo " Calling SQL Plus to do setup for case 5" +sqlplus scott @ulcase5 +echo " Calling SQL Loader to load data for case 5" +sqlldr scott ulcase5 + +# CASE6 +echo " " +echo " Starting case 6" +echo " Calling SQL Plus to do setup for case 6" +sqlplus scott @ulcase6 +echo " Calling SQL Loader to load data for case 6" +sqlldr scott ulcase6 direct=true + +# CASE7 +echo " " +echo " Starting case 7" +echo " Calling SQL Plus to do setup for case 7" +sqlplus scott @ulcase7s +echo " Calling SQL Loader to load data for case 7" +sqlldr scott ulcase7 +echo " Calling SQL Plus to do cleanup for case 7" +sqlplus scott @ulcase7e + +# CASE8 +echo " " +echo " Starting case 8" +echo " Calling SQL Plus to do setup for case 8" +sqlplus scott @ulcase8 +echo " Calling SQL Loader to load data for case 8" +sqlldr scott ulcase8 + +# CASE9 +echo " " +echo " Starting case 9" +echo " Calling SQL Plus to do setup for case 9" +sqlplus scott @ulcase9 +echo " Calling SQL Loader to load data for case 9" +sqlldr scott ulcase9 + +# CASE10 +echo " " +echo " Starting case 10" +echo " Calling SQL Plus to do setup for case 10" +sqlplus scott @ulcase10 +echo " Calling SQL Loader to load data for case 10" +sqlldr scott ulcase10 + +# CASE11 +echo " " +echo " Starting case 11" +echo " Calling SQL Plus to do setup for case 11" +sqlplus scott @ulcase11 +echo " Calling SQL Loader to load data for case 11" +sqlldr scott ulcase11 + + diff --git a/ulcase1.ctl b/ulcase1.ctl new file mode 100644 index 0000000..8df9ec4 --- /dev/null +++ b/ulcase1.ctl @@ -0,0 +1,62 @@ +-- Copyright (c) 1991, 2004 Oracle. All rights reserved. +-- NAME +-- ulcase1.ctl - SQL*Loader Case Study 1: Loading Variable-Length Data +-- +-- DESCRIPTION +-- This case study demonstrates the following: +-- +-- A simple control file identifying one table and three columns +-- to be loaded. +-- +-- Including data to be loaded from the control file itself, so +-- there is no separate datafile. +-- +-- Loading data in stream format, with both types of delimited +-- fields: terminated and enclosed. +-- +-- TO RUN THIS CASE STUDY: +-- 1. Before executing this control file, log in to SQL*Plus as +-- scott/tiger. Enter @ulcase1 to execute the SQL script for +-- this case study. This prepares and populates tables and +-- then returns you to the system prompt. +-- +-- 2. At the system prompt, invoke the case study as follows: +-- sqlldr USERID=scott/tiger CONTROL=ulcase1.ctl LOG=ulcase1.log +-- +-- NOTES ABOUT THIS CONTROL FILE +-- The LOAD DATA statement is required at the beginning of the +-- control file. +-- +-- INFILE * specifies that the data is found in the control file +-- and not in an external file. +-- +-- The INTO TABLE statement is required to identify the table to +-- be loaded (dept) into. By default, SQL*Loader requires the +-- table to be empty before it inserts any records. +-- +-- FIELDS TERMINATED BY specifies that the data is terminated by +-- commas, but may also be enclosed by quotation marks. Datatypes +-- for all fields default to CHAR. +-- +-- The names of columns to load are enclosed in parentheses. +-- If no datatype or length is specified and the field is delimited +-- with ENCLOSED BY or with TERMINATED BY, then the default +-- datatype is CHAR and the default length is 255. If ENCLOSED BY +-- or TERMINATED BY is not specified, then the default type is CHAR +-- and the default length is 1. +-- +-- BEGINDATA specifies the beginning of the data. +-- +LOAD DATA +INFILE * +INTO TABLE DEPT +FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' +(DEPTNO, DNAME, LOC) +BEGINDATA +12,RESEARCH,"SARATOGA" +10,"ACCOUNTING",CLEVELAND +11,"ART",SALEM +13,FINANCE,"BOSTON" +21,"SALES",PHILA. +22,"SALES",ROCHESTER +42,"INT'L","SAN FRAN" diff --git a/ulcase1.sql b/ulcase1.sql new file mode 100644 index 0000000..be7f115 --- /dev/null +++ b/ulcase1.sql @@ -0,0 +1,44 @@ +rem +rem $Header: ulcase1.sql 14-jul-99.14:22:19 mjaeger Exp $ +rem +rem Copyright (c) 1991, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem ulcase1.sql - +rem DESCRIPTION +rem +rem RETURNS +rem +rem NOTES +rem +rem MODIFIED (MM/DD/YY) +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem jstenois 06/17/99 - cleanup tables before load and show feedback +rem ksudarsh 03/01/93 - comment out vms specific host command +rem ksudarsh 12/29/92 - Creation +rem cheigham 08/28/91 - Creation +rem + +set termout off + +rem host write sys$output "Building first demonstration tables. Please wait" + +drop table emp; +drop table dept; + +create table emp + (empno number(4) not null, + ename char(10), + job char(9), + mgr number(4), + hiredate date, + sal number(7,2), + comm number(7,2), + deptno number(2)); + +create table dept + (deptno number(2), + dname char(14) , + loc char(13) ) ; + +exit diff --git a/ulcase10.ctl b/ulcase10.ctl new file mode 100644 index 0000000..d474b47 --- /dev/null +++ b/ulcase10.ctl @@ -0,0 +1,82 @@ +-- Copyright (c) 1991, 2004 Oracle. All rights reserved. +-- NAME +-- ulcase10.ctl - SQL*Loader Case Study 10: Loading REF Fields and VARRAYs +-- +-- DESCRIPTION +-- This case study demonstrates the following: +-- +-- Loading a customer table that has a primary key as its OID and +-- stores order items in a VARRAY. +-- +-- Loading an order table that has a reference to the customer table and +-- the order items in a VARRAY. +-- +-- TO RUN THIS CASE STUDY: +-- 1. Before executing this control file, log in to SQL*Plus as +-- scott/tiger. Enter @ulcase10 to execute the SQL script for +-- this case study. This prepares and populates tables and +-- then returns you to the system prompt. +-- +-- 2. At the system prompt, invoke the case study as follows: +-- sqlldr USERID=scott/tiger CONTROL=ulcase1.ctl0 LOG=ulcase10.log +-- +-- NOTES ABOUT THIS CONTROL FILE +-- cust_no and item_list_count are FILLER fields. The FILLER field is +-- assigned values from the data field to which it is mapped. +-- +-- The cust field is created as a REF field. +-- +-- item_list is stored in a VARRAY. +-- +-- The second occurrence of item_list identifies the datatype of each +-- element of the VARRAY. Here, the datatype is COLUMN OBJECT. +-- +-- The listing of item, cnt, price shows all attributes of the column +-- object that are loaded for the VARRAY. The list is enclosed in parentheses. +-- +-- The data is contained in the control file and is preceded by the +-- BEGINDATA parameter. +-- +LOAD DATA +INFILE * +CONTINUEIF THIS (1) = '*' + +INTO TABLE customers +REPLACE +FIELDS TERMINATED BY "," +( + cust_no CHAR, + name CHAR, + addr CHAR +) + +INTO TABLE orders +REPLACE +FIELDS TERMINATED BY "," +( + order_no CHAR, + cust_no FILLER CHAR, + cust REF (CONSTANT 'CUSTOMERS', cust_no), + item_list_count FILLER CHAR, + item_list VARRAY COUNT (item_list_count) + ( + item_list COLUMN OBJECT + ( + item CHAR, + cnt CHAR, + price CHAR + ) + ) +) + +BEGINDATA +*00001,Spacely Sprockets,15 Space Way, +*00101,00001,2, +*Sprocket clips, 10000, .01, + Sprocket cleaner, 10, 14.00 +*00002,Cogswell Cogs,12 Cogswell Lane, +*00100,00002,4, +*one quarter inch cogs,1000,.02, +*one half inch cog, 150, .04, +*one inch cog, 75, .10, + Custom coffee mugs, 10, 2.50 diff --git a/ulcase10.sql b/ulcase10.sql new file mode 100644 index 0000000..513a046 --- /dev/null +++ b/ulcase10.sql @@ -0,0 +1,80 @@ +rem +Rem $Header: ulcase10.sql 11-may-00.13:48:45 rpfau Exp $ +rem +rem ulcase10.sql +rem +rem Copyright (c) 1998, 1999,, 2000 Oracle Corporation. All rights reserved. +rem +rem NAME +rem ulcase10.sql - set up for SQL Loader example 10 +rem +rem DESCRIPTION +rem Create tables need to for example of using SQL Loader to load +rem VARRAYS and references +rem +rem NOTES +rem none +rem +rem MODIFIED (MM/DD/YY) +Rem rpfau 05/11/00 - Remove slashes on create table commands so it +Rem runs successfully using sqlplus. +Rem cmlim 07/27/99 - add / +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem jstenois 06/17/99 - cleanup tables before load and show feedback +rem jstenois 10/26/98 - demo of 8.1 features for sqlldr +rem jstenois 10/26/98 - Created +rem + +rem host write sys$output "Building case 10 demonstration tables. Please wait" + +rem do all cleanup + +drop table orders; +drop table customers; +drop type item_list_type; +drop type item_type; +drop type customer_type; + +rem Create an ORDER record that has a VARRAY for the items that comprise the +rem order and has a reference field to a record in the CUSTOMER table for +rem the customer placing the order. + +rem create customer type + +create type customer_type as object ( + cust_no char(5), + name char(20), + addr char(20) +); +/ + +rem create object table for customer type + +create table customers of customer_type + (primary key (cust_no)) + object id primary key; + +rem create type for order items + +create type item_type as object ( + item varchar(50), + cnt number, + price number(7,2) +); +/ + +rem create varray type for order items + +create type item_list_type as varray (1000) of item_type; +/ + +rem create orders table with varray for items and ref to object table + +create table orders ( + order_no char(5), + cust ref customer_type references customers, + item_list item_list_type +); + +exit; +/ diff --git a/ulcase11.ctl b/ulcase11.ctl new file mode 100644 index 0000000..05f22d3 --- /dev/null +++ b/ulcase11.ctl @@ -0,0 +1,72 @@ +-- Copyright (c) 1991, 2004 Oracle. All rights reserved. +-- NAME +-- ulcase11.ctl - SQL*Loader Case Study 11: Load Data in the Unicode +-- Character Set UTF-16 +-- +-- DESCRIPTION +-- This case study demonstrates the following: +-- Using SQL*Loader to load data in the Unicode character set, UTF16. +-- +-- Using SQL*Loader to load data in a fixed-width, multibyte character set. +-- +-- Using character-length semantics. +-- +-- Using SQL*Loader to load data in little-endian byte order. SQL*Loader +-- checks the byte order of the system on which it is running. If necessary, +-- SQL*Loader swaps the byte order of the data to ensure that any +-- byte-order-dependent data is correctly loaded. +-- +-- TO RUN THIS CASE STUDY: +-- 1. Before executing this control file, log in to SQL*Plus as +-- scott/tiger. Enter @ulcase11 to execute the SQL script for +-- this case study. This prepares and populates tables and +-- then returns you to the system prompt. +-- +-- 2. At the system prompt, invoke the case study as follows: +-- sqlldr USERID=scott/tiger CONTROL=ulcase11.ctl LOG=ulcase11.log +-- +-- NOTES ABOUT THIS CONTROL FILE +-- +-- The character set specified with the CHARACTERSET keyword is UTF16. +-- SQL*Loader will convert the data from the UTF16 character set to +-- the database character set. Because UTF16 is specified as the +-- character set, character-length semantics are used for the load. +-- +-- BYTEORDER LITTLE tells SQL*Loader that the data in the datafile is +-- in little-endian byte order. SQL*Loader checks the byte order of the +-- system on which it is running to determine if any byte-swapping is +-- necessary. In this example, all the character data in UTF16 is +-- byte-order dependent. +-- +-- The TERMINATED BY and OPTIONALLY ENCLOSED BY clauses both specify +-- hexadecimal strings. The X'002c' is the encoding for a comma (,) in +-- UTF-16 big-endian format. The X'0022' is the encoding for a double +-- quotation mark (") in big-endian format. Because the datafile is in +-- little-endian format, SQL*Loader swaps the bytes before checking for +-- a match. If these clauses were specified as character strings instead +-- of hexadecimal strings, SQL*Loader would convert the strings to the +-- datafile character set (UTF16) and byte-swap as needed before checking +-- for a match. +-- +-- Because character-length semantics are used, the maximum length for +-- the empno, hiredate, and deptno fields is interpreted as characters, +-- not bytes. +-- +-- The TERMINATED BY clause for the deptno field is specified using the +-- character string ":". SQL*Loader converts the string to the datafile +-- character set (UTF16) and byte-swaps as needed before checking for a match. + +LOAD DATA +CHARACTERSET utf16 +BYTEORDER little +INFILE ulcase11.dat +REPLACE + +INTO TABLE EMP +FIELDS TERMINATED BY X'002c' OPTIONALLY ENCLOSED BY X'0022' +(empno integer external (5), ename, job, mgr, + hiredate DATE(20) "DD-Month-YYYY", + sal, comm, + deptno CHAR(5) TERMINATED BY ":", + projno, + loadseq SEQUENCE(MAX,1) ) diff --git a/ulcase11.dat b/ulcase11.dat new file mode 100644 index 0000000..6817763 Binary files /dev/null and b/ulcase11.dat differ diff --git a/ulcase11.sql b/ulcase11.sql new file mode 100644 index 0000000..9109160 --- /dev/null +++ b/ulcase11.sql @@ -0,0 +1,40 @@ +Rem +Rem $Header: ulcase11.sql 06-feb-2001.14:26:12 rpfau Exp $ +Rem +Rem ulcase11.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem ulcase11.sql - Set up for SQL Loade example 11 +Rem +Rem DESCRIPTION +Rem Create table emp for example loading little endian unicode (UTF-16) +Rem data. +Rem +Rem NOTES +Rem None +Rem +Rem MODIFIED (MM/DD/YY) +Rem rpfau 02/06/01 - Merged rpfau_sqlldr_add_case_study_11 +Rem rpfau 01/30/01 - Created +Rem +set termout off + +rem host write sys$output "Building demonstration tables for case study 11. Please wait" + +drop table emp; + +create table emp + (empno number(4) not null, + ename char(10), + job char(9), + mgr number(4), + hiredate date, + sal number(7,2), + comm number(7,2), + deptno number(2), + projno number, + loadseq number); + +exit diff --git a/ulcase2.ctl b/ulcase2.ctl new file mode 100644 index 0000000..d7d2741 --- /dev/null +++ b/ulcase2.ctl @@ -0,0 +1,56 @@ +-- Copyright (c) 1991, 2004 Oracle. All rights reserved. +-- NAME +-- ulcase2.ctl - SQL*Loader Case Study 2: Loading Fixed-Format Files +-- +-- DESCRIPTION +-- This control file demonstrates the following: +-- Use of a separate data file. +-- +-- Data conversions. +-- +-- TO RUN THIS CASE STUDY: +-- 1. Before executing this control file, log in to SQL*Plus as +-- scott/tiger. Enter @ulcase1 to execute the SQL script for +-- this case study. This prepares and populates tables and +-- then returns you to the system prompt. It is the same script +-- used to prepare for case study 1, so if you have already +-- run case study 1, you can skip this step. +-- +-- 2. At the system prompt, invoke the case study as follows: +-- sqlldr USERID=scott/tiger CONTROL=ulcase2.ctl LOG=ulcase2.log +-- +-- NOTES ABOUT THIS CONTROL FILE +-- The LOAD DATA statement is required at the beginning of the +-- control file. +-- +-- The name of the file containing data follows the INFILE parameter. +-- +-- The INTO TABLE statement is required to identify the table to +-- be loaded into. +-- +-- empno, ename, job, and so on are names of columns in table emp. +-- The datatypes (INTEGER EXTERNAL, CHAR, DECIMAL EXTERNAL) identify +-- the datatype of data fields in the file, not of corresponding +-- columns in the emp table. +-- +-- Note that the set of column specifications is enclosed in +-- parentheses. +-- +-- Records loaded in this example from the emp table contain +-- department numbers. Unless the dept table is loaded first, +-- referential integrity checking rejects these records (if +-- referential integrity constraints are enabled for the emp table). + +-- +LOAD DATA +INFILE 'ulcase2.dat' +INTO TABLE EMP + +( EMPNO POSITION(01:04) INTEGER EXTERNAL, + ENAME POSITION(06:15) CHAR, + JOB POSITION(17:25) CHAR, + MGR POSITION(27:30) INTEGER EXTERNAL, + SAL POSITION(32:39) DECIMAL EXTERNAL, + COMM POSITION(41:48) DECIMAL EXTERNAL, + DEPTNO POSITION(50:51) INTEGER EXTERNAL) + diff --git a/ulcase2.dat b/ulcase2.dat new file mode 100644 index 0000000..e8ebbf6 --- /dev/null +++ b/ulcase2.dat @@ -0,0 +1,7 @@ +7782 CLARK MANAGER 7839 2572.50 10 +7839 KING PRESIDENT 5500.00 10 +7934 MILLER CLERK 7782 920.00 10 +7566 JONES MANAGER 7839 3123.75 20 +7499 ALLEN SALESMAN 7698 1600.00 300.00 30 +7654 MARTIN SALESMAN 7698 1312.50 1400.00 30 +7658 CHAN ANALYST 7566 3450.00 20 diff --git a/ulcase3.ctl b/ulcase3.ctl new file mode 100644 index 0000000..2d16635 --- /dev/null +++ b/ulcase3.ctl @@ -0,0 +1,83 @@ +-- Copyright (c) 1991, 2004 Oracle. All rights reserved. +-- NAME +-- ulcase3.ctl - SQL*Loader Case Study 3: Loading a Delimited, +-- Free-format File +-- +-- DESCRIPTION +-- This case study demonstrates the following: +-- Loading data (enclosed and terminated) in stream format. +-- +-- Loading dates using the DATE datatype. +-- +-- Using SEQUENCE numbers to generate unique keys for loaded data. +-- +-- Using APPEND to indicate that the table need not be empty before +-- inserting new records. +-- +-- Using comments in the control file set off by two hyphens. +-- +-- TO RUN THIS CASE STUDY: +-- 1. Before executing this control file, log in to SQL*Plus as +-- scott/tiger. Enter @ulcase3 to execute the SQL script for +-- this case study. This prepares and populates tables, adds +-- the projno and loadseq columns to table emp, and then returns +-- you to the system prompt. +-- +-- 2. At the system prompt, invoke the case study as follows: +-- sqlldr USERID=scott/tiger CONTROL=ulcase3.ctl LOG=ulcase3.log +-- +-- NOTES ABOUT THIS CONTROL FILE +-- This control file loads the same table as in case 2, but it +-- loads three additional columns (hiredate, projno, and loadseq). +-- The projno and loadseq columns are added to the emp table when +-- you run the ulcase3.sql script. +-- +-- INFILE * specifies that the data is found at the end of the +-- control file. +-- +-- APPEND specifies that the data can be loaded even if the table +-- already contains rows. That is, the table need not be empty. +-- +-- The default terminator for the data fields is a comma, and some +-- fields may be enclosed by double quotation marks ("). +-- +-- The data to be loaded into column hiredate appears in the format +-- DD-Month-YYYY. The length of the date field is specified to have +-- a maximum of 20. The maximum length is in bytes, with default +-- byte-length semantics. If character-length semantics were used +-- instead, the length would be in characters. If a length is not +-- specified, then the length depends on the length of the date mask. +-- +-- The SEQUENCE function generates a unique value in the column loadseq. +-- This function finds the current maximum value in column loadseq and +-- adds the increment (1) to it to obtain the value for loadseq for +-- each row inserted. +-- +-- BEGINDATA specifies the end of the control information and the +-- beginning of the data. +-- +-- Although each physical record equals one logical record, the fields +-- vary in length, so that some records are longer than others. Note +-- also that several rows have null values for comm. + +LOAD DATA +INFILE * +APPEND + +INTO TABLE EMP +FIELDS TERMINATED BY "," OPTIONALLY ENCLOSED BY '"' +(empno, ename, job, mgr, + hiredate DATE(20) "DD-Month-YYYY", + sal, comm, + deptno CHAR TERMINATED BY ':', + projno, + loadseq SEQUENCE(MAX,1) ) + +BEGINDATA +7782, "Clark", "Manager", 7839, 09-June-1981, 2572.50,, 10:101 +7839, "King", "President", , 17-November-1981, 5500.00,, 10:102 +7934, "Miller", "Clerk", 7782, 23-January-1982, 920.00,, 10:102 +7566, "Jones", "Manager", 7839, 02-April-1981, 3123.75,, 20:101 +7499, "Allen", "Salesman", 7698, 20-February-1981, 1600.00, 300.00, 30:103 +7654, "Martin", "Salesman", 7698, 28-September-1981, 1312.50, 1400.00, 30:103 +7658, "Chan", "Analyst", 7566, 03-May-1982, 3450,, 20:101 diff --git a/ulcase3.sql b/ulcase3.sql new file mode 100644 index 0000000..e233df3 --- /dev/null +++ b/ulcase3.sql @@ -0,0 +1,31 @@ +rem +rem $Header: ulcase3.sql 14-jul-99.14:23:36 mjaeger Exp $ +rem +rem Copyright (c) 1991, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem ulcase3.sql - +rem DESCRIPTION +rem +rem RETURNS +rem +rem NOTES +rem ulcase2.sql must be executed before this pocedure. +rem MODIFIED (MM/DD/YY) +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem jstenois 06/17/99 - cleanup tables before load and show feedback +rem ksudarsh 03/11/93 - comment out vms specific host command +rem ksudarsh 12/29/92 - Creation +rem cheigham 08/28/91 - Creation +rem + +set termout off + +rem Do not clean up table because this example shows appending to existing +rem rows in table that also has new columns. + +rem host write sys$output "Adding columns to emp. Please wait." + +alter table emp add (projno number, loadseq number); + +exit diff --git a/ulcase4.ctl b/ulcase4.ctl new file mode 100644 index 0000000..2bd522f --- /dev/null +++ b/ulcase4.ctl @@ -0,0 +1,76 @@ +-- Copyright (c) 1991, 2004 Oracle. All rights reserved. +-- NAME +-- ulcase4.ctl - SQL*Loader Case Study 4: Loading Combined Physical Records +-- +-- DESCRIPTION +-- This case study demonstrates the following: +-- Combining multiple physical records to form one logical +-- record with CONTINUEIF. +-- +-- Inserting negative numbers. +-- +-- Using REPLACE to indicate that the table should be emptied +-- before the new data is inserted. +-- +-- Specifying a discard file in the control file using DISCARDFILE. +-- +-- Specifying a maximum number of discards using DISCARDMAX. +-- +-- Rejecting records due to duplicate values in a unique index +-- or due to invalid data values. +-- +-- TO RUN THIS CASE STUDY: +-- 1. Before executing this control file, log in to SQL*Plus as +-- scott/tiger. Enter @ulcase4 to execute the SQL script for +-- this case study. This prepares and populates tables and +-- then returns you to the system prompt. +-- +-- 2. At the system prompt, invoke the case study as follows: +-- sqlldr USERID=scott/tiger CONTROL=ulcase4.ctl LOG=ulcase4.log +-- +-- NOTES ABOUT THIS CONTROL FILE +-- DISCARDFILE specifies a discard file named ulcase4.dsc. +-- +-- DISCARDMAX specifies a maximum of 999 discards allowed before +-- terminating the run. For all practical purposes, this allows +-- all discards for this test case. In real-world situations, +-- there may well be more than 999 discarded records. +-- +-- REPLACE specifies that if there is data in the table being loaded, +-- then SQL*Loader should delete that data before loading new data. +-- +-- CONTINUEIF specifies that if an asterisk is found in column 1 +-- of the current record, then the next physical record after that +-- record should be appended to it from the logical record. Note that +-- column 1 in each physical record should then contain either an +-- asterisk or a nondata value. +-- +-- The data file (ulcase4.dat) for this case study shows asterisks +-- in the first position and, though not visible, a newline character +-- is in position 20. Note that clark's commission is -10, and +-- SQL*Loader loads the value, converting it to a negative number. +-- +-- The resulting log file will show that the last two records are +-- rejected, given two assumptions. If a unique index is created on +-- column empno, then the record for chin will be rejected because +-- his empno is identical to chan's. If empno is defined as NOT NULL, +-- then chen's record will be rejected because it has no value for +-- empno. + +-- +LOAD DATA +INFILE "ulcase4.dat" +DISCARDFILE "ulcase4.dsc" +DISCARDMAX 999 +REPLACE +CONTINUEIF (1) = '*' +INTO TABLE EMP + +( EMPNO POSITION(01:04) INTEGER EXTERNAL, + ENAME POSITION(06:15) CHAR, + JOB POSITION(17:25) CHAR, + MGR POSITION(27:30) INTEGER EXTERNAL, + SAL POSITION(32:39) DECIMAL EXTERNAL, + COMM POSITION(41:48) DECIMAL EXTERNAL, + DEPTNO POSITION(50:51) INTEGER EXTERNAL, + HIREDATE POSITION(52:60) INTEGER EXTERNAL) diff --git a/ulcase4.dat b/ulcase4.dat new file mode 100644 index 0000000..6696bb0 --- /dev/null +++ b/ulcase4.dat @@ -0,0 +1,18 @@ +*7782 CLARK MA + NAGER 7839 2572.50 -10 2512-NOV-85 +*7839 KING PR + ESIDENT 5500.00 2505-APR-83 +*7934 MILLER CL + ERK 7782 920.00 2508-MAY-80 +*7566 JONES MA + NAGER 7839 3123.75 2517-JUL-85 +*7499 ALLEN SA + LESMAN 7698 1600.00 300.00 25 3-JUN-84 +*7654 MARTIN SA + LESMAN 7698 1312.50 1400.00 2521-DEC-85 +*7658 CHAN AN + ALYST 7566 3450.00 2516-FEB-84 +* CHEN AN + ALYST 7566 3450.00 2516-FEB-84 +*7658 CHIN AN + ALYST 7566 3450.00 2516-FEB-84 diff --git a/ulcase4.sql b/ulcase4.sql new file mode 100644 index 0000000..b1b0ac5 --- /dev/null +++ b/ulcase4.sql @@ -0,0 +1,37 @@ +rem +rem $Header: ulcase4.sql 14-jul-99.14:24:22 mjaeger Exp $ +rem +rem Copyright (c) 1990, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem +rem FUNCTION +rem NOTES +rem MODIFIED (MM/DD/YY) +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem jstenois 06/17/99 - cleanup tables before load and show feedback +rem ksudarsh 03/11/93 - comment out vms specific host command +rem ksudarsh 12/29/92 - Creation +rem cheigham 08/28/91 - Creation +rem Heigham 11/21/90 - create UNIQUE index +rem + +set termout off + +rem host write sys$output "Building case 4 demonstration tables. Please wait" + +drop table emp; + +create table emp + (empno number(4) not null, + ename char(10), + job char(9), + mgr number(4), + hiredate date, + sal number(7,2), + comm number(7,2), + deptno number(2)); + +create unique index empix on emp(empno); + +exit diff --git a/ulcase5.ctl b/ulcase5.ctl new file mode 100644 index 0000000..34c550d --- /dev/null +++ b/ulcase5.ctl @@ -0,0 +1,72 @@ +-- Copyright (c) 1991, 2004 Oracle. All rights reserved. +-- NAME +-- ulcase5.ctl - SQL*Loader Case Study 5: Loading Data Into Multiple Tables +-- DESCRIPTION +-- This case study demonstrates the following: +-- Loading multiple tables. +-- +-- Using SQL*Loader to break down repeating groups in a flat file +-- and to load the data into normalized tables. In this way, one +-- file record may generate multiple database rows. +-- +-- Deriving multiple logical records from each physical record. +-- +-- Using a WHEN clause. +-- +-- Loading the same field (empno) into multiple tables. +-- +-- TO RUN THIS CASE STUDY: +-- 1. Before executing this control file, log in to SQL*Plus as +-- scott/tiger. Enter @ulcase5 to execute the SQL script for +-- this case study. This prepares and populates tables and +-- then returns you to the system prompt. +-- +-- 2. At the system prompt, invoke the case study as follows: +-- sqlldr USERID=scott/tiger CONTROL=ulcase5.ctl LOG=ulcase5.log +-- +-- NOTES ABOUT THIS CONTROL FILE +-- REPLACE specifies that if there is data in the tables to be +-- loaded (emp and proj), SQL*loader should delete the data before +-- loading new rows. +-- +-- Multiple INTO TABLE clauses load two tables, emp and proj. +-- The same set of records is processed three times, using different +-- combinations of columns each time to load table proj. +-- +-- WHEN loads only rows with nonblank project numbers. When projno +-- is defined as columns 25...27, rows are inserted into proj only +-- if there is a value in those columns. +-- +-- When projno is defined as columns 29...31, rows are inserted +-- into proj only if there is a value in those columns. +-- +-- When projno is defined as columns 33...35, rows are inserted +-- into proj only if there is a value in those columns. +-- +LOAD DATA +INFILE 'ulcase5.dat' +BADFILE 'ulcase5.bad' +DISCARDFILE 'ulcase5.dsc' +REPLACE + +INTO TABLE EMP + (EMPNO POSITION(1:4) INTEGER EXTERNAL, + ENAME POSITION(6:15) CHAR, + DEPTNO POSITION(17:18) CHAR, + MGR POSITION(20:23) INTEGER EXTERNAL) + +INTO TABLE PROJ +-- PROJ has two columns, both not null: EMPNO and PROJNO +WHEN PROJNO != ' ' + (EMPNO POSITION(1:4) INTEGER EXTERNAL, + PROJNO POSITION(25:27) INTEGER EXTERNAL) -- 1st proj + +INTO TABLE PROJ +WHEN PROJNO != ' ' + (EMPNO POSITION(1:4) INTEGER EXTERNAL, + PROJNO POSITION(29:31) INTEGER EXTERNAL) -- 2nd proj + +INTO TABLE PROJ +WHEN PROJNO != ' ' + (EMPNO POSITION(1:4) INTEGER EXTERNAL, + PROJNO POSITION(33:35) INTEGER EXTERNAL) -- 3rd proj diff --git a/ulcase5.dat b/ulcase5.dat new file mode 100644 index 0000000..2da50bb --- /dev/null +++ b/ulcase5.dat @@ -0,0 +1,12 @@ +1234 BAKER 10 9999 101 102 103 +1234 JOKER 10 9999 777 888 999 +2664 YOUNG 20 2893 425 abc 102 +5321 OTOOLE 10 9999 321 55 40 +2134 FARMER 20 4555 236 456 +2414 LITTLE 20 5634 236 456 40 +6542 LEE 10 4532 102 321 14 +2849 EDDS xx 4555 294 40 +4532 PERKINS 10 9999 40 +1244 HUNT 11 3452 665 133 456 + 123 DOOLITTLE 12 9940 132 +1453 MACDONALD 25 5532 200 diff --git a/ulcase5.sql b/ulcase5.sql new file mode 100644 index 0000000..a15e56d --- /dev/null +++ b/ulcase5.sql @@ -0,0 +1,47 @@ +rem +rem $Header: ulcase5.sql 20-jul-99.18:06:21 cmlim Exp $ +rem +rem Copyright (c) 1991, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem ulcase5.sql - +rem DESCRIPTION +rem +rem RETURNS +rem +rem NOTES +rem +rem MODIFIED (MM/DD/YY) +Rem cmlim 07/20/99 - add unique index on empno +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem jstenois 06/17/99 - cleanup tables before load and show feedback +rem ksudarsh 03/11/93 - comment out vms specific host command +rem ksudarsh 12/29/92 - Creation +rem cheigham 08/28/91 - Creation +rem + +set termout off + +rem host write sys$output "Building case 5 demonstration tables. Please wait" + +drop table emp; + +drop table proj; + +create table emp + (empno number(4) not null, + ename char(10), + job char(9), + mgr number(4), + hiredate date, + sal number(7,2), + comm number(7,2), + deptno number(2)); + +create unique index empix on emp(empno); + +create table proj + (empno number, + projno number); + +exit diff --git a/ulcase6.ctl b/ulcase6.ctl new file mode 100644 index 0000000..0709b7f --- /dev/null +++ b/ulcase6.ctl @@ -0,0 +1,47 @@ +-- Copyright (c) 1991, 2004 Oracle. All rights reserved. +-- NAME +-- ulcase6.ctl - SQL*Loader Case Study 6: Loading Data Using the +-- Direct Path Load Method +-- +-- DESCRIPTION +-- This case study demonstrates the following: +-- Use of the direct path load method to load and index data. +-- +-- How to specify the indexes for which the data is presorted. +-- +-- Use of the NULLIF clause. +-- +-- Loading all-blank numeric fields as NULL. +-- +-- TO RUN THIS CASE STUDY: +-- 1. Before executing this control file, log in to SQL*Plus as +-- scott/tiger. Enter @ulcase6 to execute the SQL script for +-- this case study. This prepares and populates tables and +-- then returns you to the system prompt. +-- +-- 2. At the system prompt, invoke the case study as follows: +-- sqlldr USERID=scott/tiger CONTROL=ulcase6.ctl LOG=ulcase6.log DIRECT=TRUE +-- +-- NOTES ABOUT THIS CONTROL FILE +-- The SORTED INDEXES statement identifies the indexes on which +-- the data is sorted. This statement indicates that the datafile +-- is sorted on the columns in the empix index. It allows +-- SQL*Loader to optimize index creation by eliminating the sort +-- phase for this data when using the direct path load method. +-- +-- The NULLIF...BLANKS clause specifies that the column should +-- be loaded as NULL if the field in the datafile consists of +-- all blanks. +-- +LOAD DATA +INFILE 'ulcase6.dat' +REPLACE +INTO TABLE emp +SORTED INDEXES (empix) +(empno POSITION(1:4), +ename POSITION(6:15), +job POSITION(17:25), +mgr POSITION(27:30) NULLIF mgr=blanks, +sal POSITION(32:39) NULLIF sal=blanks, +comm POSITION(41:48) NULLIF comm=blanks, +deptno POSITION(50:51) NULLIF empno=blanks) diff --git a/ulcase6.dat b/ulcase6.dat new file mode 100644 index 0000000..82ebd9e --- /dev/null +++ b/ulcase6.dat @@ -0,0 +1,7 @@ +7499 ALLEN SALESMAN 7698 1600.00 300.00 30 +7566 JONES MANAGER 7839 3123.75 20 +7654 MARTIN SALESMAN 7698 1312.50 1400.00 30 +7658 CHAN ANALYST 7566 3450.00 20 +7782 CLARK MANAGER 7839 2572.50 10 +7839 KING PRESIDENT 5500.00 10 +7934 MILLER CLERK 7782 920.00 10 diff --git a/ulcase6.sql b/ulcase6.sql new file mode 100644 index 0000000..3322af1 --- /dev/null +++ b/ulcase6.sql @@ -0,0 +1,41 @@ +rem +rem $Header: ulcase6.sql 14-jul-99.14:25:48 mjaeger Exp $ +rem +rem Copyright (c) 1991, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem ulcase6.sql - +rem DESCRIPTION +rem +rem RETURNS +rem +rem NOTES +rem +rem MODIFIED (MM/DD/YY) +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem jstenois 06/17/99 - cleanup tables before load and show feedback +rem ksudarsh 02/21/94 - create unique index "empix" +rem ksudarsh 03/11/93 - comment out vms specific host command +rem ksudarsh 12/29/92 - Creation +rem ksudarsh 12/28/92 - Don't drop dept +rem cheigham 08/28/91 - Creation +rem cheigham 03/19/91 - Creation + +set termout off +rem host write sys$output "Building case 6 demonstration tables. Please wait" + +drop table emp; + +create table emp + (empno number(4) not null, + ename char(10), + job char(9), + mgr number(4), + hiredate date, + sal number(7,2), + comm number(7,2), + deptno number(2)); + +create unique index empix on emp(empno); + +exit diff --git a/ulcase7.ctl b/ulcase7.ctl new file mode 100644 index 0000000..412cf59 --- /dev/null +++ b/ulcase7.ctl @@ -0,0 +1,104 @@ +-- Copyright (c) 1991, 2004 Oracle. All rights reserved. +-- NAME +-- ulcase7.ctl - Extracting Data From a Formatted Report +-- +-- DESCRIPTION +-- This case study demonstrates the following: +-- Use of SQL*Loader with an INSERT trigger. +-- +-- Use of the SQL string to manipulate data. +-- +-- Use of different initial and trailing delimiters. +-- +-- Use of SYSDATE. +-- +-- Use of the TRAILING NULLCOLS clause. +-- +-- Ambiguous field length warnings. +-- +-- Use of a discard file. +-- +-- TO RUN THIS CASE STUDY: +-- 1. Before executing this control file, log in to SQL*Plus as +-- scott/tiger. Enter @ulcase7s to execute the SQL script for +-- this case study. This creates a BEFORE INSERT trigger that +-- is required to fill in the department number, job name, +-- and manager's number when these fields are not present on +-- a data line. When values are present, they should be saved +-- in a global variable. When values are not present, the +-- global variables are used. +-- +-- 2. At the system prompt, invoke the case study as follows: +-- sqlldr USERID=scott/tiger CONTROL=ulcase7.ctl LOG=ulcase7.log +-- +-- 3. After you have run the case study and finished with it, you +-- must run the ulcase7e.sql script before you can successfully +-- run other case studies. This script drops the INSERT trigger +-- and the global variables package. Log in to SQL*Plus as +-- scott/tiger. Enter @ulcase7e. +-- +-- NOTES ABOUT THIS CONTROL FILE +-- The WHEN (57) = '.' clause indicates that the decimal point +-- in column 57 (the salary field) identifies a line with data +-- on it. All other lines in the report are discarded. +-- +-- The TRAILING NULLCOLS clause causes SQL*Loader to treat any fields +-- that are missing at the end of a record as null. Because the +-- commission field is not present for every record, this clause says +-- to load a null commission instead of rejecting the record when only +-- seven fields are found instead of the expected eight. +-- +-- The hiredate is filled in using the current system date (SYSDATE). +-- +-- The specification for deptno will generate a warning message in +-- the log file because the specified length does not agree with +-- the length determined by the field's position. The specified +-- length (3) is used. The length is in bytes with the default +-- byte-length semantics. If character-length semantics were used +-- instead, this length would be in characters. +-- +-- The NULLIF clause says that because the report shows only department +-- number, job, and manager when the value changes, these fields may +-- be blank. This control file causes them to be loaded as null, and +-- an insert trigger fills in the last valid value. +-- +-- For the job field, the SQL string changes the job name to +-- uppercase letters. +-- +-- For the mgr field, it is necessary to specify starting position. +-- If the job field and the manager field were both blank, then the +-- job field's TERMINATED BY WHITESPACE clause would cause SQL*Loader +-- to scan forward to the employee name field. Without the POSITION +-- clause, the employee name field would be mistakenly interpreted +-- as the manager field. +-- +-- For the sal field, the SQL string translates the field from a +-- formatted character string into a number. The numeric value takes +-- less space and can be printed with a variety of formatting options. +-- +-- For the comm field, different initial and trailing delimiters pick the +-- numeric value out of a formatted field. The SQL string then converts +-- the value to its stored form. +-- +LOAD DATA +INFILE 'ulcase7.dat' +DISCARDFILE 'ulcase7.dsc' +APPEND +INTO TABLE emp + WHEN (57)='.' + TRAILING NULLCOLS + (hiredate SYSDATE, + deptno POSITION(1:2) INTEGER EXTERNAL(3) + NULLIF deptno=BLANKS, + job POSITION(7:14) CHAR TERMINATED BY WHITESPACE + NULLIF job=BLANKS "UPPER(:job)", + mgr POSITION(28:31) INTEGER EXTERNAL TERMINATED BY WHITESPACE + NULLIF mgr=BLANKS, + ename POSITION (34:41) CHAR TERMINATED BY WHITESPACE + "UPPER(:ename)", + empno INTEGER EXTERNAL TERMINATED BY WHITESPACE, + sal POSITION(51) CHAR TERMINATED BY WHITESPACE + "TO_NUMBER(:sal,'$99,999.99')", + comm INTEGER EXTERNAL ENCLOSED BY '(' AND '%' + ":comm * 100" + ) diff --git a/ulcase7.dat b/ulcase7.dat new file mode 100644 index 0000000..7b5188f --- /dev/null +++ b/ulcase7.dat @@ -0,0 +1,13 @@ + + + Today's Newly Hired Employees + +Dept Job Manager MgrNo Emp Name EmpNo Salary/Commission +---- -------- -------- ----- -------- ----- ----------------- +20 Salesman Blake 7698 Shepard 8061 $1,600.00 (3%) + Falstaff 8066 $1,250.00 (5%) + Major 8064 $1,250.00 (14%) + +30 Clerk Scott 7788 Conrad 8062 $1,100.00 + Ford 7369 DeSilva 8063 $800.00 + Manager King 7839 Provo 8065 $2,975.00 diff --git a/ulcase7e.sql b/ulcase7e.sql new file mode 100644 index 0000000..584453c --- /dev/null +++ b/ulcase7e.sql @@ -0,0 +1,30 @@ +rem +rem $Header: ulcase7e.sql 14-jul-99.14:26:51 mjaeger Exp $ +rem +rem Copyright (c) 1991, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem ulcase7e.sql - +rem DESCRIPTION +rem +rem RETURNS +rem +rem NOTES +rem +rem MODIFIED (MM/DD/YY) +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem jstenois 06/17/99 - cleanup tables before load and show feedback +rem ksudarsh 03/11/93 - comment out vms specific host command +rem ksudarsh 12/30/92 - Creation +rem ksudarsh 12/27/92 - Creation +rem +rem ULDEMO7E.SQL +rem End-script for SQL*Loader Examples, Case 7 + +set termout off +rem host write sys$output "Cleaning up Case 7 Trigger and Package." + +DROP PACKAGE uldemo7; +DROP TRIGGER uldemo7_emp_insert; + +EXIT diff --git a/ulcase7s.sql b/ulcase7s.sql new file mode 100644 index 0000000..48173cf --- /dev/null +++ b/ulcase7s.sql @@ -0,0 +1,68 @@ +rem +rem $Header: ulcase7s.sql 26-jul-99.09:39:37 mjaeger Exp $ +rem +rem Copyright (c) 1991, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem ulcase7s.sql - +rem DESCRIPTION +rem +rem RETURNS +rem +rem NOTES +rem +rem MODIFIED (MM/DD/YY) +rem mjaeger 07/26/99 - bug 808870: OCCS: convert tabs, no long lines +rem jstenois 06/17/99 - cleanup tables before load and show feedback +rem ksudarsh 03/11/93 - comment out vms specific host command +rem ksudarsh 12/30/92 - Creation +rem ksudarsh 12/27/92 - Creation +rem +rem ULDEMO7S.SQL +rem Start-script for SQL*Loader Examples, Case 7 + +rem The variables the insert-trigger uses to save the last valid value +rem are defined in a package so they will persist between calls. + +rem Since these values will be accessed by anyone inserting into EMP, only +rem the user doing the load should have access to EMP during this time +rem (Alternatively, the trigger could be modified to check the USERENV fnction +rem in a WHEN clause and only perform its functions for a particular user.) + +set termout off +rem host write sys$output "Building Package and Trigger for Case 7.Please wait" + +CREATE OR REPLACE PACKAGE uldemo7 AS + last_deptno NUMBER; + last_job CHAR(9); + last_mgr NUMBER; +END uldemo7; +/ + +CREATE OR REPLACE TRIGGER uldemo7_emp_insert + BEFORE INSERT ON emp + FOR EACH ROW + + BEGIN + IF :new.deptno IS NOT NULL THEN + uldemo7.last_deptno := :new.deptno; -- save value for later use + ELSE + :new.deptno := uldemo7.last_deptno; -- use last valid value + END IF; + + IF :new.job IS NOT NULL THEN + uldemo7.last_job := :new.job; -- save value for later use + ELSE + :new.job := uldemo7.last_job; -- use last valid value + END IF; + + IF :new.mgr IS NOT NULL THEN + uldemo7.last_mgr := :new.mgr; -- save value for later use + ELSE + :new.mgr := uldemo7.last_mgr; -- use last valid value + END IF; + + END; +/ + +EXIT diff --git a/ulcase8.ctl b/ulcase8.ctl new file mode 100644 index 0000000..d984c50 --- /dev/null +++ b/ulcase8.ctl @@ -0,0 +1,53 @@ +-- Copyright (c) 1991, 2004 Oracle. All rights reserved. +-- NAME +-- ulcase8.ctl - SQL*Loader Case Study 8: Loading Partitioned Tables +-- +-- DESCRIPTION +-- This case study demonstrates the following: +-- Partitioning of data. +-- +-- Explicitly defined field positions and datatypes. +-- +-- Loading data using the fixed-record-length option. +-- +-- TO RUN THIS CASE STUDY: +-- 1. Before executing this control file, log in to SQL*Plus as +-- scott/tiger. Enter @ulcase8 to execute the SQL script for +-- this case study. This prepares and populates tables and +-- then returns you to the system prompt. +-- +-- 2. At the system prompt, invoke the case study as follows: +-- sqlldr USERID=scott/tiger CONTROL=ulcase8.ctl LOG=ulcase8.log +-- +-- NOTES ABOUT THIS CONTROL FILE +-- This control file loads the lineitem table with fixed-length +-- records, partitioning the data according to shipment date. +-- +-- The INFILE clause specifies that each record in the datafile is +-- of fixed length (129 bytes in this example). +-- +-- The PARTITION clause identifies the column name and location of the +-- data in the datafile to be loaded into each column. +-- +LOAD DATA + INFILE 'ulcase8.dat' "fix 129" +BADFILE 'ulcase8.bad' +TRUNCATE +INTO TABLE lineitem +PARTITION (ship_q1) + (l_orderkey position (1:6) char, + l_partkey position (7:11) char, + l_suppkey position (12:15) char, + l_linenumber position (16:16) char, + l_quantity position (17:18) char, + l_extendedprice position (19:26) char, + l_discount position (27:29) char, + l_tax position (30:32) char, + l_returnflag position (33:33) char, + l_linestatus position (34:34) char, + l_shipdate position (35:43) char, + l_commitdate position (44:52) char, + l_receiptdate position (53:61) char, + l_shipinstruct position (62:78) char, + l_shipmode position (79:85) char, + l_comment position (86:128) char) diff --git a/ulcase8.dat b/ulcase8.dat new file mode 100644 index 0000000..ba7b258 --- /dev/null +++ b/ulcase8.dat @@ -0,0 +1,10 @@ + 1 151978511724386.60 7.04.0NO09-SEP-6412-FEB-9622-MAR-96DELIVER IN PERSONTRUCK iPBw4mMm7w7kQ zNPL i261OPP + 1 2731 73223658958.28.09.06NO12-FEB-9628-FEB-9620-APR-96TAKE BACK RETURN MAIL 5wM04SNyl0AnghCP2nx lAi + 1 3370 3713 810210.96 .1.02NO29-MAR-9605-MAR-9631-JAN-96TAKE BACK RETURN REG AIRSQC2C 5PNCy4mM + 1 5214 46542831197.88.09.06NO21-APR-9630-MAR-9616-MAY-96NONE AIR Om0L65CSAwSj5k6k + 1 6564 6763246897.92.07.02NO30-MAY-9607-FEB-9603-FEB-96DELIVER IN PERSONMAIL CB0SnyOL PQ32B70wB75k 6Aw10m0wh + 1 7403 160524 31329.6 .1.04NO30-JUN-9614-MAR-9601 APR-96NONE FOB C2gOQj OB6RLk1BS15 igN + 2 8819 82012441659.44 0.08NO05-AUG-9609-FEB-9711-MAR-97COLLECT COD AIR O52M70MRgRNnmm476mNm + 3 9451 721230 41113.5.05.01AF05-SEP-9629-DEC-9318-FEB-94TAKE BACK RETURN FOB 6wQnO0Llg6y + 3 9717 1834440788.44.07.03RF09-NOV-9623-DEC-9315-FEB-94TAKE BACK RETURN SHIP LhiA7wygz0k4g4zRhMLBAM + 3 9844 1955 6 8066.64.04.01RF28-DEC-9615-DEC-9314-FEB-94TAKE BACK RETURN REG AIR6nmBmjQkgiCyzCQBkxPPOx5j4hB 0lRywgniP1297 diff --git a/ulcase8.sql b/ulcase8.sql new file mode 100644 index 0000000..2734cd6 --- /dev/null +++ b/ulcase8.sql @@ -0,0 +1,58 @@ +rem +Rem $Header: ulcase8.sql 20-jul-99.18:20:38 cmlim Exp $ +rem +rem ulcase8.sql +rem +rem Copyright (c) 1998, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem ulcase8.sql - Setup for SQL Loader example 8 +rem +rem DESCRIPTION +rem Create partitioned table for example 8 +rem +rem NOTES +rem Note that all partitions are created in the default tablespace. +rem Normally, each partition would be in a saparate tablespace, but we +rem use the same tablespace to keep the example simple. +rem +rem MODIFIED (MM/DD/YY) +Rem cmlim 07/20/99 - fix syntax for create table +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem jstenois 06/17/99 - cleanup tables before load and show feedback +rem jstenois 11/06/98 - example of loading fix record length file +rem jstenois 11/06/98 - Created +rem + +set termout off + +rem host write sys$output "Building case 8 demonstration tables. Please wait" + +drop table lineitem; + +create table lineitem +(l_orderkey number, +l_partkey number, +l_suppkey number, +l_linenumber number, +l_quantity number, +l_extendedprice number, +l_discount number, +l_tax number, +l_returnflag char, +l_linestatus char, +l_shipdate date, +l_commitdate date, +l_receiptdate date, +l_shipinstruct char(17), +l_shipmode char(7), +l_comment char(43)) +partition by range (l_shipdate) +( +partition ship_q1 values less than (TO_DATE('01-APR-1996', 'DD-MON-YYYY')), +partition ship_q2 values less than (TO_DATE('01-JUL-1996', 'DD-MON-YYYY')), +partition ship_q3 values less than (TO_DATE('01-OCT-1996', 'DD-MON-YYYY')), +partition ship_q4 values less than (TO_DATE('01-JAN-1997', 'DD-MON-YYYY')) +); + +exit diff --git a/ulcase9.ctl b/ulcase9.ctl new file mode 100644 index 0000000..3f7de41 --- /dev/null +++ b/ulcase9.ctl @@ -0,0 +1,66 @@ +-- Copyright (c) 1991, 2004 Oracle. All rights reserved. +-- NAME +-- ulcase9.ctl - SQL*Loader Case Study 9: Loading LOBFILEs (CLOBs) +-- +-- DESCRIPTION +-- This case study demonstrates the following: +-- Adding a CLOB column called resume to table emp. +-- +-- Using a filler field (res_file). +-- +-- Loading multiple LOBFILEs into the emp table. +-- +-- TO RUN THIS CASE STUDY: +-- 1. Before executing this control file, log in to SQL*Plus as +-- scott/tiger. Enter @ulcase9 to execute the SQL script for +-- this case study. This prepares and populates tables and +-- then returns you to the system prompt. +-- +-- 2. At the system prompt, invoke the case study as follows: +-- sqlldr USERID=scott/tiger CONTROL=ulcase9.ctl LOG=ulcase9.log +-- +-- NOTES ABOUT THIS CONTROL FILE +-- This is an example of using SQL Loader to load LOBs from +-- secondary data file. +-- +-- There is one file per resume (the "TERMINATED BY EOF" clause +-- indicates this) and the name of the file containing the resume +-- is in field res_file. +-- +-- res_file is a filler field. The filler field is assigned values +-- from the data field to which it is mapped. This means that the +-- file name stored in the field is not loaded into any field in +-- the table. +-- +-- The resume column is loaded as a CLOB. The LOBFILE function specifies +-- the field name in which the name of the file that contains data for +-- LOB field is provided. +-- +-- The field name for column RESUME is in quotation marks because +-- RESUME is also a keyword for SQL*Loader. The quotation marks force +-- SQL*Loader to treat it as a column name instead. +-- +LOAD DATA +INFILE * +INTO TABLE EMP +REPLACE +FIELDS TERMINATED BY ',' +( EMPNO INTEGER EXTERNAL, + ENAME CHAR, + JOB CHAR, + MGR INTEGER EXTERNAL, + SAL DECIMAL EXTERNAL, + COMM DECIMAL EXTERNAL, + DEPTNO INTEGER EXTERNAL, + RES_FILE FILLER CHAR, + "RESUME" LOBFILE (RES_FILE) TERMINATED BY EOF NULLIF RES_FILE = 'NONE' +) + +BEGINDATA +7782,CLARK,MANAGER,7839,2572.50,,10,ulcase91.dat +7839,KING,PRESIDENT,,5500.00,,10,ulcase92.dat +7934,MILLER,CLERK,7782,920.00,,10,ulcase93.dat +7566,JONES,MANAGER,7839,3123.75,,20,ulcase94.dat +7499,ALLEN,SALESMAN,7698,1600.00,300.00,30,ulcase95.dat +7654,MARTIN,SALESMAN,7698,1312.50,1400.00,30,ulcase96.dat +7658,CHAN,ANALYST,7566,3450.00,,20,NONE diff --git a/ulcase9.sql b/ulcase9.sql new file mode 100644 index 0000000..363e0da --- /dev/null +++ b/ulcase9.sql @@ -0,0 +1,41 @@ +rem +rem $Header: ulcase9.sql 14-jul-99.14:28:05 mjaeger Exp $ +rem +rem ulcase9.sql +rem +rem Copyright (c) 1998, 1999, Oracle Corporation. All rights reserved. +rem +rem NAME +rem ulcase9.sql - setup for SQL Loader example 9 +rem +rem DESCRIPTION +rem Add RESUME column to EMP for example of using SQL Loader to load LOBs +rem +rem NOTES +rem Assumes an EMP table already exists +rem +rem MODIFIED (MM/DD/YY) +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem jstenois 06/17/99 - cleanup tables before load and show feedback +rem jstenois 10/26/98 - demo of 8.1 features for sqlldr +rem jstenois 10/26/98 - Created +rem + +set termout off + +rem host write sys$output "Building case 9 demonstration tables. Please wait" + +drop table emp; + +create table emp + (empno number(4) not null, + ename char(10), + job char(9), + mgr number(4), + hiredate date, + sal number(7,2), + comm number(7,2), + deptno number(2), + resume clob); + +exit diff --git a/ulcase91.dat b/ulcase91.dat new file mode 100644 index 0000000..1e0e5ad --- /dev/null +++ b/ulcase91.dat @@ -0,0 +1,14 @@ + Resume for Mary Clark + +Career Objective: Manage a sales team with consistent record breaking + performance. + +Education: BA Business University of Iowa 1992 + +Experience: 1992-1994 - Sales Support at MicroSales Inc. + Won "Best Sales Support" award in 1993 and 1994 + + 1994-Present - Sales Manager at MicroSales Inc. + Most sales in mid-South division for 2 years + + diff --git a/ulcase92.dat b/ulcase92.dat new file mode 100644 index 0000000..3cb4e3a --- /dev/null +++ b/ulcase92.dat @@ -0,0 +1,23 @@ + Resume for Monica King + +Career Objective: President of large computer services company + +Education: BA English Literature Bennington, 1985 + +Experience: 1985-1986 - Mailroom at New World Services + + 1986-1987 - Secretary for sales management at New World + Services + + 1988-1989 - Sales support at New World Services + + 1990-1992 - Saleman at New World Services + + 1993-1994 - Sales Manager at New World Services + + 1995 - Vice President of Sales and Marketing at New + World Services + + 1996-Present - President of New World Services + + diff --git a/ulcase93.dat b/ulcase93.dat new file mode 100644 index 0000000..4d94cd9 --- /dev/null +++ b/ulcase93.dat @@ -0,0 +1,7 @@ + Resume for Dan Miller + +Career Objective: Work as a sales support specialist for a services company + +Education: Plainview High School, 1996 + +Experience: 1996 - Present: Mail room clerk at New World Services diff --git a/ulcase94.dat b/ulcase94.dat new file mode 100644 index 0000000..cc0b62a --- /dev/null +++ b/ulcase94.dat @@ -0,0 +1,15 @@ + Resume for Alyson Jones + +Career Objective: Work in senior sales management for a vibrant and + growing company + +Education: BA Philosophy Howard Univerity 1993 + +Experience: 1993 - Sales Support for New World Services + + 1994-1995 - Salesman for New World Services. Led in US + sales in both 1994 and 1995. + + 1996 - present - Sales Manager New World Services. My sales + team has beat its quota by at least 15% each year. + diff --git a/ulcase95.dat b/ulcase95.dat new file mode 100644 index 0000000..f96d785 --- /dev/null +++ b/ulcase95.dat @@ -0,0 +1,10 @@ + Resume for David Allen + +Career Objective: Senior Sales man for agressive Services company + +Education: BS Business Administration, Weber State 1994 + +Experience: 1993-1994 - Sales Support New World Services + + 1994-present - Salesman at New World Service. Won sales award for + exceeding sales quota by over 20% in 1995, 1996. diff --git a/ulcase96.dat b/ulcase96.dat new file mode 100644 index 0000000..5eebe02 --- /dev/null +++ b/ulcase96.dat @@ -0,0 +1,8 @@ + Resume for Tom Martin + +Career Objective: Salesman for a computing service company + +Education: 1988 - BA Mathematics, University of the North + +Experience: 1988-1992 Sales Support, New World Services + 1993-present Salesman New World Services diff --git a/viewdemo.sql b/viewdemo.sql new file mode 100644 index 0000000..e6aad9b --- /dev/null +++ b/viewdemo.sql @@ -0,0 +1,177 @@ +rem +rem $Header: viewdemo.sql 12-aug-2004.06:18:09 rsriragh Exp $ +rem +rem Copyright (c) 1996, 2004, Oracle. All rights reserved. +rem +rem Owner : mchien +rem +rem NAME +rem viewdemo.sql - Oracle 8 demo of object views +rem +rem DESCRIPTON +rem This demo features Oracle8's object extensions to views, object views. +rem +rem MODIFIED (MM/DD/YY) +rem rsriragh 08/12/04 - fix order by diffs +rem hyeh 01/11/00 - enhance order by clause +rem hyeh 08/10/99 - use sqlplus syntax +rem mjaeger 07/14/99 - bug 808870: OCCS: convert tabs, no long lines +rem yaggarwa 08/06/98 - Add New syntax +rem cchau 08/18/97 - enable dictionary protection +rem mchien 05/29/97 - fix type syntax +rem mchien 07/02/96 - born +rem +rem + +REMARK >>>> Set System Variables For Current SQLPlus Session <<<< +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET PAGESIZE 24 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET DEFINE '^' + +set echo on +set numwidth 6 +connect sys/knl_test7 as sysdba +grant connect,resource,dba to vrr1 identified by vrr1; + +connect vrr1/vrr1 + +REM create base tables + +CREATE TABLE department ( +deptno NUMBER(3), +dname VARCHAR2(20), +loc VARCHAR2(20), +CONSTRAINT pr1 primary key(deptno) +) partition BY RANGE (deptno) + (partition p1 VALUES less than (100), + partition p2 VALUES less than (200), + partition p3 VALUES less than (maxvalue) + ); + +CREATE TYPE dept_t AS OBJECT ( +deptno NUMBER(3), +dname VARCHAR2(20), +loc VARCHAR2(20)); +/ + +CREATE TABLE employee ( +empno NUMBER(4) PRIMARY KEY, +ename VARCHAR2(20), +job VARCHAR2(20), +deptno NUMBER(3), + CONSTRAINT fk1 FOREIGN KEY (deptno) REFERENCES department) -- foreign key + partition BY RANGE (empno) + (partition p1 VALUES less than (100), + partition p2 VALUES less than (200), + partition p3 VALUES less than (maxvalue) + ); + +insert into department select deptno, dname, loc from scott.dept; +insert into employee select empno, ename, job, deptno from scott.emp; +commit; + +----------------------------------------------------------------------. +REM Updatable views + +REM typed view + +CREATE VIEW dept_ext_view OF dept_t +WITH OBJECT OID (deptno) AS +SELECT d.deptno, d.dname, d.loc +FROM department d; + +REM view with ref view column + +CREATE VIEW emp_dept_view (empno, ename, job, edept) AS +SELECT empno, ename, job, MAKE_REF(dept_ext_view, deptno) +FROM employee; + +select * from user_updatable_columns + where table_name = 'DEPT_EXT_VIEW' order by 3; +select * from user_updatable_columns + where table_name = 'EMP_DEPT_VIEW' order by 3; + +REM now perform select, insert, update, delete on the views + +select * from dept_ext_view order by deptno; + +-- deref through pkref 'edept' +select empno, ename, job, + e.edept.deptno "DNO", e.edept.dname "DNAME", e.edept.loc "LOC" + from emp_dept_view e + order by empno; + +-- deref with distinct + +select distinct sys_op_dump(deref(edept)), empno from + emp_dept_view order by empno; + +-- deref through pkref 'edept' in where clause +select empno, ename, job, + ed.edept.deptno "DNO", ed.edept.dname "DNAME", ed.edept.loc "LOC" + from emp_dept_view ed, dept_ext_view de + where ed.edept.deptno = de.deptno + order by empno; + +-- deref through pkref 'edept' in order by clause +select empno, ename, job, + e.edept.deptno "DNO", e.edept.dname "DNAME", e.edept.loc "LOC" + from emp_dept_view e + order by e.edept.deptno, empno; + +-- deref through pkref 'edept' in group by clause +select e.edept.deptno, max(empno) + from emp_dept_view e + group by e.edept.deptno order by 1; + +----------------------------------------------------------------------. +-- now perform dml on updatable columns +insert into dept_ext_view values (100, 'LRT', 'Redwood City'); +insert into dept_ext_view values (200, 'ST', 'Redwood Shores'); +-- update oid - ok because no foreign key reference +update dept_ext_view set deptno = 0 where dname = 'LRT'; + +-- test for oid access optimization +select empno, ename, job, + ed.edept.deptno "DNO", ed.edept.dname "DNAME", ed.edept.loc "LOC" + from emp_dept_view ed, dept_ext_view de + where ref(de) = (ed.edept) + order by empno; + +select empno, ename, job, + ed.edept.deptno "DNO", ed.edept.dname "DNAME", ed.edept.loc "LOC" + from emp_dept_view ed, dept_ext_view de + where ref(de) = (ed.edept) and ref(de) is not null + order by empno; + +select empno, ename, job, + ed.edept.deptno "DNO", ed.edept.dname "DNAME", ed.edept.loc "LOC" + from emp_dept_view ed, dept_ext_view de + where ref(de) = (ed.edept) or ref(de) is null + order by empno; + +-- update oid - fail because foreign key reference +update dept_ext_view set deptno = 99 where dname = 'SALES'; +commit; + +select sys_op_dump(value(p)) from dept_ext_view p + order by 1; +select sys_op_dump(deref(ref(p))) from dept_ext_view p + order by 1; + +insert into emp_dept_view (empno, ename, job) + values (1234, 'John Doe', 'manager'); +commit; + +select empno, ename, job, reftohex(edept) + from emp_dept_view + where empno = 1234 + order by empno; + +connect sys/knl_test7 as sysdba +drop user vrr1 cascade; +set echo off diff --git a/xademo1.sql b/xademo1.sql new file mode 100644 index 0000000..256c852 --- /dev/null +++ b/xademo1.sql @@ -0,0 +1,121 @@ +Rem +Rem $Header: xademo1.sql 30-nov-2005.00:34:26 yohu Exp $ +Rem +Rem xademo1.sql +Rem +Rem Copyright (c) 2005, Oracle. All rights reserved. +Rem +Rem NAME +Rem xademo1.sql - XA PL/SQL APIs demo 1 +Rem +Rem DESCRIPTION +Rem This demo program illustrates how XA PL/SQL APIs may be used +Rem in programming PL/SQL procedures/functions. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem yohu 11/21/05 - yohu_xa_plsql +Rem yohu 10/26/05 - Created +Rem + +connect scott/tiger +set serveroutput on +CREATE or REPLACE PROCEDURE xa_demo(gtrid IN NUMBER, op IN VARCHAR2, + emp_no IN NUMBER, e_name IN VARCHAR2) is + xid DBMS_XA_XID; + rc PLS_INTEGER; + oer PLS_INTEGER; + XAE exception; +BEGIN + xid := DBMS_XA_XID(gtrid); + + rc := dbms_xa.XA_START(xid, dbms_xa.TMNOFLAGS); + IF rc!=dbms_xa.XA_OK THEN + oer := dbms_xa.XA_GETLASTOER(); + dbms_output.put_line('ORA-' || oer || ' occured, xa_start failed!'); + raise XAE; + ELSE dbms_output.put_line('XA_START okay'); + END IF; + + CASE + WHEN op = 'add' THEN + INSERT INTO emp(empno, ename, sal) VALUES(emp_no, e_name, 1111); + WHEN op = 'del' THEN + DELETE FROM emp where empno = emp_no AND ename = e_name; + WHEN op = 'inc' THEN + UPDATE emp SET sal=sal+1 WHERE empno = emp_no AND ename = e_name; + ELSE + BEGIN + dbms_output.put_line('Unknown op code!'); + RAISE XAE; + END; + END CASE; + + rc := dbms_xa.XA_END(xid, dbms_xa.TMSUCCESS); + IF rc!=dbms_xa.XA_OK THEN + oer := dbms_xa.XA_GETLASTOER(); + dbms_output.put_line('ORA-' || oer || ' occured, xa_end failed!'); + raise XAE; + ELSE dbms_output.put_line('XA_END okay'); + END IF; + + rc := dbms_xa.XA_PREPARE(xid); + IF rc=dbms_xa.XA_OK THEN + dbms_output.put_line('XA_PREPARE okay'); + + rc := dbms_xa.XA_COMMIT(xid, FALSE); + IF rc!=dbms_xa.XA_OK THEN + oer := dbms_xa.XA_GETLASTOER(); + dbms_output.put_line('ORA-' || oer || ' occured, xa_commit failed!'); + raise XAE; + ELSE dbms_output.put_line('XA_COMMIT okay'); + END IF; + + ELSIF rc=dbms_xa.XA_RDONLY THEN + dbms_output.put_line('XA_PREPARE readonly'); + ELSE + oer := dbms_xa.XA_GETLASTOER(); + dbms_output.put_line('ORA-' || oer || ' occured, xa_prepare failed!'); + raise XAE; + END IF; +EXCEPTION + WHEN OTHERS THEN + dbms_output.put_line('XA error('||rc|| + ') occured, rolling back the transaction...'); + rc := dbms_xa.XA_END(xid, dbms_xa.TMSUCCESS); + rc := dbms_xa.XA_ROLLBACK(xid); + IF rc != dbms_xa.XA_OK THEN + oer := dbms_xa.XA_GETLASTOER(); + dbms_output.put_line('XA-'||rc||', ORA-' || oer || + ' xa_rollback does not return XA_OK!'); + raise_application_error(-20001, 'ORA-'||oer|| + ' error in rolling back a failed transaction!'); + END IF; + raise_application_error(-20002, 'ORA-'||oer|| + ' error in transaction processing, transction rolled back!'); +END; +/ +show errors + +REM sample usage: + +BEGIN xa_demo(111, 'add', 1234, 'xa_demo1'); END; +/ +Rem the following rollback should be a noop +ROLLBACK; +select empno,ename,sal from emp where empno=1234 and ename='xa_demo1'; + +BEGIN xa_demo(222, 'inc', 1234, 'xa_demo1'); END; + / +Rem the following rollback should be a noop +ROLLBACK; +select empno,ename,sal from emp where empno=1234 and ename='xa_demo1'; + +BEGIN xa_demo(333, 'del', 1234, 'xa_demo1'); END; +/ +select empno,ename,sal from emp where empno=1234 and ename='xa_demo1'; + +disconnect +quit diff --git a/xademo2.sql b/xademo2.sql new file mode 100644 index 0000000..2ae5ce0 --- /dev/null +++ b/xademo2.sql @@ -0,0 +1,154 @@ +Rem +Rem $Header: xademo2.sql 30-nov-2005.01:13:59 yohu Exp $ +Rem +Rem xademo2.sql +Rem +Rem Copyright (c) 2005, Oracle. All rights reserved. +Rem +Rem NAME +Rem xademo2.sql - XA PL/SQL API usage demo 2 +Rem +Rem DESCRIPTION +Rem This demo program illustrates how XA PL/SQL APIs may be used +Rem to have a single transaction working across sessions. +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem yohu 11/21/05 - yohu_xa_plsql +Rem yohu 10/26/05 - Created +Rem + +Rem Session 1: starts a transaction and do some work + +connect scott/tiger +SET SERVEROUTPUT ON +DECLARE + rc PLS_INTEGER; + oer PLS_INTEGER; + XAE exception; +BEGIN + rc := dbms_xa.XA_START(DBMS_XA_XID(123), dbms_xa.TMNOFLAGS); + IF rc!=dbms_xa.XA_OK THEN + oer := dbms_xa.XA_GETLASTOER(); + dbms_output.put_line('ORA-' || oer || ' occured, xa_start failed!'); + raise XAE; + ELSE dbms_output.put_line('XA_START(new xid=123) okay'); + END IF; + + UPDATE emp SET sal=sal*1.1 WHERE empno = 7788; + + rc := dbms_xa.XA_END(DBMS_XA_XID(123), dbms_xa.TMSUSPEND); + IF rc!=dbms_xa.XA_OK THEN + oer := dbms_xa.XA_GETLASTOER(); + dbms_output.put_line('ORA-' || oer || ' occured, xa_end failed!'); + raise XAE; + ELSE dbms_output.put_line('XA_END(suspend xid=123) okay'); + END IF; +EXCEPTION + WHEN OTHERS THEN + dbms_output.put_line('XA error('||rc|| + ') occured, rolling back the transaction...'); + rc := dbms_xa.XA_END(DBMS_XA_XID(123), dbms_xa.TMSUCCESS); + rc := dbms_xa.XA_ROLLBACK(DBMS_XA_XID(123)); + IF rc != dbms_xa.XA_OK THEN + oer := dbms_xa.XA_GETLASTOER(); + dbms_output.put_line('XA-'||rc||', ORA-' || oer || + ' xa_rollback does not return XA_OK!'); + raise_application_error(-20001, 'ORA-'||oer|| + ' error in rolling back a failed transaction!'); + END IF; + raise_application_error(-20002, 'ORA-'||oer|| + ' error in transaction processing, transction rolled back!'); +END; +/ +show errors +disconnect + + +Rem Session 2: resumes the transaction and do some work + +connect scott/tiger +SET SERVEROUTPUT ON +DECLARE + rc PLS_INTEGER; + oer PLS_INTEGER; + s NUMBER; + XAE exception; +BEGIN + rc := dbms_xa.XA_START(DBMS_XA_XID(123), dbms_xa.TMRESUME); + IF rc!=dbms_xa.XA_OK THEN + oer := dbms_xa.XA_GETLASTOER(); + dbms_output.put_line('ORA-' || oer || ' occured, xa_start failed!'); + raise XAE; + ELSE dbms_output.put_line('XA_START(resume xid=123) okay'); + END IF; + + SELECT sal INTO s FROM emp WHERE empno = 7788; + dbms_output.put_line('empno = 7788, sal = ' || s); + + rc := dbms_xa.XA_END(DBMS_XA_XID(123), dbms_xa.TMSUCCESS); + IF rc!=dbms_xa.XA_OK THEN + oer := dbms_xa.XA_GETLASTOER(); + dbms_output.put_line('ORA-' || oer || ' occured, xa_end failed!'); + raise XAE; + ELSE dbms_output.put_line('XA_END(detach xid=123) okay'); + END IF; +EXCEPTION + WHEN OTHERS THEN + dbms_output.put_line('XA error('||rc|| + ') occured, rolling back the transaction...'); + rc := dbms_xa.XA_END(DBMS_XA_XID(123), dbms_xa.TMSUCCESS); + rc := dbms_xa.XA_ROLLBACK(DBMS_XA_XID(123)); + IF rc != dbms_xa.XA_OK THEN + oer := dbms_xa.XA_GETLASTOER(); + dbms_output.put_line('XA-'||rc||', ORA-' || oer || + ' xa_rollback does not return XA_OK!'); + raise_application_error(-20001, 'ORA-'||oer|| + ' error in rolling back a failed transaction!'); + END IF; + raise_application_error(-20002, 'ORA-'||oer|| + ' error in transaction processing, transction rolled back!'); +END; +/ +show errors +disconnect + + +Rem Session 3: commit the transaction + +connect scott/tiger +SET SERVEROUTPUT ON +DECLARE + rc PLS_INTEGER; + oer PLS_INTEGER; + XAE exception; +BEGIN + rc := dbms_xa.XA_COMMIT(DBMS_XA_XID(123), TRUE); + IF rc!=dbms_xa.XA_OK THEN + oer := dbms_xa.XA_GETLASTOER(); + dbms_output.put_line('ORA-' || oer || ' occured, xa_commit failed!'); + raise XAE; + ELSE dbms_output.put_line('XA_COMMIT(commit xid=123) okay'); + END IF; + +EXCEPTION + WHEN XAE THEN + dbms_output.put_line('XA error('||rc|| + ') occured, rolling back the transaction...'); + rc := dbms_xa.XA_ROLLBACK(DBMS_XA_XID(123)); + IF rc != dbms_xa.XA_OK THEN + oer := dbms_xa.XA_GETLASTOER(); + dbms_output.put_line('XA-'||rc||', ORA-' || oer || + ' xa_rollback does not return XA_OK!'); + raise_application_error(-20001, 'ORA-'||oer|| + ' error in rolling back a failed transaction!'); + END IF; + raise_application_error(-20002, 'ORA-'||oer|| + ' error in transaction processing, transction rolled back!'); +END; +/ +show errors +disconnect +quit diff --git a/xmlgen1.sql b/xmlgen1.sql new file mode 100644 index 0000000..fc9f0bb --- /dev/null +++ b/xmlgen1.sql @@ -0,0 +1,302 @@ +Rem +Rem $Header: xmlgen1.sql 29-apr-2001.13:23:02 rbooredd Exp $ +Rem +Rem xmlgen1.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem xmlgen1.sql - XML generation using DBMS_XMLGEN package +Rem +Rem DESCRIPTION +Rem This demo shows how to generate Purchase Order XML document +Rem from existing relational database using DBMS_XMLGEN package +Rem +Rem Object views are defined over relational tables to get data in +Rem canonical form. +Rem +Rem NOTES +Rem DBMS_XMLGEN Package maps UDT attributes names +Rem starting with '@' to xml attributes +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbooredd 04/29/01 - Merged rbooredd_xml_demo1 +Rem rbooredd 04/29/01 - +Rem rbooredd 04/27/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +connect system/manager +grant connect,resource to xmlgen1 identified by xmlgen1; +connect xmlgen1/xmlgen1; + +-- Purchase Order Object View Model + +-- PhoneList Varray object type +CREATE TYPE PhoneList_vartyp AS VARRAY(10) OF VARCHAR2(20) +/ + +-- Address object type +CREATE TYPE Address_typ AS OBJECT ( + Street VARCHAR2(200), + City VARCHAR2(200), + State CHAR(2), + Zip VARCHAR2(20) + ) +/ + +-- Customer object type +CREATE TYPE Customer_typ AS OBJECT ( + CustNo NUMBER, + CustName VARCHAR2(200), + Address Address_typ, + PhoneList PhoneList_vartyp +) +/ + + +-- StockItem object type +CREATE TYPE StockItem_typ AS OBJECT ( + "@StockNo" NUMBER, + Price NUMBER, + TaxRate NUMBER +) +/ + +-- LineItems object type +CREATE TYPE LineItem_typ AS OBJECT ( + "@LineItemNo" NUMBER, + Item StockItem_typ, + Quantity NUMBER, + Discount NUMBER + ) +/ +-- LineItems Nested table +CREATE TYPE LineItems_ntabtyp AS TABLE OF LineItem_typ +/ + +-- Purchase Order object type +CREATE TYPE PO_typ AUTHID CURRENT_USER AS OBJECT ( + "@PONO" NUMBER, + Cust_ref REF Customer_typ, + OrderDate DATE, + ShipDate TIMESTAMP, + LineItems_ntab LineItems_ntabtyp, + ShipToAddr Address_typ + ) +/ + +-- Create Purchase Order Relational Model tables + +--Customer table +CREATE TABLE Customer_tab( + CustNo NUMBER NOT NULL, + CustName VARCHAR2(200) , + Street VARCHAR2(200) , + City VARCHAR2(200) , + State CHAR(2) , + Zip VARCHAR2(20) , + Phone1 VARCHAR2(20), + Phone2 VARCHAR2(20), + Phone3 VARCHAR2(20), + constraint cust_pk PRIMARY KEY (CustNo) +) +ORGANIZATION INDEX OVERFLOW; + +-- Purchase Order table +CREATE TABLE po_tab ( + PONo NUMBER, /* purchase order no */ + Custno NUMBER constraint po_cust_fk references Customer_tab, + /* Foreign KEY referencing customer */ + OrderDate DATE, /* date of order */ + ShipDate TIMESTAMP, /* date to be shipped */ + ToStreet VARCHAR2(200), /* shipto address */ + ToCity VARCHAR2(200), + ToState CHAR(2), + ToZip VARCHAR2(20), + constraint po_pk PRIMARY KEY(PONo) +); + +--Stock Table +CREATE TABLE Stock_tab ( + StockNo NUMBER constraint stock_uk UNIQUE, + Price NUMBER, + TaxRate NUMBER +); + +--Line Items Table +CREATE TABLE LineItems_tab( + LineItemNo NUMBER, + PONo NUMBER constraint LI_PO_FK REFERENCES po_tab, + StockNo NUMBER , + Quantity NUMBER, + Discount NUMBER, + constraint LI_PK PRIMARY KEY (PONo, LineItemNo) +); + +-- create Object Views + +--Customer Object View +CREATE OR REPLACE VIEW Customer OF Customer_typ + WITH OBJECT IDENTIFIER(CustNo) + AS SELECT c.Custno, C.custname, + Address_typ(C.Street, C.City, C.State, C.Zip), + PhoneList_vartyp(Phone1, Phone2, Phone3) + FROM Customer_tab c; + +--Purchase order view +CREATE OR REPLACE VIEW PO OF PO_typ + WITH OBJECT IDENTIFIER ("@PONO") + AS SELECT P.PONo, + MAKE_REF(Customer, P.Custno), + P.OrderDate, + P.ShipDate, + CAST( MULTISET( + SELECT LineItem_typ( L.LineItemNo, + StockItem_typ(L.StockNo,S.Price,S.TaxRate), + L.Quantity, L.Discount) + FROM LineItems_tab L, Stock_tab S + WHERE L.PONo = P.PONo and S.StockNo=L.StockNo ) + AS LineItems_ntabtyp), + Address_typ(P.ToStreet,P.ToCity, P.ToState, P.ToZip) + FROM PO_tab P; + + + +-------------------- +-- Populate data +------------------- +-- Establish Inventory + +INSERT INTO Stock_tab VALUES(1004, 6750.00, 2) ; +INSERT INTO Stock_tab VALUES(1011, 4500.23, 2) ; +INSERT INTO Stock_tab VALUES(1534, 2234.00, 2) ; +INSERT INTO Stock_tab VALUES(1535, 3456.23, 2) ; + +-- Register Customers + +INSERT INTO Customer_tab + VALUES (1, 'Jean Nance', '2 Avocet Drive', + 'Redwood Shores', 'CA', '95054', + '415-555-1212', NULL, NULL) ; + +INSERT INTO Customer_tab + VALUES (2, 'John Nike', '323 College Drive', + 'Edison', 'NJ', '08820', + '609-555-1212', '201-555-1212', NULL) ; + +-- Place Orders + +INSERT INTO PO_tab + VALUES (1001, 1, SYSDATE, '10-MAY-1997', + NULL, NULL, NULL, NULL) ; + +INSERT INTO PO_tab + VALUES (2001, 2, SYSDATE, '20-MAY-1997', + '55 Madison Ave', 'Madison', 'WI', '53715') ; + +-- Detail Line Items + +INSERT INTO LineItems_tab VALUES(01, 1001, 1534, 12, 0) ; +INSERT INTO LineItems_tab VALUES(02, 1001, 1535, 10, 10) ; +INSERT INTO LineItems_tab VALUES(01, 2001, 1004, 1, 0) ; +INSERT INTO LineItems_tab VALUES(02, 2001, 1011, 2, 1) ; + +-------------------------------------------------- +-- create getXML wrapper function over DBMS_XMLGEN +-------------------------------------------------- +create or replace function getXML( sql_query varchar2, + rset_tag varchar2:='ROWSET', + rtag varchar2:='ROW') +return clob is + ctx number; + xmldoc sys.XMLType; +begin + ctx := DBMS_XMLGEN.newContext(sql_query); + + if (nvl(rset_tag,'X') != 'ROWSET') then + DBMS_XMLGEN.setRowSetTag(ctx,rset_tag); + end if; + + if (nvl(rtag,'Y') != 'ROW') then + DBMS_XMLGEN.setRowTag(ctx,rtag); + end if; + + xmldoc := DBMS_XMLGEN.getXMLType(ctx); + DBMS_XMLGEN.closeContext(ctx); + return xmldoc.getClobVal(); +exception + when others then + DBMS_XMLGEN.closeContext(ctx); + raise; +end; +/ +show error + +-- generate xml from any query using dbms_xmlgen package +set long 100000 + +select getXML('select "@PONO",lineitems_ntab lineitems,shiptoaddr + from po p') poxml +from dual; + + +------------------------------------------------------------ +-- Use DBMS_XMLGEN Package to generate each PO in XML format +-- and store XMLType in po_xml table +------------------------------------------------------------ + +-- create table with xmltype column to store po in XML format +create table po_xml( + XPO SYS.XMLType /* purchase order in XML format */ +) +/ + + +declare + qryCtx dbms_xmlgen.ctxHandle; + pxml SYS.XMLType; +begin + + -- get the query context; + qryCtx := dbms_xmlgen.newContext(' + select "@PONO",deref(cust_ref) customer,p.OrderDate,p.shipdate, + lineitems_ntab lineitems,shiptoaddr + from po p' + ); + + -- set the maximum number of rows to be 1, + dbms_xmlgen.setMaxRows(qryCtx, 1); + -- set rowset tag to null and row tag to PurchaseOrder + dbms_xmlgen.setRowSetTag(qryCtx,null); + dbms_xmlgen.setRowTag(qryCtx,'PurchaseOrder'); + + loop + -- now get the po in xml format + pxml := dbms_xmlgen.getXMLType(qryCtx); + + -- if there were no rows processed, then quit..! + exit when dbms_xmlgen.getNumRowsProcessed(qryCtx) = 0; + + -- Store XMLType po in po_xml table + insert into po_xml values(pxml); + end loop; + +end; +/ + +-- query po_xml table for generated POs in XML format +set long 100000 +select x.xpo.getClobVal() xpo +from po_xml x; + +-- cleanup +connect system/manager +drop user xmlgen1 cascade; diff --git a/xmlgen2.sql b/xmlgen2.sql new file mode 100644 index 0000000..1c97087 --- /dev/null +++ b/xmlgen2.sql @@ -0,0 +1,236 @@ +Rem +Rem $Header: xmlgen2.sql 29-apr-2001.13:23:03 rbooredd Exp $ +Rem +Rem xmlgen2.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem xmlgen2.sql - XML generation using SYS_XMLGEN() and SYS_XMLAGG() +Rem +Rem DESCRIPTION +Rem This demo shows how to generate Purchase Order XML document +Rem from existing relational database using SYS_XMLGEN() and SYS_XMLAGG() +Rem SQL functions +Rem +Rem Object views are defined over relational tables to get data in +Rem canonical form. +Rem +Rem NOTES +Rem SYS_XMLGEN() maps UDT attributes names +Rem starting with '@' to xml attributes +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbooredd 04/29/01 - Merged rbooredd_xml_demo1 +Rem rbooredd 04/29/01 - +Rem rbooredd 04/27/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +connect system/manager +grant connect,resource to xmlgen2 identified by xmlgen2; +connect xmlgen2/xmlgen2; + +-- Purchase Order Object View Model + +-- PhoneList Varray object type +CREATE TYPE PhoneList_vartyp AS VARRAY(10) OF VARCHAR2(20) +/ + +-- Address object type +CREATE TYPE Address_typ AS OBJECT ( + Street VARCHAR2(200), + City VARCHAR2(200), + State CHAR(2), + Zip VARCHAR2(20) + ) +/ + +-- Customer object type +CREATE TYPE Customer_typ AS OBJECT ( + CustNo NUMBER, + CustName VARCHAR2(200), + Address Address_typ, + PhoneList PhoneList_vartyp +) +/ + + +-- StockItem object type +CREATE TYPE StockItem_typ AS OBJECT ( + "@StockNo" NUMBER, + Price NUMBER, + TaxRate NUMBER +) +/ + +-- LineItems object type +CREATE TYPE LineItem_typ AS OBJECT ( + "@LineItemNo" NUMBER, + Item StockItem_typ, + Quantity NUMBER, + Discount NUMBER + ) +/ +-- LineItems Nested table +CREATE TYPE LineItems_ntabtyp AS TABLE OF LineItem_typ +/ + +-- Purchase Order object type +CREATE TYPE PO_typ AUTHID CURRENT_USER AS OBJECT ( + "@PONO" NUMBER, + Customer Customer_typ, + OrderDate DATE, + ShipDate TIMESTAMP, + LineItems_ntab LineItems_ntabtyp, + ShipToAddr Address_typ + ) +/ + +-- Create Purchase Order Relational Model tables + +--Customer table +CREATE TABLE Customer_tab( + CustNo NUMBER NOT NULL, + CustName VARCHAR2(200) , + Street VARCHAR2(200) , + City VARCHAR2(200) , + State CHAR(2) , + Zip VARCHAR2(20) , + Phone1 VARCHAR2(20), + Phone2 VARCHAR2(20), + Phone3 VARCHAR2(20), + constraint cust_pk PRIMARY KEY (CustNo) +) +ORGANIZATION INDEX OVERFLOW; + +-- Purchase Order table +CREATE TABLE po_tab ( + PONo NUMBER, /* purchase order no */ + Custno NUMBER constraint po_cust_fk references Customer_tab, + /* Foreign KEY referencing customer */ + OrderDate DATE, /* date of order */ + ShipDate TIMESTAMP, /* date to be shipped */ + ToStreet VARCHAR2(200), /* shipto address */ + ToCity VARCHAR2(200), + ToState CHAR(2), + ToZip VARCHAR2(20), + constraint po_pk PRIMARY KEY(PONo) +); + +--Stock Table +CREATE TABLE Stock_tab ( + StockNo NUMBER constraint stock_uk UNIQUE, + Price NUMBER, + TaxRate NUMBER +); + +--Line Items Table +CREATE TABLE LineItems_tab( + LineItemNo NUMBER, + PONo NUMBER constraint LI_PO_FK REFERENCES po_tab, + StockNo NUMBER , + Quantity NUMBER, + Discount NUMBER, + constraint LI_PK PRIMARY KEY (PONo, LineItemNo) +); + +-- create Object Views +--Customer Object View +CREATE OR REPLACE VIEW Customer OF Customer_typ + WITH OBJECT IDENTIFIER(CustNo) + AS SELECT c.Custno, C.custname, + Address_typ(C.Street, C.City, C.State, C.Zip), + PhoneList_vartyp(Phone1, Phone2, Phone3) + FROM Customer_tab c; + +--Purchase order view +CREATE OR REPLACE VIEW PO OF PO_typ + WITH OBJECT IDENTIFIER ("@PONO") + AS SELECT P.PONo, + Customer_typ(P.Custno,C.CustName,C.Address,C.PhoneList), + P.OrderDate, + P.ShipDate, + CAST( MULTISET( + SELECT LineItem_typ( L.LineItemNo, + StockItem_typ(L.StockNo,S.Price,S.TaxRate), + L.Quantity, L.Discount) + FROM LineItems_tab L, Stock_tab S + WHERE L.PONo = P.PONo and S.StockNo=L.StockNo ) + AS LineItems_ntabtyp), + Address_typ(P.ToStreet,P.ToCity, P.ToState, P.ToZip) + FROM PO_tab P, Customer C + WHERE P.CustNo=C.custNo; + + + +-------------------- +-- Populate data +------------------- +-- Establish Inventory + +INSERT INTO Stock_tab VALUES(1004, 6750.00, 2) ; +INSERT INTO Stock_tab VALUES(1011, 4500.23, 2) ; +INSERT INTO Stock_tab VALUES(1534, 2234.00, 2) ; +INSERT INTO Stock_tab VALUES(1535, 3456.23, 2) ; + +-- Register Customers + +INSERT INTO Customer_tab + VALUES (1, 'Jean Nance', '2 Avocet Drive', + 'Redwood Shores', 'CA', '95054', + '415-555-1212', NULL, NULL) ; + +INSERT INTO Customer_tab + VALUES (2, 'John Nike', '323 College Drive', + 'Edison', 'NJ', '08820', + '609-555-1212', '201-555-1212', NULL) ; + +-- Place Orders + +INSERT INTO PO_tab + VALUES (1001, 1, SYSDATE, '10-MAY-1997', + NULL, NULL, NULL, NULL) ; + +INSERT INTO PO_tab + VALUES (2001, 2, SYSDATE, '20-MAY-1997', + '55 Madison Ave', 'Madison', 'WI', '53715') ; + +-- Detail Line Items + +INSERT INTO LineItems_tab VALUES(01, 1001, 1534, 12, 0) ; +INSERT INTO LineItems_tab VALUES(02, 1001, 1535, 10, 10) ; +INSERT INTO LineItems_tab VALUES(01, 2001, 1004, 1, 0) ; +INSERT INTO LineItems_tab VALUES(02, 2001, 1011, 2, 1) ; + +------------------------------------------------------- +-- Use SYS_XMLGEN() to generate PO in XML format +------------------------------------------------------- +set long 20000 +set pages 100 +SELECT SYS_XMLGEN(value(p), + sys.xmlgenformatType.createFormat('PurchaseOrder')).getClobVal() PO +FROM po p +WHERE p."@PONO"=1001; + +------------------------------------------------------- +-- Use SYS_XMLAGG() to aggrigate all Purchase Orders +-- into one XML Document +------------------------------------------------------- +set long 20000 +set pages 200 +SELECT SYS_XMLAGG(SYS_XMLGEN(value(p), + sys.xmlgenformatType.createFormat('PurchaseOrder'))).getClobVal() PO +FROM po p; + + +-- cleanup +connect system/manager +drop user xmlgen2 cascade; diff --git a/xmltype1.sql b/xmltype1.sql new file mode 100644 index 0000000..287c401 --- /dev/null +++ b/xmltype1.sql @@ -0,0 +1,175 @@ +Rem +Rem $Header: xmltype1.sql 04-may-2001.14:29:48 rbooredd Exp $ +Rem +Rem xmltype1.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem xmltype1.sql - XMLType demo 1 +Rem +Rem DESCRIPTION +Rem This demo shows how to use XMLType to store and access +Rem xml documents inside database +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbooredd 04/29/01 - Merged rbooredd_xml_demo1 +Rem rbooredd 04/29/01 - +Rem rbooredd 04/27/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +connect system/manager +grant connect,resource,query rewrite to xmltype1 identified by xmltype1; +connect xmltype1/xmltype1; + +-- create xml table to store Purchase Order documents +CREATE TABLE po_tab( + po sys.XMLType +) XMLType COLUMN po + STORE AS CLOB ( + TABLESPACE system + STORAGE(INITIAL 4K NEXT 8K) + CHUNK 4096 NOCACHE LOGGING + ); + +------------------------------------ +-- DML on XMLType column +------------------------------------ + +-- insert PurchaseOrder into po_tab table +-- with createXML constructor +insert into po_tab +values(sys.XMLType.createXML( +' + + Po_1 + John + + 1033, Main Street + Sunnyvalue + CA + +') +); + +insert into po_tab +values(sys.XMLType.createXML( +' + + Po_2 + Nance + + 1033, Main Street + Sunnyvalue + CA + +') +); + + +-- Updating Purchase Order 2 with new shipping address +update po_tab e +set e.po=sys.XMLType.createXML( +' + + Po_2 + Nance + + 2 Avocet Drive + Redwood Shores + CA + +') +where e.po.extract('/PO/@pono').getNumberVal()=2; + + +-- deleting Purchase Order 2 +delete from po_tab e +where e.po.extract('/PO/PNAME/text()').getStringVal()='Po_2'; + +commit; + +------------------------------------ +-- Queries on XMLType column +------------------------------------ + +-- selecting XMLType document as CLOB +set long 2000 +select e.po.getClobval() +from po_tab e; + +-- extract Purchase Order NAME where pono attribue exists and equal to 1 +-- and customer name is like '%John%' + +select e.po.extract('/PO/PNAME/text()').getStringVal() PNAME +from po_tab e +where e.po.existsNode('/PO/@pono') = 1 and + e.po.extract('/PO/@pono').getNumberVal() = 1 and + e.po.extract('/PO/CUSTNAME/text()').getStringVal() like '%John%'; + +-- check if /PO/SHIPADDR/STATE node is a xml fragment +select e.po.extract('/PO/SHIPADDR/STATE').isFragment() +from po_tab e; + +-- use Extract(), ExitsNode() XML Operators to query XML document +select extract(e.po,'/PO/PNAME/text()').getStringVal() PNAME +from po_tab e +where existsNode(e.po,'/PO/SHIPADDR') = 1 and + extract(e.po,'/PO/@pono').getNumberVal() = 1 and + extract(e.po,'/PO/CUSTNAME/text()').getStringVal() like '%John%'; + +--------------------------------------- +-- Functional Indexes on XMLType column +--------------------------------------- + +-- create a unique functional index on pono to enforce +-- unique constraint on pono attribute +create unique index pono_fidx on po_tab(sys.xmltype.getNumberVal( + sys.xmltype.extract(po,'/PO/@pono'))); + +-- insert fails due to unique constraint violation! +insert into po_tab +values(sys.XMLType.createXML( +' + + Po_1 + John + + 1033, Main Street + Sunnyvalue + CA + +') +); + + +-- create a functional index on customer name +create index cname_fidx on po_tab(substr(sys.xmltype.getStringVal( + sys.xmltype.extract(po,'/PO/CUSTNAME/text()')),1,200)); + +-- create a functional index for existsNode() of SHIPADDR +create index sadd_fidx on po_tab(po.existsNode('/PO/SHIPADDR')); + + +-- use functional indexes to improve query performance +alter session set query_rewrite_enabled=true; +alter session set query_rewrite_integrity=trusted; + +select /*+ index(e pono_fidx) */ e.po.getClobVal() +from po_tab e +where e.po.extract('/PO/@pono').getNumberVal() = 1; + +-- cleanup +connect system/manager +drop user xmltype1 cascade; diff --git a/xmltype2.sql b/xmltype2.sql new file mode 100644 index 0000000..c88b9ac --- /dev/null +++ b/xmltype2.sql @@ -0,0 +1,118 @@ +Rem +Rem $Header: xmltype2.sql 04-may-2001.12:22:18 rbooredd Exp $ +Rem +Rem xmltype2.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem xmltype2.sql - XMLType demo 2 +Rem +Rem DESCRIPTION +Rem This demo shows how to use XMLType inside PL/SQL +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rbooredd 04/29/01 - Merged rbooredd_xml_demo1 +Rem rbooredd 04/27/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +connect system/manager +grant connect,resource to xmltype2 identified by xmltype2; +connect xmltype2/xmltype2; + + +-------------------------------------------------------------------------------- +-- Exploding the Purchase Order xml documnet to Store in a Relational Table +-- using XMLType methods and Table Function (pipelined) +-------------------------------------------------------------------------------- +create type poRow_type as object +( + poname varchar2(20), + postreet varchar2(20), + pocity varchar2(20), + postate char(2), + pozip char(10) +); +/ + +create type poRow_list as TABLE of poRow_type; +/ + +create or replace function poExplode_func (poList IN sys.XMLType) return +poRow_list +pipelined is + out_rec poRow_type := poRow_type(null,null,null,null,null); + poxml sys.XMLType; + i binary_integer := 1; +begin + + loop + + -- extract the i'th purchase order! + poxml := poList.extract('//PO['||i||']'); + + exit when poxml is null; + + -- extract the required attributes..!!! + out_rec.poname := + poxml.extract('/PO/PONAME/text()').getStringVal(); + out_rec.postreet := + poxml.extract('/PO/POADDR/STREET/text()').getStringVal(); + out_rec.pocity := + poxml.extract('/PO/POADDR/CITY/text()').getStringVal(); + out_rec.postate := + poxml.extract('/PO/POADDR/STATE/text()').getStringVal(); + out_rec.pozip := + poxml.extract('/PO/POADDR/ZIP/text()').getStringVal(); + + -- output the row + PIPE ROW(out_rec); + i := i+1; + end loop; + return; + +end; +/ + +-- generate poRow_type rowset from xml documnet +select * + from TABLE( CAST( + poExplode_func( + sys.XMLType.createXML( + ' + + + Po_1 + + 100 Main Street + Sunnyvale + CA + 94086 + + + + Po_2 + + 200 First Street + Oaksdale + CA + 95043 + + + ') + ) AS poRow_list)); + +-- cleanup +connect system/manager +drop user xmltype2 cascade; diff --git a/xmltype3.java b/xmltype3.java new file mode 100644 index 0000000..28222b5 --- /dev/null +++ b/xmltype3.java @@ -0,0 +1,162 @@ +/* $Header: xmltype3.java 09-dec-2001.18:51:27 bkhaladk Exp $ */ + +/* Copyright (c) 2001, Oracle Corporation. All rights reserved. */ + +/* + DESCRIPTION + This demo shows how to access/modify XMLType inside java/jdbc: + - retrieve PurchaseOrder(pono#2001) xml document from database + - store this PurchaseOrder in po_xml_hist table + - update "DISCOUNT" element using java DOM API + - update modified PurchaseOrder xml documnet in database + - delete PurchaseOrder 1001 + + PRIVATE CLASSES + None + + NOTES + Need to have classes12.zip, xmlparserv2.jar, and xdb_g.jar in CLASSPATH + And execute xmltype3.sql first to setup schema: + sqlplus /nolog @xmltype3.sql + + MODIFIED (MM/DD/YY) + bkhaladk 12/09/01 - . + bkhaladk 12/05/01 - . + bkhaladk 12/03/01 - . + rbooredd 04/29/01 - Merged rbooredd_xml_demo1 + rbooredd 04/27/01 - Creation + */ + +import java.sql.*; +import java.io.*; + +import oracle.xml.parser.v2.*; +import org.xml.sax.*; +import org.w3c.dom.*; + +import oracle.jdbc.driver.*; +import oracle.sql.*; + +import oracle.xdb.XMLType; + +public class xmltype3 +{ + + //static String conStr = "jdbc:oracle:thin:@energize:1521:m3"; + static String conStr = "jdbc:oracle:oci8:@"; + static String user = "xmltype3"; + static String pass = "xmltype3"; + /* static String qryStr = + "select x.xpo from po_xml x "+ + "where x.xpo.extract('/PurchaseOrder/@PONO').getNumberVal()=2001";*/ + static String qryStr = + "select x.xpo from po_xml x "; + + + static String updateXML(String xmlTypeStr) + { + System.out.println("\n==============================="); + System.out.println("xmlType.getStringVal():"); + System.out.println(xmlTypeStr); + System.out.println("==============================="); + String outXML = null; + try{ + DOMParser parser = new DOMParser(); + parser.setValidationMode(parser.PARTIAL_VALIDATION); + parser.setPreserveWhitespace (true); + + + parser.parse(new StringReader(xmlTypeStr)); + System.out.println("xmlType.getStringVal(): xml String is well-formed"); + + XMLDocument doc = parser.getDocument(); + + NodeList nl = doc.getElementsByTagName("DISCOUNT"); + + for(int i=0;i + + 1 + Jean Nance +
+ 2 Avocet Drive + Redwood Shores + CA + 95054 +
+ + 415-555-1212 + +
+ 29-APR-01 + 10-MAY-97 12.00.00.000000 AM + + + + 2234 + 2 + + 12 + 0 + + + + 3456.23 + 2 + + 10 + 10 + + + + ' +)); + +insert into po_xml +values(sys.XMLType.createXML( +' + + 2 + John Nike +
+ 323 College Drive + Edison + NJ + 08820 +
+ + 609-555-1212 + 201-555-1212 + +
+ 29-APR-01 + 20-MAY-97 12.00.00.000000 AM + + + + 6750 + 2 + + 1 + 0 + + + + 4500.23 + 2 + + 2 + 1 + + + + 55 Madison Ave + Madison + WI + 53715 + +
' +)); + + +set long 100000 +select x.xpo.getClobVal() xpo +from po_xml x; + +-- create po_xml_hist table store old PurchaseOrders +create table po_xml_hist( + xpo sys.xmltype +); + diff --git a/xrwutl.sql b/xrwutl.sql new file mode 100644 index 0000000..590b1e2 --- /dev/null +++ b/xrwutl.sql @@ -0,0 +1,383 @@ +Rem +Rem $Header: rdbms/demo/xrwutl.sql /main/2 2008/10/07 11:18:57 jraitto Exp $ +Rem +Rem xrwutl.sql +Rem +Rem Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved. +Rem +Rem NAME +Rem xrwutl.sql - Utility to extract output from EXPLAIN_REWRITE() +Rem +Rem DESCRIPTION +Rem EXPLAIN_REWRITE() contains a large number of output fields. +Rem This utility helps to easily select the output fields from +Rem EXPLAIN_REWRITE(). +Rem +Rem NOTES +Rem This utility is merged as a demo script +Rem +Rem MODIFIED (MM/DD/YY) +Rem jraitto 10/04/08 - Handle internally thrown errors +Rem - Fix bug 4390758 +Rem jraitto 10/03/08 - fix bug 4391670 by re-signraising unexpected +Rem errors +Rem mthiyaga 04/01/05 - mthiyaga_xrw_demo +Rem mthiyaga 28/03/05 - Created +Rem + +SET ECHO ON +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 + + +set echo off; + +-- DEFINITION for xrw (mv_list, command_list, querytxt): +-- This is a procedure to simplify the output from +-- explain_rewrite(). +-- INPUT +-- mv_list : List of mvs separated by commmas. +-- +-- command_list : List of commands separated by commas; you can provide +-- any of the following commands. +-- COMMAND LIST +-- +-- querytxt : Text of the query to be rewritten +-- + +connect /as sysdba; + +SET SERVEROUTPUT ON SIZE 32512; + +set echo off; + +-- The procedure is used to print a big string. Procedure dbms_output.put_line +-- cannot print a string that is longer than 250 chars. + +CREATE OR REPLACE PROCEDURE print_big_buf + ( + buf IN VARCHAR2 + ) +AS + len PLS_INTEGER; + nl PLS_INTEGER; + bsize CONSTANT PLS_INTEGER := 250; + +BEGIN + dbms_output.enable(1000000); + len := LENGTHB(buf); + nl := floor(len/bsize); + + FOR j IN 1..nl LOOP + dbms_output.put_line(SUBSTRB(buf, (j-1)*bsize + 1, bsize)); + END LOOP; + + dbms_output.put_line(SUBSTRB(buf, nl*bsize + 1, len - nl*bsize)); + +END; +/ + +GRANT EXECUTE ON SYS.print_big_buf TO PUBLIC; + + + +------------------------------------------------------------------------------ +-- DESCRIPTION for ckrw_help +-- This procedure can be called by the user to get help on +-- how to use xrw +------------------------------------------------------------------------------ + + CREATE OR REPLACE PROCEDURE xrw_help AUTHID CURRENT_USER + AS + BEGIN + + dbms_output.put_line('HELP for the use of precedure xrw'); + + dbms_output.put_line('sys.xrw (list_of_mvs (separated by commas), '|| + 'list of commands (separated by commas), querytxt)'); + + dbms_output.put_line('**** List of commands:'); + dbms_output.put_line('QUERY_TXT '); + dbms_output.put_line('REWRITTEN_TXT '); + dbms_output.put_line('QUERY_BLOCK_NO '); + dbms_output.put_line('PASS '); + dbms_output.put_line('COSTS '); + dbms_output.new_line; + + END; +/ +show errors + + + + + +------------------------------------------------------------------------------ +-- DEFINITION for check_mvs: +-- This procedure takes an array of mv names and checks whether +-- they are really mvs; if there is any name in the list that doesn't +-- correspond to a MV then we raise an error +-- INPUT +-- num_mvs : number of mvs given +-- mv_array : array of mv names +------------------------------------------------------------------------------ + +CREATE OR REPLACE PROCEDURE check_mvs + ( + num_mvs IN PLS_INTEGER, + mv_array IN dbms_utility.uncl_array + ) AUTHID CURRENT_USER + AS + i PLS_INTEGER; + BEGIN + IF (num_mvs > 0) THEN + DECLARE + mv_found PLS_INTEGER := 0; + mv_name VARCHAR2(30); + is_not_mv EXCEPTION; + cursor find_mv (given_mv_name VARCHAR2) IS SELECT 1 from user_mviews + where upper(mview_name) = given_mv_name; + + BEGIN + FOR i IN 1..num_mvs LOOP + mv_name := rtrim(ltrim(upper(mv_array(i)))); + open find_mv(mv_name); + fetch find_mv INTO mv_found; + -- The mv wasn't found in user_mviews, so the name given + -- doesn't correspond to a MV + IF (mv_found = 0) THEN + RAISE is_not_mv; + END IF; + + close find_mv; + END LOOP; + EXCEPTION WHEN NO_DATA_FOUND OR is_not_mv THEN + dbms_output.put_line('**FAILURE** Materialized View ' || mv_name || + ' was not found'); + RAISE NO_DATA_FOUND; + END; + END IF; + END; +/ +show errors + + + + +------------------------------------------------------------------------------ +-- DEFINITION for xrw: +-- This procedure is the top level api the user will use to +-- simplify output from explain_rewrite(). +------------------------------------------------------------------------------ + +CREATE OR REPLACE PROCEDURE xrw + ( + mv_list IN VARCHAR2, + command_list IN VARCHAR2, + querytxt IN VARCHAR2 + ) AUTHID CURRENT_USER + AS + + Rewrite_Array SYS.RewriteArrayType := SYS.RewriteArrayType(); + no_of_msgs NUMBER; + i NUMBER; + + + buf VARCHAR2(32512); + + + -- Variables used for the list of mvs given + num_mvs PLS_INTEGER := 0; + mv_array dbms_utility.uncl_array; + i PLS_INTEGER := 1; + + -- Variables used for the different commands + num_commands PLS_INTEGER := 0; + commands_array dbms_utility.lname_array; + command VARCHAR2(30); + query_txt BOOLEAN := false; + rewritten_txt BOOLEAN := false; + query_block_no BOOLEAN := false; + pass BOOLEAN := false; + costs BOOLEAN := false; + + + + empty_line VARCHAR2(80) := NULL; + + + + querytxt_err EXCEPTION; + commlist_err EXCEPTION; + + rewrite_err EXCEPTION; + no_rewrite_err EXCEPTION; + command_err EXCEPTION; + is_not_mv EXCEPTION; + explain_rewrite_err EXCEPTION; + failure_displayed BOOLEAN := false; + + BEGIN + + IF (mv_list IS NOT NULL) THEN + BEGIN + dbms_utility.comma_to_table (mv_list, num_mvs, mv_array); + EXCEPTION + WHEN OTHERS THEN + dbms_output.put_line ('** FAILURE ** Malformed MV list'); + failure_displayed := true; + RAISE; + END; + -- Check whether the given mvs are actually MVs + BEGIN + check_mvs (num_mvs, mv_array); + EXCEPTION + WHEN NO_DATA_FOUND THEN + RAISE is_not_mv; + WHEN OTHERS THEN + RAISE; + END; + END IF; + + IF querytxt IS NULL THEN + RAISE querytxt_err; + END IF; + +-- IF command_list IS NULL THEN +-- RAISE commlist_err; +-- END IF; + + IF command_list IS NOT NULL THEN + BEGIN + dbms_utility.comma_to_table (command_list, num_commands, commands_array); + EXCEPTION + WHEN OTHERS THEN + dbms_output.put_line ('** FAILURE ** Malformed command list'); + failure_displayed := true; + RAISE; + END; + END IF; + + -- Read the list of command and set the BOOLEAN variables appropriately + + FOR i IN 1..num_commands LOOP + command := rtrim(ltrim(upper(commands_array(i)))); + IF command = 'QUERY_TXT' THEN + query_txt := true; + ELSIF command = 'REWRITTEN_TXT' THEN + rewritten_txt := true; + ELSIF command = 'QUERY_BLOCK_NO' THEN + query_block_no := true; + ELSIF command = 'PASS' THEN + pass := true; + ELSIF command = 'COSTS' THEN + costs := true; + ELSE + dbms_output.put_line('Use execute sys.xrw_help to get the list ' || + 'of valid commands'); + RAISE command_err; + END IF; + END LOOP; + +BEGIN + dbms_output.new_line; + BEGIN + IF mv_list IS NULL then + dbms_mview.Explain_Rewrite(querytxt, '', Rewrite_Array); + ELSE + dbms_mview.Explain_Rewrite(querytxt, mv_list, Rewrite_Array); + END IF; + EXCEPTION + WHEN OTHERS THEN + dbms_output.put_line ('** Failure ** DBMS_MVIEW.EXPLAIN_REWRITE has encountered an error'); + failure_displayed := true; + RAISE; + END; + + no_of_msgs := Rewrite_array.count; + DBMS_OUTPUT.PUT_LINE('============================================================================'); + FOR i IN 1..no_of_msgs + LOOP + IF (i = 2) THEN + DBMS_OUTPUT.PUT_LINE('>> '); + DBMS_OUTPUT.PUT_LINE('------------------------- ANALYSIS OF QUERY REWRITE -------------------------'); + END IF; + DBMS_OUTPUT.PUT_LINE('>> '); + IF (query_block_no) THEN + IF (i > 1) THEN + DBMS_OUTPUT.PUT_LINE('>> QRY BLK #: '|| + Rewrite_Array(i).query_block_no); + END IF; + END IF; + DBMS_OUTPUT.PUT_LINE('>> MESSAGE : ' || Rewrite_Array(i).message); + IF (query_txt) THEN + DBMS_OUTPUT.PUT_LINE('>> QUERY : ' || Rewrite_Array(i).query_text); + END IF; + IF (rewritten_txt) THEN + DBMS_OUTPUT.PUT_LINE('>> RW QUERY : '|| Rewrite_Array(i).rewritten_text); + END IF; + IF (costs) THEN + DBMS_OUTPUT.PUT_LINE('>> ORIG COST: '|| Rewrite_Array(i).original_cost || ' RW COST: '|| Rewrite_Array(i).rewritten_cost); + END IF; + + IF (pass) THEN + IF (i > 1) THEN + IF (Rewrite_Array(i).pass = 'YES') THEN + DBMS_OUTPUT.PUT_LINE('>> MESSAGE OUTPUT BEFORE VIEW MERGING... '); + ELSE + DBMS_OUTPUT.PUT_LINE('>> MESSAGE OUTPUT AFTER VIEW MERGING... '); + END IF; + END IF; + END IF; + IF (i = 1) THEN + DBMS_OUTPUT.PUT_LINE('============================================================================'); + ELSIF (i != no_of_msgs) THEN + DBMS_OUTPUT.PUT_LINE('----------------------------------------------------------------------------'); + END IF; + END LOOP; + DBMS_OUTPUT.PUT_LINE('============================ END OF MESSAGES ==============================='); +END; + + + + EXCEPTION + WHEN querytxt_err THEN + dbms_output.put_line('**FAILURE** The querytxt cannot be NULL'); + WHEN commlist_err THEN + dbms_output.put_line('**FAILURE** The command list cannot be NULL'); + + WHEN command_err THEN + dbms_output.put_line('**FAILURE** ' || command || + ' is not a valid command'); + WHEN is_not_mv THEN + -- MV not found, this error has already been displayed + dbms_output.new_line; + WHEN OTHERS THEN + dbms_output.new_line; + IF (NOT failure_displayed) THEN + dbms_output.put_line('**FAILURE** An unexpected error has occurred'); + dbms_output.new_line; + END IF; + RAISE; + END; +/ +show errors; + + +drop public synonym XRW; +create public synonym XRW for SYS.XRW; +GRANT EXECUTE ON XRW TO PUBLIC; + +drop public synonym xrw_HELP; +create public synonym xrw_HELP for SYS.xrw_HELP; +GRANT EXECUTE ON xrw_HELP TO PUBLIC; + + + + + + diff --git a/xtdemo01.dat b/xtdemo01.dat new file mode 100644 index 0000000..f6f535f --- /dev/null +++ b/xtdemo01.dat @@ -0,0 +1,7 @@ +12,RESEARCH,"SARATOGA" +10,"ACCOUNTING",CLEVELAND +11,"ART",SALEM +13,FINANCE,"BOSTON" +21,"SALES",PHILA. +22,"SALES",ROCHESTER +42,"INT'L","SAN FRAN" diff --git a/xtdemo01.sql b/xtdemo01.sql new file mode 100644 index 0000000..3f5a4d3 --- /dev/null +++ b/xtdemo01.sql @@ -0,0 +1,71 @@ +Rem +Rem $Header: xtdemo01.sql 07-jun-2001.14:03:36 rsahani Exp $ +Rem +Rem xtdemo01.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem xtdemo01.sql - External Table Demo 1 +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rsahani 06/07/01 - Merged rsahani_add_xt_demos_010605 +Rem rsahani 06/05/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +connect sys/knl_test7 as sysdba + +Rem Demo 1: External Table - Using variable-length data +Rem ###################### +Rem This demo corresponds to sql*ldr demo Case 1 in rdbms/demo/ulcase.sh +Rem - FIELDS TERMINATED BY specifies that data is terminated by commas, +Rem but may also be enclosed by quotation marks +Rem - datatypes for all fields defaults to CHAR +Rem ###################### + +Rem Create Directory +@xtsetup.sql + +Rem Drop and create external table +drop table xtdemo01; +CREATE TABLE xtdemo01 +( + DEPTNO NUMBER(2), + DNAME CHAR(14), + LOC CHAR(13) +) +ORGANIZATION external +( + TYPE oracle_loader + DEFAULT DIRECTORY def_dir + ACCESS PARAMETERS + ( + RECORDS DELIMITED BY NEWLINE CHARACTERSET WE8DEC + BADFILE 'deptXT.bad' + LOGFILE 'deptXT.log' + FIELDS TERMINATED BY "," OPTIONALLY ENCLOSED BY '"' LDRTRIM + ) + location ('xtdemo01.dat') +) +REJECT LIMIT UNLIMITED; + +Rem Query external table +select * from xtdemo01 order by deptno; + +Rem Cleanup +drop table xtdemo01; +drop directory def_dir; diff --git a/xtdemo02.sql b/xtdemo02.sql new file mode 100644 index 0000000..36640f2 --- /dev/null +++ b/xtdemo02.sql @@ -0,0 +1,86 @@ +Rem +Rem $Header: xtdemo02.sql 07-jun-2001.14:03:36 rsahani Exp $ +Rem +Rem xtdemo02.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem xtdemo02.sql - External Table Demo 2 +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rsahani 06/07/01 - Merged rsahani_add_xt_demos_010605 +Rem rsahani 06/05/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +connect sys/knl_test7 as sysdba + +Rem Demo 2: External Table - Using fixed-format fields +Rem ###################### +Rem This demo corresponds to sql*ldr demo Case 2 in rdbms/demo/ulcase.sh +Rem - POSITIONAL_SPEC is used to identify a column name and the location +Rem of data in the datafile to be loaded into that column +Rem - the datatypes (integer external, char, decimal external) identify +Rem the datatype of data fields in file and not of corresponding +Rem columns in the empXT table +Rem ###################### + +Rem Create directory +@xtsetup.sql + +Rem Drop and Create external table +drop table empXT; +CREATE TABLE empXT +( + EMPNO NUMBER(4), + ENAME VARCHAR2(10), + JOB VARCHAR2(9), + MGR NUMBER(4), + SAL NUMBER(7,2), + COMM NUMBER(7,2), + DEPTNO NUMBER(2) +) +ORGANIZATION external +( + TYPE oracle_loader + DEFAULT DIRECTORY def_dir + ACCESS PARAMETERS + ( + RECORDS DELIMITED BY NEWLINE CHARACTERSET WE8DEC + BADFILE def_dir:'empXT.bad' + LOGFILE def_dir:'empXT.log' + FIELDS LDRTRIM + ( + EMPNO (1:4) INTEGER EXTERNAL(4), + ENAME (6:15) CHAR(10), + JOB (17:25) CHAR(9), + MGR (27:30) INTEGER EXTERNAL(4), + SAL (32:39) INTEGER EXTERNAL(8), + COMM (41:48) INTEGER EXTERNAL(8), + DEPTNO (50:51) INTEGER EXTERNAL(2) + ) + ) + location (def_dir:'ulcase2.dat') +) +REJECT LIMIT UNLIMITED; + +Rem Query External Table +select * from empXT order by empno; + +Rem Cleanup +drop table empXT; +drop directory def_dir; diff --git a/xtdemo03.dat b/xtdemo03.dat new file mode 100644 index 0000000..b9472b8 --- /dev/null +++ b/xtdemo03.dat @@ -0,0 +1,7 @@ +7782, "Clark", "Manager", 7839, 09-June-1981, 2572.50,, 10:101 +7839, "King", "President", , 17-November-1981, 5500.00,, 10:102 +7934, "Miller", "Clerk", 7782, 23-January-1982, 920.00,, 10:102 +7566, "Jones", "Manager", 7839, 02-April-1981, 3123.75,, 20:101 +7499, "Allen", "Salesman", 7698, 20-February-1981, 1600.00, 300.00, 30:103 +7654, "Martin", "Salesman", 7698, 28-September-1981, 1312.50, 1400.00, 30:103 +7658, "Chan", "Analyst", 7566, 03-May-1982, 3450,, 20:101 diff --git a/xtdemo03.sql b/xtdemo03.sql new file mode 100644 index 0000000..3ae2e16 --- /dev/null +++ b/xtdemo03.sql @@ -0,0 +1,94 @@ +Rem +Rem $Header: xtdemo03.sql 07-jun-2001.14:03:38 rsahani Exp $ +Rem +Rem xtdemo03.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem xtdemo03.sql - External Table Demo 3 +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rsahani 06/07/01 - Merged rsahani_add_xt_demos_010605 +Rem rsahani 06/05/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 108 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 200 +SET ECHO ON + +connect sys/knl_test7 as sysdba + +Rem Demo 3: External Table - Using a Delimited, Free-Format File +Rem ###################### +Rem This demo corresponds to sql*ldr demo Case 3 in rdbms/demo/ulcase.sh +Rem - general specifications are overidden with declarations for +Rem individual fields: +Rem some data is enclosed in quotation marks, some is set off by commas +Rem and the values for DEPTNO and PROJNO are separated by colon +Rem - %a (agent number), %p (process number) is appended to +Rem BAD filename and LOG filename +Rem ###################### + +Rem Create Directory +@xtsetup.sql + +Rem Drop and create external table +drop table xtdemo03; +CREATE TABLE xtdemo03 +( + EMPNO NUMBER(4), + ENAME CHAR(10), + JOB CHAR(9), + MGR NUMBER(4), + HIREDATE DATE, + SAL NUMBER(7,2), + COMM NUMBER(7,2), + DEPTNO NUMBER(2), + PROJNO NUMBER +) +ORGANIZATION external +( + TYPE oracle_loader + DEFAULT DIRECTORY def_dir + ACCESS PARAMETERS + ( + RECORDS DELIMITED BY NEWLINE CHARACTERSET WE8DEC + BADFILE 'empXT_%a_%p.bad' + LOGFILE 'empXT_%a_%p.log' + FIELDS TERMINATED BY "," OPTIONALLY ENCLOSED BY '"' LDRTRIM + ( + EMPNO CHAR(255), + ENAME CHAR(255), + JOB CHAR(255), + MGR CHAR(255), + HIREDATE CHAR(20) + DATE_FORMAT DATE MASK "DD-Month-YYYY", + SAL CHAR(255), + COMM CHAR(255), + DEPTNO CHAR(255) + TERMINATED BY ":" OPTIONALLY ENCLOSED BY '"', + PROJNO CHAR(255) + ) + ) + location ('xtdemo03.dat') +) +REJECT LIMIT UNLIMITED; + +Rem Query external table +select * from xtdemo03 order by empno; + +Rem Cleanup +drop table xtdemo03; +drop directory def_dir; + diff --git a/xtdemo04.dat b/xtdemo04.dat new file mode 100644 index 0000000..6480242 --- /dev/null +++ b/xtdemo04.dat @@ -0,0 +1,9 @@ +1234 BAKER 10 9999 101 102 103 +2664 YOUNG 20 2893 425 102 +5321 OTOOLE 10 9999 321 55 40 +2134 FARMER 20 4555 236 456 +2414 LITTLE 20 5634 236 456 40 +6542 LEE 10 4532 102 321 14 +4532 PERKINS 10 9999 40 +1244 HUNT 11 3452 665 133 456 + 123 DOOLITTLE 12 9940 132 diff --git a/xtdemo04.sql b/xtdemo04.sql new file mode 100644 index 0000000..3efc1e2 --- /dev/null +++ b/xtdemo04.sql @@ -0,0 +1,124 @@ +Rem +Rem $Header: xtdemo04.sql 07-jun-2001.14:03:39 rsahani Exp $ +Rem +Rem xtdemo04.sql +Rem +Rem Copyright (c) Oracle Corporation 2001. All Rights Reserved. +Rem +Rem NAME +Rem xtdemo04.sql - +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem +Rem +Rem MODIFIED (MM/DD/YY) +Rem rsahani 06/07/01 - Merged rsahani_add_xt_demos_010605 +Rem rsahani 06/06/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 108 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 200 +SET ECHO ON + +connect sys/knl_test7 as sysdba + +Rem Demo 4: External Table - Loading data into multiple tables +Rem ###################### + +Rem Create Directory +@xtsetup.sql + +Rem Drop and create external table +drop table emp_proj_XT; +CREATE TABLE emp_proj_XT +( + EMPNO NUMBER(4), + ENAME CHAR(10), + DEPTNO NUMBER(2), + MGR NUMBER(4), + PROJ1 NUMBER, + PROJ2 NUMBER, + PROJ3 NUMBER +) +ORGANIZATION external +( + TYPE oracle_loader + DEFAULT DIRECTORY def_dir + ACCESS PARAMETERS + ( + RECORDS DELIMITED BY NEWLINE CHARACTERSET WE8DEC + BADFILE 'emp_proj.bad' + DISCARDFILE 'emp_proj.dis' + LOGFILE 'emp_proj.log' + FIELDS LDRTRIM + ( + EMPNO (1:4) INTEGER EXTERNAL(4), + ENAME (6:15) CHAR(10), + DEPTNO (17:18) CHAR(2), + MGR (20:23) INTEGER EXTERNAL(4), + PROJ1 (25:27) INTEGER EXTERNAL(4), + PROJ2 (29:31) INTEGER EXTERNAL(3), + PROJ3 (32:34) INTEGER EXTERNAL(4) + ) + ) + location ('xtdemo04.dat') +) +REJECT LIMIT UNLIMITED; + +Rem Query external table +select * from emp_proj_XT order by empno, ename; + +Rem Create regular tables in which data will be inserted +drop table emp; +create table emp +( + EMPNO NUMBER(4), + ENAME CHAR(10), + DEPTNO NUMBER(2), + MGR NUMBER(4) +); + +select count(*) from emp; + +drop table proj; +create table proj +( + EMPNO NUMBER(4), + PROJID NUMBER +); + +select count(*) from proj; + +Rem Load data into EMP and PROJ table from EMP_PROJ_XT table +Rem using MULTI-TABLE INSERT +insert all +when 1=1 then + into emp (empno, ename, deptno, mgr) + values (empno, ename, deptno, mgr) +when proj1 is not null then + into proj (empno, projid) + values (empno, proj1) +when proj2 is not null then + into proj (empno, projid) + values (empno, proj2) +when proj3 is not null then + into proj (empno, projid) + values (empno, proj3) +select * from emp_proj_XT; + +Rem Verify that data has been loaded correctly +select * from emp order by empno; +select * from proj order by 1, 2; + +Rem Cleanup +drop table emp; +drop table proj; +drop table emp_proj_XT; +drop directory def_dir; diff --git a/xtsetup.sql b/xtsetup.sql new file mode 100644 index 0000000..0697eca --- /dev/null +++ b/xtsetup.sql @@ -0,0 +1,42 @@ +Rem +Rem $Header: xtsetup.sql 06-oct-2003.13:23:55 rsahani Exp $ +Rem +Rem xtsetup.sql +Rem +Rem Copyright (c) 2001, 2003, Oracle Corporation. All rights reserved. +Rem +Rem NAME +Rem xtsetup.sql - Create DEFAULT DIRECTORY required by +Rem External Table Demos +Rem +Rem DESCRIPTION +Rem +Rem +Rem NOTES +Rem SQL statements for creating default directory should be +Rem uncommented and modified to point to location where +Rem data files referenced in external table are located +Rem +Rem MODIFIED (MM/DD/YY) +Rem rsahani 10/06/03 - uncomment "create directory" +Rem rsahani 06/07/01 - Merged rsahani_add_xt_demos_010605 +Rem rsahani 06/05/01 - Created +Rem + +SET FEEDBACK 1 +SET NUMWIDTH 10 +SET LINESIZE 80 +SET TRIMSPOOL ON +SET TAB OFF +SET PAGESIZE 100 +SET ECHO ON + +connect sys/knl_test7 as sysdba + +Rem Drop and create default directory +Rem - &1 in create directory statement below must be replaced by +Rem absolute path of the directory where data files referenced +Rem in external table demos are stored +drop directory def_dir; + +create directory def_dir as '&1';