/ Check-in [c2fe746e]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:First cut at an implementation of the REPLACE() function. We might yet make this a compile-time option or move it into a separate source file. (CVS 3697)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: c2fe746ea782f84e850aaf3af7f5536b027a19a1
User & Date: drh 2007-03-17 13:27:55
Context
2007-03-17
17:52
Added TRIM, LTRIM, and RTRIM functions. (CVS 3698) check-in: 6fe13eea user: drh tags: trunk
13:27
First cut at an implementation of the REPLACE() function. We might yet make this a compile-time option or move it into a separate source file. (CVS 3697) check-in: c2fe746e user: drh tags: trunk
10:28
Add crash2.test, for robustness testing with variable disk block size. (CVS 3696) check-in: b0f8203d user: danielk1977 tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/func.c.

    12     12   ** This file contains the C functions that implement various SQL
    13     13   ** functions of SQLite.  
    14     14   **
    15     15   ** There is only one exported symbol in this file - the function
    16     16   ** sqliteRegisterBuildinFunctions() found at the bottom of the file.
    17     17   ** All other code has file scope.
    18     18   **
    19         -** $Id: func.c,v 1.136 2007/01/29 17:58:28 drh Exp $
           19  +** $Id: func.c,v 1.137 2007/03/17 13:27:55 drh Exp $
    20     20   */
    21     21   #include "sqliteInt.h"
    22     22   #include <ctype.h>
    23     23   /* #include <math.h> */
    24     24   #include <stdlib.h>
    25     25   #include <assert.h>
    26     26   #include "vdbeInt.h"
................................................................................
   664    664       unsigned char c = *pBlob;
   665    665       *(z++) = hexdigits[(c>>4)&0xf];
   666    666       *(z++) = hexdigits[c&0xf];
   667    667     }
   668    668     *z = 0;
   669    669     sqlite3_result_text(context, zHex, n*2, sqlite3_free);
   670    670   }
          671  +
          672  +/*
          673  +** The replace() function.  Three arguments are all strings: call
          674  +** them A, B, and C. The result is also a string which is derived
          675  +** from A by replacing every occurance of B with C.  The match
          676  +** must be exact.  Collating sequences are not used.
          677  +*/
          678  +static void replaceFunc(
          679  +  sqlite3_context *context,
          680  +  int argc,
          681  +  sqlite3_value **argv
          682  +){
          683  +  const unsigned char *zStr;        /* The input string A */
          684  +  const unsigned char *zPattern;    /* The pattern string B */
          685  +  const unsigned char *zRep;        /* The replacement string C */
          686  +  unsigned char *zOut;              /* The output */
          687  +  int nStr;                /* Size of zStr */
          688  +  int nPattern;            /* Size of zPattern */
          689  +  int nRep;                /* Size of zRep */
          690  +  int nOut;                /* Maximum size of zOut */
          691  +  int loopLimit;           /* Last zStr[] that might match zPattern[] */
          692  +  int i, j;                /* Loop counters */
          693  +
          694  +  assert( argc==3 );
          695  +  if( sqlite3_value_type(argv[0])==SQLITE_NULL ||
          696  +      sqlite3_value_type(argv[1])==SQLITE_NULL ||
          697  +      sqlite3_value_type(argv[2])==SQLITE_NULL ){
          698  +    return;
          699  +  }
          700  +  nStr = sqlite3_value_bytes(argv[0]);
          701  +  zStr = sqlite3_value_text(argv[0]);
          702  +  nPattern = sqlite3_value_bytes(argv[1]);
          703  +  zPattern = sqlite3_value_text(argv[1]);
          704  +  nRep = sqlite3_value_bytes(argv[2]);
          705  +  zRep = sqlite3_value_text(argv[2]);
          706  +  if( nPattern>=nRep ){
          707  +    nOut = nStr;
          708  +  }else{
          709  +    nOut = (nStr/nPattern + 1)*nRep;
          710  +  }
          711  +  zOut = sqlite3_malloc(nOut+1);
          712  +  if( zOut==0 ) return;
          713  +  loopLimit = nStr - nPattern;  
          714  +  for(i=j=0; i<=loopLimit; i++){
          715  +    if( zStr[i]!=zPattern[0] || memcmp(&zStr[i], zPattern, nPattern) ){
          716  +      zOut[j++] = zStr[i];
          717  +    }else{
          718  +      memcpy(&zOut[j], zRep, nRep);
          719  +      j += nRep;
          720  +      i += nPattern-1;
          721  +    }
          722  +  }
          723  +  memcpy(&zOut[j], &zStr[i], nStr-i);
          724  +  j += nStr - i;
          725  +  assert( j<=nOut );
          726  +  zOut[j] = 0;
          727  +  sqlite3_result_text(context, (char*)zOut, j, sqlite3_free);
          728  +}
          729  +
   671    730   
   672    731   #ifdef SQLITE_SOUNDEX
   673    732   /*
   674    733   ** Compute the soundex encoding of a word.
   675    734   */
   676    735   static void soundexFunc(
   677    736     sqlite3_context *context,
................................................................................
  1077   1136       { "ifnull",             2, 0, SQLITE_UTF8,    1, ifnullFunc },
  1078   1137       { "random",            -1, 0, SQLITE_UTF8,    0, randomFunc },
  1079   1138       { "randomblob",         1, 0, SQLITE_UTF8,    0, randomBlob },
  1080   1139       { "nullif",             2, 0, SQLITE_UTF8,    1, nullifFunc },
  1081   1140       { "sqlite_version",     0, 0, SQLITE_UTF8,    0, versionFunc},
  1082   1141       { "quote",              1, 0, SQLITE_UTF8,    0, quoteFunc  },
  1083   1142       { "last_insert_rowid",  0, 1, SQLITE_UTF8,    0, last_insert_rowid },
  1084         -    { "changes",            0, 1, SQLITE_UTF8,    0, changes    },
  1085         -    { "total_changes",      0, 1, SQLITE_UTF8,    0, total_changes },
         1143  +    { "changes",            0, 1, SQLITE_UTF8,    0, changes           },
         1144  +    { "total_changes",      0, 1, SQLITE_UTF8,    0, total_changes     },
         1145  +    { "replace",            3, 0, SQLITE_UTF8,    0, replaceFunc       },
  1086   1146   #ifdef SQLITE_SOUNDEX
  1087   1147       { "soundex",            1, 0, SQLITE_UTF8, 0, soundexFunc},
  1088   1148   #endif
  1089   1149   #ifndef SQLITE_OMIT_LOAD_EXTENSION
  1090   1150       { "load_extension",     1, 1, SQLITE_UTF8,    0, loadExt },
  1091   1151       { "load_extension",     2, 1, SQLITE_UTF8,    0, loadExt },
  1092   1152   #endif

Changes to test/func.test.

     7      7   #    May you find forgiveness for yourself and forgive others.
     8      8   #    May you share freely, never taking more than you give.
     9      9   #
    10     10   #***********************************************************************
    11     11   # This file implements regression tests for SQLite library.  The
    12     12   # focus of this file is testing built-in functions.
    13     13   #
    14         -# $Id: func.test,v 1.57 2007/01/29 17:58:28 drh Exp $
           14  +# $Id: func.test,v 1.58 2007/03/17 13:27:56 drh Exp $
    15     15   
    16     16   set testdir [file dirname $argv0]
    17     17   source $testdir/tester.tcl
    18     18   
    19     19   # Create a table to work with.
    20     20   #
    21     21   do_test func-0.0 {
................................................................................
   724    724     } {
   725    725       incr i
   726    726       do_test func-20.$i {
   727    727         execsql {SELECT soundex($name)}
   728    728       } $sdx
   729    729     }
   730    730   }
          731  +
          732  +# Tests of the REPLACE function.
          733  +#
          734  +do_test func-21.1 {
          735  +  catchsql {
          736  +    SELECT replace(1,2);
          737  +  }
          738  +} {1 {wrong number of arguments to function replace()}}
          739  +do_test func-21.2 {
          740  +  catchsql {
          741  +    SELECT replace(1,2,3,4);
          742  +  }
          743  +} {1 {wrong number of arguments to function replace()}}
          744  +do_test func-21.3 {
          745  +  execsql {
          746  +    SELECT typeof(replace("This is the main test string", NULL, "ALT"));
          747  +  }
          748  +} {null}
          749  +do_test func-21.4 {
          750  +  execsql {
          751  +    SELECT typeof(replace(NULL, "main", "ALT"));
          752  +  }
          753  +} {null}
          754  +do_test func-21.5 {
          755  +  execsql {
          756  +    SELECT typeof(replace("This is the main test string", "main", NULL));
          757  +  }
          758  +} {null}
          759  +do_test func-21.6 {
          760  +  execsql {
          761  +    SELECT replace("This is the main test string", "main", "ALT");
          762  +  }
          763  +} {{This is the ALT test string}}
          764  +do_test func-21.7 {
          765  +  execsql {
          766  +    SELECT replace("This is the main test string", "main", "larger-main");
          767  +  }
          768  +} {{This is the larger-main test string}}
          769  +do_test func-21.8 {
          770  +  execsql {
          771  +    SELECT replace("aaaaaaa", "a", "0123456789");
          772  +  }
          773  +} {0123456789012345678901234567890123456789012345678901234567890123456789}
          774  +
          775  +
   731    776   
   732    777   finish_test