Author: timbo
Date: Tue Nov 24 05:07:10 2009
New Revision: 13591

Modified:
   dbi/trunk/Changes
   dbi/trunk/DBI.pm
   dbi/trunk/DBI.xs
   dbi/trunk/DBIXS.h
   dbi/trunk/dbixs_rev.h

Log:
Added DBI::sql_type_cast() and corresponding internal sql_type_cast_svpv()
Added DBIstcf_DISCARD_STRING and DBIstcf_STRICT constants.
Bumped DBISTATE_VERSION from 94 to 95.
XXX Needs tests.


Modified: dbi/trunk/Changes
==============================================================================
--- dbi/trunk/Changes   (original)
+++ dbi/trunk/Changes   Tue Nov 24 05:07:10 2009
@@ -8,13 +8,12 @@
 
 =head2 Changes in DBI 1.611 (svn rXXX)
 
-XXX needs to be redone to convert ReadOnly to an internal flag:
-
-  Fixes DBI->trace(0, *STDERR); (H.Merijn Brand)
+  Fixed DBI->trace(0, *STDERR); (H.Merijn Brand)
     which tried to open a file named "*main::STDERR" in perl-5.10.x
 
   Bumped required perl version to 5.8.1 (as announced in DBI 1.607)
 
+XXX needs to be redone to convert ReadOnly to an internal flag:
   Changed "Issuing rollback() due to DESTROY without explicit disconnect"
     warning to not be issued if ReadOnly set for that dbh.
   Updated dbipport.h to Devel::PPPort 3.19 (H.Merijn Brand)
@@ -24,7 +23,16 @@
   Added ChildCallbacks => { ... } to Callbacks as a way to
     specify Callbacks for child handles.
     With tests and docs thanks to David E. Wheeler.
-XXX awaiting docs
+XXX awaiting docs for ChildCallbacks from David.
+
+  Added DBI::sql_type_cast($value, $type, $flags) to cast a string value
+    to an SQL type. e.g. SQL_INTEGER effectively does $value += 0;
+    Has other options plus an internal interface for drivers.
+
+  Added specification of type casting behaviour for bind_column()
+    based on DBI::sql_type_cast() and two new bind_column attributes
+    StrictlyTyped and DiscardString. Thanks to Martin Evans.
+XXX awaiting docs for sql_type_cast & bind_column from Martin Evans.
 
 =head2 Changes in DBI 1.609 (svn r12816) 8th June 2009
 

Modified: dbi/trunk/DBI.pm
==============================================================================
--- dbi/trunk/DBI.pm    (original)
+++ dbi/trunk/DBI.pm    Tue Nov 24 05:07:10 2009
@@ -223,6 +223,8 @@
        SQL_INTERVAL_HOUR_TO_MINUTE
        SQL_INTERVAL_HOUR_TO_SECOND
        SQL_INTERVAL_MINUTE_TO_SECOND
+       DBIstcf_DISCARD_STRING
+       DBIstcf_STRICT
    ) ],
    sql_cursor_types => [ qw(
         SQL_CURSOR_FORWARD_ONLY
@@ -233,7 +235,7 @@
    ) ], # for ODBC cursor types
    utils     => [ qw(
        neat neat_list $neat_maxlen dump_results looks_like_number
-       data_string_diff data_string_desc data_diff
+       data_string_diff data_string_desc data_diff sql_type_cast
    ) ],
    profile   => [ qw(
        dbi_profile dbi_profile_merge dbi_profile_merge_nodes dbi_time

Modified: dbi/trunk/DBI.xs
==============================================================================
--- dbi/trunk/DBI.xs    (original)
+++ dbi/trunk/DBI.xs    Tue Nov 24 05:07:10 2009
@@ -78,6 +78,7 @@
 static int      set_err_char _((SV *h, imp_xxh_t *imp_xxh, const char *err_c, 
IV err_i, const char *errstr, const char *state, const char *method));
 static int      set_err_sv   _((SV *h, imp_xxh_t *imp_xxh, SV *err, SV 
*errstr, SV *state, SV *method));
 static int      quote_type _((int sql_type, int p, int s, int *base_type, void 
*v));
+static int      sql_type_cast_svpv _((pTHX_ SV *sv, int sql_type, U32 flags, 
void *v));
 static I32      dbi_hash _((const char *string, long i));
 static void     dbih_dumphandle _((pTHX_ SV *h, const char *msg, int level));
 static int      dbih_dumpcom _((pTHX_ imp_xxh_t *imp_xxh, const char *msg, int 
level));
@@ -434,11 +435,12 @@
     DBIS->get_fbav    = dbih_get_fbav;
     DBIS->make_fdsv   = dbih_make_fdsv;
     DBIS->neat_svpv   = neatsvpv;
-    DBIS->bind_as_num = quote_type;
+    DBIS->bind_as_num = quote_type; /* XXX deprecated */
     DBIS->hash        = dbi_hash;
     DBIS->set_err_sv  = set_err_sv;
     DBIS->set_err_char= set_err_char;
     DBIS->bind_col    = dbih_sth_bind_col;
+    DBIS->sql_type_cast_svpv = sql_type_cast_svpv;
 
 
     /* Remember the last handle used. BEWARE! Sneaky stuff here!        */
@@ -1696,6 +1698,8 @@
     (void)s;
     (void)t;
     (void)v;
+    /* looks like it's never been used, and doesn't make much sense anyway */
+    warn("Use of DBI internal bind_as_num/quote_type function is deprecated");
     switch(sql_type) {
     case SQL_INTEGER:
     case SQL_SMALLINT:
@@ -1714,6 +1718,107 @@
 }
 
 
+/* Convert a simple string representation of a value into a more specific
+ * perl type based on an sql_type value.
+ * The semantics of SQL standard TYPE values are interpreted _very_ loosely
+ * on the basis of "be liberal in what you accept and let's throw in some
+ * extra semantics while we're here" :)
+ * Returns:
+ *  -2: sql_type isn't handled, value unchanged
+ *  -1: sv is undef, value unchanged
+ *   0: sv couldn't be cast cleanly and DBIstcf_STRICT was used
+ *   1: sv couldn't be cast cleanly and DBIstcf_STRICT was not used
+ *   2: sv was cast ok
+ */
+
+int
+sql_type_cast_svpv(pTHX_ SV *sv, int sql_type, U32 flags, void *v)
+{
+    int cast_ok = 0;
+    int grok_flags;
+    UV uv;
+
+    /* do nothing for undef (NULL) or non-string values */
+    if (!sv || !SvOK(sv))
+        return -1;
+
+    switch(sql_type) {
+
+    default:
+        return -2;   /* not a recognised SQL TYPE, value unchanged */
+
+    case SQL_INTEGER:
+        /* sv_2iv is liberal, may return SvIV, SvUV, or SvNV */
+        sv_2iv(sv);
+        /* SvNOK will be set if value is out of range for IV/UV.
+         * SvIOK should be set but won't if sv is not numeric (in which
+         * case perl would have warn'd already if -w or warnings are in effect)
+         */
+        cast_ok = (SvIOK(sv) && !SvNOK(sv));
+        break;
+
+    case SQL_DOUBLE:
+        sv_2nv(sv);
+        /* SvNOK should be set but won't if sv is not numeric (in which
+         * case perl would have warn'd already if -w or warnings are in effect)
+         */
+        cast_ok = SvNOK(sv);
+        break;
+
+    /* caller would like IV else UV else NV */
+    /* else no error and sv is untouched */
+    case SQL_NUMERIC:
+        /* based on the code in perl's toke.c */
+        uv = 0;
+        grok_flags = grok_number(SvPVX(sv), SvCUR(sv), &uv);
+        cast_ok = 1;
+        if (flags == IS_NUMBER_IN_UV) { /* +ve int */
+            if (uv <= IV_MAX)   /* prefer IV over UV */
+                 sv_2iv(sv);
+            else sv_2uv(sv);
+        }
+        else if (flags == (IS_NUMBER_IN_UV | IS_NUMBER_NEG)
+            && uv <= IV_MAX
+        ) {
+            sv_2iv(sv);
+        }
+        else if (flags) { /* is numeric */
+            sv_2nv(sv);
+        }
+        else if (flags & DBIstcf_STRICT)
+            cast_ok = 0;
+        break;
+
+#if 0 /* XXX future possibilities */
+    case SQL_BIGINT:    /* use Math::BigInt if too large for IV/UV */
+#endif
+    }
+
+    if (cast_ok) {
+
+        if (flags & DBIstcf_DISCARD_STRING
+        && SvNIOK(sv)  /* we set a numeric value */
+        && SvPVX(sv)   /* we have a buffer to discard */
+        ) {
+            SvOOK_off(sv);
+            if (SvLEN(sv)) {
+                Safefree(SvPVX(sv));
+                SvLEN(sv) = 0;
+            }
+            SvPVX(sv) = NULL;
+            SvPOK_off(sv);
+        }
+    }
+
+    if (cast_ok)
+        return 2;
+    else if (flags & DBIstcf_STRICT)
+        return 0;
+    else return 1;
+}
+
+
+
 /* --- Generic Handle Attributes (for all handle types) ---     */
 
 static int
@@ -4007,7 +4112,7 @@
         SQL_ALL_TYPES                    = SQL_ALL_TYPES
         SQL_ARRAY                        = SQL_ARRAY
         SQL_ARRAY_LOCATOR                = SQL_ARRAY_LOCATOR
-    SQL_BIGINT                       = SQL_BIGINT
+        SQL_BIGINT                       = SQL_BIGINT
         SQL_BINARY                       = SQL_BINARY
         SQL_BIT                          = SQL_BIT
         SQL_BLOB                         = SQL_BLOB
@@ -4081,6 +4186,8 @@
         DBIpp_st_qq     = DBIpp_st_qq
         DBIpp_st_bs     = DBIpp_st_bs
         DBIpp_st_XX     = DBIpp_st_XX
+        DBIstcf_DISCARD_STRING  = DBIstcf_DISCARD_STRING
+        DBIstcf_STRICT          = DBIstcf_STRICT
     CODE:
     RETVAL = ix;
     OUTPUT:
@@ -4438,7 +4545,15 @@
         RETVAL
 
 
-
+int
+sql_type_cast(sv, sql_type, flags=0)
+    SV *        sv
+    int         sql_type
+    U32         flags
+    CODE:
+    RETVAL = sql_type_cast_svpv(aTHX_ sv, sql_type, flags, 0);
+    OUTPUT:
+        RETVAL
 
 
 

Modified: dbi/trunk/DBIXS.h
==============================================================================
--- dbi/trunk/DBIXS.h   (original)
+++ dbi/trunk/DBIXS.h   Tue Nov 24 05:07:10 2009
@@ -342,6 +342,10 @@
 #define neatsvpv(sv,len)        (DBIS->neat_svpv(sv,len))
 #endif
 
+/* --- For sql_type_cast_svpv() --- */
+
+#define DBIstcf_DISCARD_STRING  0x0001
+#define DBIstcf_STRICT          0x0002
 
 /* --- Implementors Private Data Support --- */
 
@@ -392,7 +396,7 @@
 
 struct dbistate_st {
 
-#define DBISTATE_VERSION  94    /* Must change whenever dbistate_t does */
+#define DBISTATE_VERSION  95    /* Must change whenever dbistate_t does */
 
     /* this must be the first member in structure                       */
     void (*check_version) _((const char *name,
@@ -417,7 +421,7 @@
     SV        * (*get_attr_k)   _((SV *h, SV *keysv, int dbikey));
     AV        * (*get_fbav)     _((imp_sth_t *imp_sth));
     SV        * (*make_fdsv)    _((SV *sth, const char *imp_class, STRLEN 
imp_size, const char *col_name));
-    int         (*bind_as_num)  _((int sql_type, int p, int s, int *t, void 
*v));
+    int         (*bind_as_num)  _((int sql_type, int p, int s, int *t, void 
*v)); /* XXX deprecated */
     I32         (*hash)         _((const char *string, long i));
     SV        * (*preparse)     _((SV *sth, char *statement, IV ps_return, IV 
ps_accept, void *foo));
 
@@ -430,11 +434,13 @@
     int         (*set_err_char) _((SV *h, imp_xxh_t *imp_xxh, const char *err, 
IV err_i, const char *errstr, const char *state, const char *method));
     int         (*bind_col)     _((SV *sth, SV *col, SV *ref, SV *attribs));
 
-    IO *logfp_ref;      /* DAA keep ptr to filehandle for refcounting */
+    IO *logfp_ref;              /* keep ptr to filehandle for refcounting */
+
+    int         (*sql_type_cast_svpv) _((pTHX_ SV *sv, int sql_type, U32 
flags, void *v));
 
     /* WARNING: Only add new structure members here, and reduce pad2 to keep */
     /* the memory footprint exactly the same */
-    void *pad2[4];
+    void *pad2[3];
 };
 
 /* macros for backwards compatibility */

Modified: dbi/trunk/dbixs_rev.h
==============================================================================
--- dbi/trunk/dbixs_rev.h       (original)
+++ dbi/trunk/dbixs_rev.h       Tue Nov 24 05:07:10 2009
@@ -1,4 +1,3 @@
-/* Mon Nov  2 22:44:58 2009 */
-/* Mixed revision working copy (13455M:13465) */
+/* Tue Nov 24 12:53:00 2009 */
 /* Code modified since last checkin */
-#define DBIXS_REVISION 13455
+#define DBIXS_REVISION 13590

Reply via email to