Author: timbo
Date: Sun Jun  1 14:42:16 2008
New Revision: 11362

Modified:
   dbi/trunk/Changes
   dbi/trunk/DBI.xs
   dbi/trunk/t/18concathash.t

Log:
Fix _concat_hash_sorted/_join_hash_sorted to work with values with embedded nul 
bytes.
Added related tests.
Assorted related minor code tweaks.


Modified: dbi/trunk/Changes
==============================================================================
--- dbi/trunk/Changes   (original)
+++ dbi/trunk/Changes   Sun Jun  1 14:42:16 2008
@@ -57,6 +57,7 @@
 =head2 Changes in DBI 1.605 XXX
 
 Add note about _concat_hash_sorted once integrated
+Use _concat_hash_sorted for *_cached() and ShowErrorStatement
 Add DBI::Gofer::Serialiser::MIME / Base64
 Add DBI::Gofer::Serialiser::JSON
 
@@ -66,15 +67,15 @@
     methods that get embedded into compiled drivers to use the
     inner sth handle when passed a $sth instead of an sql string.
     Drivers will need to be recompiled to pick up this change.
-  Fixed lean in neat() for some kinds of values thanks to Rudolf Lippan.
+  Fixed leak in neat() for some kinds of values thanks to Rudolf Lippan.
 
   Increased timeout on tests to accomodate very slow systems.
   Removed the beeps "\a" from Makefile.PL warnings.
   Removed check for PlRPC-modules from Makefile.PL
-  Added cache miss trace message to DBD::Gofer transport class.
-  Added $drh->dbixs_revision method.
   Clarified docs re ":N" style placeholders.
 
+  Added cache miss trace message to DBD::Gofer transport class.
+  Added $drh->dbixs_revision method.
   Added explicit LICENSE specification (perl) to META.yaml
 
 =head2 Changes in DBI 1.604 (svn rev 10994) 24th March 2008

Modified: dbi/trunk/DBI.xs
==============================================================================
--- dbi/trunk/DBI.xs    (original)
+++ dbi/trunk/DBI.xs    Sun Jun  1 14:42:16 2008
@@ -298,28 +298,24 @@
 
 
 static SV *
-_join_hash_sorted (hash, kv_sep, pair_sep, not_neat, sort)
-    HV *hash;
-    char *kv_sep;
-    char *pair_sep;
-    int not_neat;
-    int sort;
+_join_hash_sorted(HV *hash, char *kv_sep, STRLEN kv_sep_len, char *pair_sep, 
STRLEN pair_sep_len, int not_neat, int sort)
 {
        dTHX;
         I32 hv_len;
-        STRLEN kv_sep_len, pair_sep_len, hv_val_len, total_len = 0;
+        STRLEN total_len = 0;
         char **keys;
         unsigned int i = 0;
-        SV **hash_svp;
         SV *return_sv;
 
-        kv_sep_len = strlen(kv_sep);
-        pair_sep_len = strlen(pair_sep);
-
         keys = _sort_hash_keys(hash, sort, &total_len);
         if (!keys)
             return newSVpv("", 0);
 
+        if (!kv_sep_len)
+            kv_sep_len = strlen(kv_sep);
+        if (!pair_sep_len)
+            pair_sep_len = strlen(pair_sep);
+
         hv_len = hv_iterinit(hash);
         /* total_len += Separators + quotes + term null */
         total_len += kv_sep_len*hv_len + pair_sep_len*hv_len+2*hv_len+1;
@@ -327,22 +323,31 @@
         sv_setpv(return_sv, ""); /* quell undef warnings */
 
         for (i=0; i<hv_len; ++i) {
-            hash_svp = hv_fetch(hash, keys[i], strlen(keys[i]), 0);
-            if (!hash_svp) {
-                 warn("No Hash entry with key: %s", keys[i]);
+            SV **hash_svp = hv_fetch(hash, keys[i], strlen(keys[i]), 0);
+
+            sv_catpv(return_sv, keys[i]); /* XXX keys can't contain nul chars 
*/
+            sv_catpvn(return_sv, kv_sep, kv_sep_len);
+
+            if (!hash_svp) {    /* should never happen */
+                warn("No hash entry with key '%s'", keys[i]);
+                sv_catpvn(return_sv, "???", 3);
                 continue;
             }
 
-            sv_catpvf(return_sv, "%s%s", keys[i], kv_sep);
             if (not_neat) {
-                if (SvOK(*hash_svp))
-                     sv_catpvf(return_sv, "'%s'", SvPV(*hash_svp, hv_val_len));
-                else sv_catpv(return_sv, "undef");
+                if (SvOK(*hash_svp)) {
+                     STRLEN hv_val_len;
+                     char *hv_val = SvPV(*hash_svp, hv_val_len);
+                     sv_catpvn(return_sv, "'", 1);
+                     sv_catpvn(return_sv, hv_val, hv_val_len);
+                     sv_catpvn(return_sv, "'", 1);
+                }
+                else sv_catpvn(return_sv, "undef", 5);
             }
             else     sv_catpv(return_sv, neatsvpv(*hash_svp,0));
 
             if (i < hv_len-1)
-                sv_catpv(return_sv, pair_sep);
+                sv_catpvn(return_sv, pair_sep, pair_sep_len);
         }
 
         Safefree(keys);
@@ -4387,7 +4392,7 @@
 
 
 SV *
-_concat_hash_sorted (hash, kv_sep_sv, pair_sep_sv, 
value_format_sv,sort_type_sv)
+_concat_hash_sorted(hash, kv_sep_sv, pair_sep_sv, value_format_sv, 
sort_type_sv)
     HV *hash
     SV *kv_sep_sv
     SV *pair_sep_sv
@@ -4397,18 +4402,15 @@
     STRLEN kv_sep_len, pair_sep_len;
     char *kv_sep, *pair_sep;
     int not_neat, sort;
-
     CODE:
         kv_sep = SvPV(kv_sep_sv, kv_sep_len);
         pair_sep = SvPV(pair_sep_sv, pair_sep_len);
-
-        if (SvGMAGICAL(value_format_sv))
+        if (SvGMAGICAL(value_format_sv)) /* SvTRUE doesn't handle magic */
             mg_get(value_format_sv);
         not_neat = SvTRUE(value_format_sv);
-
         sort = (SvOK(sort_type_sv)) ? SvIV(sort_type_sv) : -1;
 
-        RETVAL = _join_hash_sorted(hash,kv_sep, pair_sep, not_neat, sort);
+        RETVAL = _join_hash_sorted(hash, kv_sep, kv_sep_len, pair_sep, 
pair_sep_len, not_neat, sort);
 
     OUTPUT:
         RETVAL

Modified: dbi/trunk/t/18concathash.t
==============================================================================
--- dbi/trunk/t/18concathash.t  (original)
+++ dbi/trunk/t/18concathash.t  Sun Jun  1 14:42:16 2008
@@ -15,13 +15,23 @@
 BEGIN { use_ok('DBI') };
 
 # null and undefs -- segfaults?;
-is (DBI::_concat_hash_sorted({ }, "=", ":", 0, undef), "");
-eval {DBI::_concat_hash_sorted(undef, "=", ":", 0, undef), undef};
-like ($@ || "", qr/hash is not a hash reference/); #XXX check this
-is (DBI::_concat_hash_sorted({ }, undef, ":", 0, undef), "");
-
-is (DBI::_concat_hash_sorted({ }, "=", undef, 0, undef), "");
-is (DBI::_concat_hash_sorted({ }, "=", ":", undef, undef),"");
+is (DBI::_concat_hash_sorted({ }, "=",   ":",   0, undef), "");
+eval { DBI::_concat_hash_sorted(undef, "=", ":", 0, undef) };
+like ($@ || "", qr/is not a hash reference/);
+is (DBI::_concat_hash_sorted({ }, undef, ":",   0,     undef), "");
+is (DBI::_concat_hash_sorted({ }, "=",   undef, 0,     undef), "");
+is (DBI::_concat_hash_sorted({ }, "=",   ":",   undef, undef),"");
+
+# simple cases
+is (DBI::_concat_hash_sorted({ 1=>"a", 2=>"b" }, "=", ", ", undef, undef), 
"1='a', 2='b'");
+# nul byte in key sep and pair sep
+# (nul byte in hash not supported)
+is DBI::_concat_hash_sorted({ 1=>"a", 2=>"b" }, "=\000=", ":\000:", undef, 
undef),
+    "1=\000='a':\000:2=\000='b'", 'should work with nul bytes in kv_sep and 
pair_sep';
+is DBI::_concat_hash_sorted({ 1=>"a\000a", 2=>"b" }, "=", ":", 0, undef),
+    "1='a.a':2='b'", 'should work with nul bytes in hash value (neat)';
+is DBI::_concat_hash_sorted({ 1=>"a\000a", 2=>"b" }, "=", ":", 1, undef),
+    "1='a\000a':2='b'", 'should work with nul bytes in hash value (not neat)';
 
 # Simple stress tests
 ok(DBI::_concat_hash_sorted({bob=>'two', fred=>'one' }, "="x12000, ":", 1, 
undef));

Reply via email to