Author: byterock
Date: Mon Mar 10 13:33:51 2008
New Revision: 10901

Modified:
   dbd-oracle/trunk/Changes
   dbd-oracle/trunk/Oracle.h
   dbd-oracle/trunk/Oracle.pm
   dbd-oracle/trunk/dbdimp.c
   dbd-oracle/trunk/oci.def
   dbd-oracle/trunk/ocitrace.h

Log:
new patch for XML

Modified: dbd-oracle/trunk/Changes
==============================================================================
--- dbd-oracle/trunk/Changes    (original)
+++ dbd-oracle/trunk/Changes    Mon Mar 10 13:33:51 2008
@@ -1,5 +1,6 @@
 =head1 Changes in DBD-Oracle 1.21(svn rev xxxx) 
 
+  Added support for direct insert of large XML data with XMLType from Hendrik 
Fuss
   Fixed memory leak (not releasing Temp Lob with OCILobFreeTemporary) when 
created for a bind John Scoles
   Added suppot for bind_param_inout_array with use with execute_array from 
John Scoles
   Added enhancement for Embedded Objects handling from Paul G. Weiss

Modified: dbd-oracle/trunk/Oracle.h
==============================================================================
--- dbd-oracle/trunk/Oracle.h   (original)
+++ dbd-oracle/trunk/Oracle.h   Mon Mar 10 13:33:51 2008
@@ -98,5 +98,5 @@
 
 #define ORA_VARCHAR2_TABLE     201
 #define ORA_NUMBER_TABLE       202
-
+#define ORA_NTY                            108
 /* end of Oracle.h */

Modified: dbd-oracle/trunk/Oracle.pm
==============================================================================
--- dbd-oracle/trunk/Oracle.pm  (original)
+++ dbd-oracle/trunk/Oracle.pm  Mon Mar 10 13:33:51 2008
@@ -22,7 +22,7 @@
            ORA_VARCHAR2 ORA_STRING ORA_NUMBER ORA_LONG ORA_ROWID ORA_DATE
            ORA_RAW ORA_LONGRAW ORA_CHAR ORA_CHARZ ORA_MLSLABEL ORA_NTY
            ORA_CLOB ORA_BLOB ORA_RSET ORA_VARCHAR2_TABLE ORA_NUMBER_TABLE
-           SQLT_INT SQLT_FLT
+           SQLT_INT SQLT_FLT XMLType
        ) ],
         ora_session_modes => [ qw( ORA_SYSDBA ORA_SYSOPER ) ],
     );
@@ -1193,7 +1193,7 @@
   ORA_VARCHAR2 ORA_STRING ORA_NUMBER ORA_LONG ORA_ROWID ORA_DATE
   ORA_RAW ORA_LONGRAW ORA_CHAR ORA_CHARZ ORA_MLSLABEL ORA_NTY
   ORA_CLOB ORA_BLOB ORA_RSET ORA_VARCHAR2_TABLE ORA_NUMBER_TABLE
-  SQLT_INT SQLT_FLT
+  SQLT_INT SQLT_FLT XMLType
  
 =item SQLCS_IMPLICIT
 
@@ -1482,7 +1482,7 @@
 
 Additional values when DBD::Oracle was built using OCI 8 and later:
 
-  ORA_CLOB, ORA_BLOB, ORA_NTY, ORA_VARCHAR2_TABLE, ORA_NUMBER_TABLE
+  ORA_CLOB, ORA_BLOB, ORA_NTY, ORA_VARCHAR2_TABLE, ORA_NUMBER_TABLE, XMLType
 
 See L</Binding Cursors> for the correct way to use ORA_RSET.
 
@@ -3221,6 +3221,36 @@
 
 Any NULL values found in the embedded object will be returned as 'undef'.
 
+=head1 Support for Insert of XMLType
+
+Inserting large XML data sets into tables with XMLType fields is now supported 
by DBD::Oracle. The only special 
+requirement is the use of bind_param() with an attribute hash parameter that 
specifies ora_type as ORA_NTY. For
+example with a table like this;
+
+   create table books (book_id number, book_xml XMLType);
+
+one can insert data using this code
+
+   $sql='insert into books values (1,:p_xml)';
+   $xml= '<Books>
+                  <Book id=1>
+                       <Title>Programming the Perl DBI</Title>
+                       <Subtitle>The Cheetah Book</Subtitle>
+                       <Authors>
+                               <Author>T. Bunce</Author>
+                               <Author>Alligator Descartes</Author>
+                       </Authors>
+                       
+                  </Book>
+               </Books>....
+               <Book id=10000> ...';
+   my $sth =$dbh-> prepare($sql);
+   $sth-> bind_param("p_xml", $xml, { ora_type => ORA_NTY }); 
+   $sth-> execute();
+       
+In the above case we will assume that $xml has 10000 Book nodes and is over 
32k in size and is well formed XML. 
+This will also work for XML that is smaller than 32k as well. Attempting to 
insert malformed XML will cause an error. 
+
 =head1 Oracle Related Links
 
 =head2 Oracle Instant Client

Modified: dbd-oracle/trunk/dbdimp.c
==============================================================================
--- dbd-oracle/trunk/dbdimp.c   (original)
+++ dbd-oracle/trunk/dbdimp.c   Mon Mar 10 13:33:51 2008
@@ -262,6 +262,7 @@
     case 116:  /* SQLT_RSET    OCI 8 cursor variable   */
        case ORA_VARCHAR2_TABLE: /* 201 */
     case ORA_NUMBER_TABLE: /* 202 */
+    case ORA_NTY:   /* SQLT_NTY   Well realy only XML clobs not embedded 
objects  */
        return 1;
     }
     return 0;
@@ -985,6 +986,99 @@
 
 /* ================================================================== */
 
+#define MAX_OCISTRING_LEN 32766
+
+SV *
+createxmlfromstring(SV *sth, imp_sth_t *imp_sth, SV *source){
+
+  dTHX;
+  OCIXMLType *xml = NULL;
+  ub4 len;
+  sword status;
+  ub1 src_type;
+  dvoid* src_ptr = NULL;
+  D_imp_dbh_from_sth;
+  SV* sv_dest;
+  dvoid *bufp;
+  ub1 csform;
+  ub2 csid;
+  csid = 0;
+  csform = SQLCS_IMPLICIT;
+
+
+  len = SvLEN(source);
+  bufp = SvPV(source, len);
+
+  if (DBIS->debug >=3)
+     PerlIO_printf(DBILOGFP, " creating xml from string that is %d 
long\n",len);
+
+  if(len > MAX_OCISTRING_LEN) {
+     src_type = OCI_XMLTYPE_CREATE_CLOB;
+
+     if (DBIS->debug >=5)
+        PerlIO_printf(DBILOGFP, " use a temp lob locator for large xml \n");
+
+     OCIDescriptorAlloc_ok(imp_dbh->envhp, &src_ptr, OCI_DTYPE_LOB);
+
+     OCILobCreateTemporary_log_stat(imp_dbh->svchp, imp_sth->errhp,
+                        (OCILobLocator *) src_ptr, (ub2) OCI_DEFAULT,
+                        (ub1) OCI_DEFAULT, OCI_TEMP_CLOB, FALSE, 
OCI_DURATION_SESSION, status);
+
+        if (status != OCI_SUCCESS) {
+        oci_error(sth, imp_sth->errhp, status, "OCILobCreateTemporary");
+     }
+     csid = (SvUTF8(source) && !CS_IS_UTF8(csid)) ? utf8_csid : 
CSFORM_IMPLIED_CSID(csform);
+
+     OCILobWriteAppend_log_stat(imp_dbh->svchp, imp_dbh->errhp, src_ptr,
+                                      &len, bufp, (ub4)len, OCI_ONE_PIECE,
+                                      NULL, NULL,
+                              csid, csform, status);
+
+     if (status != OCI_SUCCESS) {
+               oci_error(sth, imp_sth->errhp, status, "OCILobWriteAppend");
+     }
+
+  } else {
+      src_type = OCI_XMLTYPE_CREATE_OCISTRING;
+      if (DBIS->debug >=5)
+        PerlIO_printf(DBILOGFP, " use a OCIStringAssignText for small xml \n");
+
+
+         OCIStringAssignText(imp_dbh->envhp,
+                                   imp_dbh->errhp,
+                                   (CONST text*) source,
+                                   (ub2) SvLEN(source),
+                                   (OCIString **) &src_ptr);
+  }
+
+
+
+  status=    OCIXMLTypeCreateFromSrc(imp_dbh->svchp,
+                                   imp_dbh->errhp,
+                                   (OCIDuration)OCI_DURATION_CALLOUT,
+                                   (ub1)src_type,
+                                   (dvoid *)src_ptr,
+                                   (sb4)OCI_IND_NOTNULL,
+                                   &xml);
+
+  if (status != OCI_SUCCESS) {
+               oci_error(sth, imp_sth->errhp, status, 
"OCIXMLTypeCreateFromSrc");
+  }
+
+  /* free temporary resources */
+  if ( src_type == OCI_XMLTYPE_CREATE_CLOB ) {
+        OCILobFreeTemporary(imp_dbh->svchp, imp_dbh->errhp,
+                                   (OCILobLocator*) src_ptr);
+
+        OCIDescriptorFree((dvoid *) src_ptr, (ub4) OCI_DTYPE_LOB);
+  }
+
+
+  sv_dest = newSViv(0);
+  sv_setref_pv(sv_dest, "OCIXMLTypePtr", xml);
+  return sv_dest;
+
+}
 
 
 void
@@ -1147,6 +1241,9 @@
     case SQL_LONGVARCHAR:
        return 8;       /* Oracle LONG          */
 
+    case SQL_UDT:
+               return 108;     /* Oracle NTY           */
+
     case SQL_CLOB:
        return 112;     /* Oracle CLOB          */
 
@@ -2259,6 +2356,74 @@
     return 1;
 }
 
+static int
+dbd_rebind_ph_xml( SV* sth, imp_sth_t *imp_sth, phs_t *phs) {
+   dTHX;
+   dTHR;
+   OCIType *tdo = NULL;
+   sword status;
+   SV* ptr;
+
+   if (DBIS->debug >= 3)
+        PerlIO_printf(DBILOGFP, " in  dbd_rebind_ph_xml\n");
+
+   /*go and create the XML dom from the passed in value*/
+
+   phs->sv=createxmlfromstring(sth, imp_sth, phs->sv );
+
+   if (phs->is_inout)
+        croak("OUT binding for NTY is currently unsupported");
+
+     /* ensure that the value is a support named object type */
+     /* (currently only OCIXMLType*)                         */
+   if ( sv_isa(phs->sv, "OCIXMLTypePtr") ) {
+         OCITypeByName(imp_sth->envhp, imp_sth->errhp, imp_sth->svchp,
+                     (CONST text*)"SYS", 3,
+                     (CONST text*)"XMLTYPE", 7,
+                     (CONST text*)0, 0,
+                     OCI_DURATION_CALLOUT, OCI_TYPEGET_HEADER,
+                     &tdo);
+         ptr = SvRV(phs->sv);
+         phs->progv  = (void*) SvIV(ptr);
+         phs->maxlen = sizeof(OCIXMLType*);
+   }
+    else
+         croak("Unsupported named object type for bind parameter");
+
+
+    /* bind by name */
+
+    OCIBindByName_log_stat(imp_sth->stmhp, &phs->bndhp, imp_sth->errhp,
+                          (text*)phs->name, (sb4)strlen(phs->name),
+                          (dvoid *) NULL, /* value supplied in BindObject 
later */
+                          0,
+                          (ub2)phs->ftype, 0,
+                          NULL,
+                          0, 0,
+                          NULL,
+                          (ub4)OCI_DEFAULT,
+                          status
+                          );
+
+    if (status != OCI_SUCCESS) {
+       oci_error(sth, imp_sth->errhp, status, "OCIBindByName SQLT_NTY");
+       return 0;
+    }
+    if (DBIS->debug >= 3)
+          PerlIO_printf(DBILOGFP, "    pp_rebind_ph_nty: END\n");
+
+
+     /* bind the object */
+     OCIBindObject(phs->bndhp, imp_sth->errhp,
+                 (CONST OCIType*)tdo,
+                 (dvoid **)&phs->progv,
+                 (ub4*)NULL,
+                 (dvoid **)NULL,
+                 (ub4*)NULL);
+
+     return 2;
+ }
+
 
 static int
 dbd_rebind_ph(SV *sth, imp_sth_t *imp_sth, phs_t *phs)
@@ -2277,6 +2442,7 @@
                phs->name, (SvPOK(phs->sv) ? neatsvpv(phs->sv,0) : 
"NULL"),(SvUTF8(phs->sv) ? "is-utf8" : "not-utf8"),
                phs->ftype, phs->csid, phs->csform, phs->is_inout);
 
+
     switch (phs->ftype) {
     case ORA_VARCHAR2_TABLE:
                done = dbd_rebind_ph_varchar2_table(sth, imp_sth, phs);
@@ -2291,6 +2457,9 @@
     case SQLT_RSET:
            done = dbd_rebind_ph_rset(sth, imp_sth, phs);
            break;
+        case ORA_NTY:
+           done = dbd_rebind_ph_xml(sth, imp_sth, phs);
+           break;
     default:
            done = dbd_rebind_ph_char(imp_sth, phs);
     }

Modified: dbd-oracle/trunk/oci.def
==============================================================================
--- dbd-oracle/trunk/oci.def    (original)
+++ dbd-oracle/trunk/oci.def    Mon Mar 10 13:33:51 2008
@@ -374,4 +374,4 @@
 OCILobFreeTemporary
 OCILobLocatorAssign
 OCILobCreateTemporary
-
+OCIXMLTypeCreateFromSrc

Modified: dbd-oracle/trunk/ocitrace.h
==============================================================================
--- dbd-oracle/trunk/ocitrace.h (original)
+++ dbd-oracle/trunk/ocitrace.h Mon Mar 10 13:33:51 2008
@@ -38,6 +38,13 @@
 
 
 
+#define 
OCIXMLTypeCreateFromSrc_log_stat(svchp,envhp,src_type,src_ptr,xml,stat)\
+    stat =OCIXMLTypeCreateFromSrc 
(svchp,envhp,(OCIDuration)OCI_DURATION_CALLOUT,(ub1)src_type,(dvoid 
*)src_ptr,(sb4)OCI_IND_NOTNULL, xml);\
+    (DBD_OCI_TRACEON) \
+               ? PerlIO_printf(DBD_OCI_TRACEFP,\
+                        
"%sOCIXMLTypeCreateFromSrc_log_stat(%p,%p,%p,%p,%p)=%s\n",\
+                        OciTp,  (void*)svchp,(void*)envhp, src_type, 
src_ptr,oci_status_name(stat)),stat \
+   : stat
 
 #define OCILobLocatorIsInit_log_stat(envhp,errhp,loc,is_init,stat)\
     stat =OCILobLocatorIsInit (envhp,errhp,loc,is_init );\

Reply via email to