[ruby-oci8-commit] [257] trunk/ruby-oci8: * ext/oci8/encoding.c, ext/oci8/extconf.rb, ext/oci8 /oci8.h

nobody at rubyforge.org nobody at rubyforge.org
Sat Mar 29 09:06:31 EDT 2008


Revision: 257
Author:   kubo
Date:     2008-03-29 09:06:30 -0400 (Sat, 29 Mar 2008)

Log Message:
-----------
* ext/oci8/encoding.c, ext/oci8/extconf.rb, ext/oci8/oci8.h
  ext/oci8/oci8lib.c: add a new file encoding.c.
    oci8_charset_id2name() is added to convert Oracle charset
    id to charset name. If the Oracle client version is 9iR2
    or upper, it uses OCINlsCharSetIdToName(). If 9iR1 or lower,
    it uses PL/SQL function nls_charset_name() and converts
    at the server side.
* ext/oci8/metadata.c: use oci8_charset_id2name() instead of
    OCINlsCharSetIdToName().

Modified Paths:
--------------
    trunk/ruby-oci8/ChangeLog
    trunk/ruby-oci8/ext/oci8/extconf.rb
    trunk/ruby-oci8/ext/oci8/metadata.c
    trunk/ruby-oci8/ext/oci8/oci8.h
    trunk/ruby-oci8/ext/oci8/oci8lib.c

Added Paths:
-----------
    trunk/ruby-oci8/ext/oci8/encoding.c

Modified: trunk/ruby-oci8/ChangeLog
===================================================================
--- trunk/ruby-oci8/ChangeLog	2008-03-29 08:37:20 UTC (rev 256)
+++ trunk/ruby-oci8/ChangeLog	2008-03-29 13:06:30 UTC (rev 257)
@@ -1,4 +1,15 @@
 2008-03-29  KUBO Takehiro  <kubo at jiubao.org>
+	* ext/oci8/encoding.c, ext/oci8/extconf.rb, ext/oci8/oci8.h
+	  ext/oci8/oci8lib.c: add a new file encoding.c.
+	    oci8_charset_id2name() is added to convert Oracle charset
+	    id to charset name. If the Oracle client version is 9iR2
+	    or upper, it uses OCINlsCharSetIdToName(). If 9iR1 or lower,
+	    it uses PL/SQL function nls_charset_name() and converts
+	    at the server side.
+	* ext/oci8/metadata.c: use oci8_charset_id2name() instead of
+	    OCINlsCharSetIdToName().
+
+2008-03-29  KUBO Takehiro  <kubo at jiubao.org>
 	* ext/oci8/extconf.rb, ext/oci8/oci8lib.c, ext/oci8/oci8.h:
 	    When '--with-runtime-check' is passed to extconf.rb, oci8lib.so
 	    is no longer linked to an Oracle client library at compilation

Added: trunk/ruby-oci8/ext/oci8/encoding.c
===================================================================
--- trunk/ruby-oci8/ext/oci8/encoding.c	                        (rev 0)
+++ trunk/ruby-oci8/ext/oci8/encoding.c	2008-03-29 13:06:30 UTC (rev 257)
@@ -0,0 +1,182 @@
+/* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
+/*
+ * encoding.c - part of ruby-oci8
+ *
+ * Copyright (C) 2008 KUBO Takehiro <kubo at jiubao.org>
+ *
+ */
+#include "oci8.h"
+
+#ifndef OCI_NLS_MAXBUFSZ
+#define OCI_NLS_MAXBUFSZ 100
+#endif
+
+/* type of callback function's argument */
+typedef struct {
+    oci8_svcctx_t *svcctx;
+    OCIStmt *stmtp;
+    union {
+        VALUE name;
+        int csid;
+    } u;
+} cb_arg_t;
+
+/* Oracle charset id -> Oracle charset name */
+static VALUE csid2name;
+VALUE oci8_charset_id2name(VALUE svc, VALUE csid);
+static VALUE charset_id2name_func(cb_arg_t *arg);
+static VALUE ensure_func(cb_arg_t *arg);
+
+#ifdef HAVE_TYPE_RB_ENCODING
+/* Oracle charset name -> Oracle charset id */
+static ID id_upcase;
+static VALUE csname2id;
+static VALUE oci8_charset_name2id(VALUE svc, VALUE name);
+static VALUE charset_name2id_func(cb_arg_t *arg);
+#endif /* HAVE_TYPE_RB_ENCODING */
+
+VALUE oci8_charset_id2name(VALUE svc, VALUE csid)
+{
+    VALUE name = rb_hash_aref(csid2name, csid);
+
+    if (!NIL_P(name)) {
+        return name;
+    }
+    Check_Type(csid, T_FIXNUM);
+    if (have_OCINlsCharSetIdToName) {
+        /* Oracle 9iR2 or upper */
+        char buf[OCI_NLS_MAXBUFSZ];
+        sword rv;
+
+        rv = OCINlsCharSetIdToName(oci8_envhp, TO_ORATEXT(buf), sizeof(buf), FIX2INT(csid));
+        if (rv != OCI_SUCCESS) {
+            return Qnil;
+        }
+        name = rb_str_new2(buf);
+    } else {
+        /* Oracle 9iR1 or lower */
+        cb_arg_t arg;
+        arg.svcctx = oci8_get_svcctx(svc);
+        arg.stmtp = NULL;
+        arg.u.csid = FIX2INT(csid);
+        name = rb_ensure(charset_id2name_func, (VALUE)&arg, ensure_func, (VALUE)&arg);
+        if (NIL_P(name)) {
+            return Qnil;
+        }
+    }
+    OBJ_FREEZE(name);
+    rb_hash_aset(csid2name, csid, name);
+#ifdef HAVE_TYPE_RB_ENCODING
+    rb_hash_aset(csname2id, name, csid);
+#endif /* HAVE_TYPE_RB_ENCODING */
+    return name;
+}
+
+/* convert chaset id to charset name by querying Oracle server.
+ * This routine is used only when the Oracle client version is 9iR1 or lower.
+ */
+static VALUE charset_id2name_func(cb_arg_t *arg)
+{
+    char buf[OCI_NLS_MAXBUFSZ];
+    ub2 buflen;
+    OCIBind *bind1 = NULL;
+    OCIBind *bind2 = NULL;
+    sword rv;
+    const char *sql = "BEGIN :name := nls_charset_name(:csid); END;";
+
+    buflen = 0;
+    rv = OCIHandleAlloc(oci8_envhp, (dvoid*)&arg->stmtp, OCI_HTYPE_STMT, 0, NULL);
+    if (rv != OCI_SUCCESS) {
+        oci8_env_raise(oci8_envhp, rv);
+    }
+    oci_lc(OCIStmtPrepare(arg->stmtp, oci8_errhp, (text*)sql, strlen(sql), OCI_NTV_SYNTAX, OCI_DEFAULT));
+    oci_lc(OCIBindByPos(arg->stmtp, &bind1, oci8_errhp, 1, buf, OCI_NLS_MAXBUFSZ, SQLT_CHR, NULL, &buflen, 0, 0, 0, OCI_DEFAULT));
+    oci_lc(OCIBindByPos(arg->stmtp, &bind2, oci8_errhp, 2, (dvoid*)&arg->u.csid, sizeof(int), SQLT_INT, NULL, NULL, 0, 0, 0, OCI_DEFAULT));
+    oci_lc(OCIStmtExecute_nb(arg->svcctx, arg->svcctx->base.hp.svc, arg->stmtp, oci8_errhp, 1, 0, NULL, NULL, OCI_DEFAULT));
+    return rb_str_new(buf, buflen);
+}
+
+static VALUE ensure_func(cb_arg_t *arg)
+{
+    if (arg->stmtp != NULL) {
+        OCIHandleFree(arg->stmtp, OCI_HTYPE_STMT);
+    }
+    return Qnil;
+}
+
+#ifdef HAVE_TYPE_RB_ENCODING
+
+static VALUE oci8_charset_name2id(VALUE svc, VALUE name)
+{
+    VALUE csid = rb_hash_aref(csname2id, StringValue(name));
+
+    if (!NIL_P(csid)) {
+        return csid;
+    }
+    name = rb_funcall(name, id_upcase, 0);
+    if (have_OCINlsCharSetNameToId) {
+        /* Oracle 9iR2 or upper */
+        ub2 rv;
+
+        rv = OCINlsCharSetNameToId(oci8_envhp, RSTRING_ORATEXT(name));
+        if (rv == 0) {
+            return Qnil;
+        }
+        csid = INT2FIX(rv);
+    } else {
+        /* Oracle 9iR1 or lower */
+        cb_arg_t arg;
+        arg.svcctx = oci8_get_svcctx(svc);
+        arg.stmtp = NULL;
+        arg.u.name = name;
+        csid = rb_ensure(charset_name2id_func, (VALUE)&arg, ensure_func, (VALUE)&arg);
+        if (NIL_P(csid)) {
+            return Qnil;
+        }
+    }
+    rb_hash_aset(csid2name, csid, name);
+    rb_hash_aset(csname2id, name, csid);
+    return csid;
+}
+
+/* convert chaset name to charset id by querying Oracle server.
+ * This routine is used only when the Oracle client version is 9iR1 or lower.
+ */
+static VALUE charset_name2id_func(cb_arg_t *arg)
+{
+    int csid;
+    sb2 ind = 0; /* null indicator */
+    OCIBind *bind1 = NULL;
+    OCIBind *bind2 = NULL;
+    sword rv;
+    const char *sql = "BEGIN :csid := nls_charset_id(:name); END;";
+
+    rv = OCIHandleAlloc(oci8_envhp, (dvoid*)&arg->stmtp, OCI_HTYPE_STMT, 0, NULL);
+    if (rv != OCI_SUCCESS) {
+        oci8_env_raise(oci8_envhp, rv);
+    }
+    oci_lc(OCIStmtPrepare(arg->stmtp, oci8_errhp, (text*)sql, strlen(sql), OCI_NTV_SYNTAX, OCI_DEFAULT));
+    oci_lc(OCIBindByPos(arg->stmtp, &bind1, oci8_errhp, 1, (dvoid*)&csid, sizeof(int), SQLT_INT, &ind, NULL, 0, 0, 0, OCI_DEFAULT));
+    oci_lc(OCIBindByPos(arg->stmtp, &bind2, oci8_errhp, 2, RSTRING_PTR(arg->u.name), RSTRING_LEN(arg->u.name), SQLT_CHR, NULL, 0, 0, 0, 0, OCI_DEFAULT));
+    oci_lc(OCIStmtExecute_nb(arg->svcctx, arg->svcctx->base.hp.svc, arg->stmtp, oci8_errhp, 1, 0, NULL, NULL, OCI_DEFAULT));
+    return ind ? Qnil : INT2FIX(csid);
+}
+
+#endif /* HAVE_TYPE_RB_ENCODING */
+
+void Init_oci8_encoding(VALUE cOCI8)
+{
+    csid2name = rb_hash_new();
+    rb_global_variable(&csid2name);
+
+#ifdef HAVE_TYPE_RB_ENCODING
+    id_upcase = rb_intern("upcase");
+    csname2id = rb_hash_new();
+    rb_global_variable(&csname2id);
+#endif /* HAVE_TYPE_RB_ENCODING */
+
+#if 0
+    rb_define_method(cOCI8, "charset_name2id", oci8_charset_name2id, 1);
+    rb_define_method(cOCI8, "charset_id2name", oci8_charset_id2name, 1);
+#endif
+}

Modified: trunk/ruby-oci8/ext/oci8/extconf.rb
===================================================================
--- trunk/ruby-oci8/ext/oci8/extconf.rb	2008-03-29 08:37:20 UTC (rev 256)
+++ trunk/ruby-oci8/ext/oci8/extconf.rb	2008-03-29 13:06:30 UTC (rev 257)
@@ -73,7 +73,7 @@
          "stmt.o", "bind.o", "metadata.o", "attr.o",
          "lob.o", "oradate.o",
          "ocinumber.o", "ocidatetime.o", "object.o", "apiwrap.o",
-         "xmldb.o"]
+         "encoding.o", "xmldb.o"]
 
 # Checking gcc or not
 if oraconf.cc_is_gcc

Modified: trunk/ruby-oci8/ext/oci8/metadata.c
===================================================================
--- trunk/ruby-oci8/ext/oci8/metadata.c	2008-03-29 08:37:20 UTC (rev 256)
+++ trunk/ruby-oci8/ext/oci8/metadata.c	2008-03-29 13:06:30 UTC (rev 257)
@@ -239,15 +239,9 @@
 
 static VALUE metadata_get_charset_name(VALUE self, VALUE charset_id)
 {
-    char buf[OCI_NLS_MAXBUFSZ];
-    sword rv;
+    oci8_metadata_t *md = DATA_PTR(self);
 
-    Check_Type(charset_id, T_FIXNUM);
-    rv = OCINlsCharSetIdToName(oci8_envhp, TO_ORATEXT(buf), sizeof(buf), FIX2INT(charset_id));
-    if (rv != OCI_SUCCESS) {
-        return Qnil;
-    }
-    return rb_str_new2(buf);
+    return oci8_charset_id2name(md->svc, charset_id);
 }
 
 static VALUE metadata_get_con(VALUE self)

Modified: trunk/ruby-oci8/ext/oci8/oci8.h
===================================================================
--- trunk/ruby-oci8/ext/oci8/oci8.h	2008-03-29 08:37:20 UTC (rev 256)
+++ trunk/ruby-oci8/ext/oci8/oci8.h	2008-03-29 13:06:30 UTC (rev 257)
@@ -367,6 +367,10 @@
 VALUE oci8_get_string_attr(oci8_base_t *base, ub4 attrtype);
 VALUE oci8_get_rowid_attr(oci8_base_t *base, ub4 attrtype);
 
+/* encoding.c */
+void Init_oci8_encoding(VALUE cOCI8);
+VALUE oci8_charset_id2name(VALUE svc, VALUE charset_id);
+
 #include "apiwrap.h"
 
 #endif

Modified: trunk/ruby-oci8/ext/oci8/oci8lib.c
===================================================================
--- trunk/ruby-oci8/ext/oci8/oci8lib.c	2008-03-29 08:37:20 UTC (rev 256)
+++ trunk/ruby-oci8/ext/oci8/oci8lib.c	2008-03-29 13:06:30 UTC (rev 257)
@@ -142,6 +142,9 @@
     Init_oci8_bind(cOCI8BindTypeBase);
     Init_oci8_stmt(cOCI8);
 
+    /* Encoding */
+    Init_oci8_encoding(cOCI8);
+
     /* register allocators */
     Init_oci8_metadata(cOCI8);
     Init_oci8_lob(cOCI8);




More information about the ruby-oci8-commit mailing list