[ruby-oci8-devel] About XML DB support in Ruby-OCI8

KUBO Takehiro kubo at jiubao.org
Thu Mar 20 11:08:33 EDT 2008


Hi Liming,

Liming Lian <liming.lian at oracle.com> writes:

> Hi Kubo,
>
> Thanks for sharing. As you said, the XML DB implementation depends on 
> object types support. This raised my interest on how object types are 
> supported in Ruby-OCI8. By hacking the code, I am still not sure how to 
> use this feature and whether it has been fully implemented. It will be 
> appreciated if  you could show me some Ruby code samples on how to 
> manipulate Object types in database supposing that this feature is 
> available.
>
> Thanks in advance!

I'll answer your questions later. It needs a time for me to write
complex things in English. It is easy for me to write C source code
than English documents.

Here is a quick fix to fetch XMLTYPE data as REXML objects.

===================================================================
--- ext/oci8/xmldb.c	(revision 253)
+++ ext/oci8/xmldb.c	(working copy)
@@ -1,7 +1,8 @@
 /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
 #include "oci8.h"
 
-#if 0 /* disabled for a while. */ && (ORACLE_CLIENT_VERSION >= 1000 || defined RUNTIME_API_CHECK)
+#if defined RUNTIME_API_CHECK || ORACLE_CLIENT_VERSION >= 1000
+/* Oracle 10g or upper */
 
 #ifndef HAVE_XMLOTN_H
 /* declarations in xmlproc.h of Oracle XML Development Kit */
@@ -158,6 +159,87 @@
 static VALUE add_attributes(VALUE obj, struct xmlctx *xctx, xmlnode *node);
 static VALUE add_nodemap(VALUE obj, struct xmlctx *xctx, xmlnamedmap *map);
 
+typedef struct {
+    oci8_bind_t bind;
+    struct xmlctx *xctx;
+} oci8_bind_xmltype_t;
+
+static void bind_xmltype_free(oci8_base_t *base)
+{
+    oci8_bind_t *obind = (oci8_bind_t *)base;
+    oci8_bind_xmltype_t *xmlbind = (oci8_bind_xmltype_t *)base;
+    xmlnode **nodes = (xmlnode **)obind->valuep;
+    ub4 idx = 0;
+
+    do {
+        if (nodes[idx] != NULL) {
+            OCIObjectFree(oci8_envhp, oci8_errhp, nodes[idx], OCI_DEFAULT);
+            nodes[idx] = NULL;
+        }
+    } while (++idx < obind->maxar_sz);
+    if (xmlbind->xctx != NULL) {
+        OCIXmlDbFreeXmlCtx(xmlbind->xctx);
+        xmlbind->xctx = NULL;
+    }
+}
+
+static VALUE bind_xmltype_get(oci8_bind_t *obind, void *data, void *null_struct)
+{
+    oci8_bind_xmltype_t *xmlbind = (oci8_bind_xmltype_t *)obind;
+    xmlnode *node = *(xmlnode **)data;
+    return oci8_make_rexml(xmlbind->xctx, node);
+}
+
+static void bind_xmltype_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
+{
+    rb_raise(rb_eRuntimeError, "not supported");
+}
+
+static void bind_xmltype_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE length)
+{
+    oci8_bind_xmltype_t *xmlbind = (oci8_bind_xmltype_t *)obind;
+    oci8_svcctx_t *svcctx = oci8_get_svcctx(svc);
+    VALUE md = rb_funcall(svc, rb_intern("describe_type"), 1, rb_str_new2("SYS.XMLTYPE"));
+    VALUE tdo = rb_funcall(svc, rb_intern("get_tdo_by_metadata"), 1, md);
+    /*
+     * md = conn.describe_type('SYS.XMLTYPE') # md:  metadata
+     * tdo = conn.get_tdo_by_metadata(md)     # tdo: type descriptor object
+     */
+
+    obind->value_sz = sizeof(xmlnode *);
+    obind->alloc_sz = sizeof(xmlnode *);
+    obind->tdo = tdo;
+    xmlbind->xctx = OCIXmlDbInitXmlCtx(oci8_envhp, svcctx->base.hp.svc, oci8_errhp, NULL, 0);
+}
+
+static void bind_xmltype_init_elem(oci8_bind_t *obind, VALUE svc)
+{
+    xmlnode **nodes = (xmlnode **)obind->valuep;
+    oci8_base_t *tdo = DATA_PTR(obind->tdo);
+    oci8_svcctx_t *svcctx = oci8_get_svcctx(svc);
+    ub4 idx = 0;
+
+    do {
+        oci_lc(OCIObjectNew(oci8_envhp, oci8_errhp, svcctx->base.hp.svc, OCI_TYPECODE_OPAQUE, tdo->hp.tdo, NULL, OCI_DURATION_SESSION, FALSE, (dvoid**)&nodes[idx]));
+    } while (++idx < obind->maxar_sz);
+}
+
+static oci8_bind_class_t bind_rexml_class = {
+    {
+        NULL,
+        bind_xmltype_free,
+        sizeof(oci8_bind_xmltype_t)
+    },
+    bind_xmltype_get,
+    bind_xmltype_set,
+    bind_xmltype_init,
+    bind_xmltype_init_elem,
+    NULL,
+    NULL,
+    NULL,
+    SQLT_NTY
+};
+
 void Init_oci_xmldb(void)
 {
     id_add = rb_intern("add");
@@ -172,6 +254,9 @@
     REXML_XMLDecl = rb_eval_string("REXML::XMLDecl");
     REXML_DocType = rb_eval_string("REXML::DocType");
     REXML_NotationDecl = rb_eval_string("REXML::NotationDecl");
+
+    /* OCI8::BindType::REXML */
+    oci8_define_bind_class("REXML", &bind_rexml_class);
 }
 
 VALUE oci8_make_rexml(struct xmlctx *xctx, xmlnode *node)
===================================================================

and

  OCI8::BindType::Mapping[:xmltype] = OCI8::BindType::REXML


More information about the ruby-oci8-devel mailing list