SQLite

Check-in [c2fe746ea7]
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
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: c2fe746ea782f84e850aaf3af7f5536b027a19a1
User & Date: drh 2007-03-17 13:27:55.000
Context
2007-03-17
17:52
Added TRIM, LTRIM, and RTRIM functions. (CVS 3698) (check-in: 6fe13eeade 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: c2fe746ea7 user: drh tags: trunk)
10:28
Add crash2.test, for robustness testing with variable disk block size. (CVS 3696) (check-in: b0f8203dbb user: danielk1977 tags: trunk)
Changes
Unified Diff Show Whitespace Changes Patch
Changes to src/func.c.
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
** This file contains the C functions that implement various SQL
** functions of SQLite.  
**
** There is only one exported symbol in this file - the function
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope.
**
** $Id: func.c,v 1.136 2007/01/29 17:58:28 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
/* #include <math.h> */
#include <stdlib.h>
#include <assert.h>
#include "vdbeInt.h"







|







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
** This file contains the C functions that implement various SQL
** functions of SQLite.  
**
** There is only one exported symbol in this file - the function
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope.
**
** $Id: func.c,v 1.137 2007/03/17 13:27:55 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
/* #include <math.h> */
#include <stdlib.h>
#include <assert.h>
#include "vdbeInt.h"
664
665
666
667
668
669
670



























































671
672
673
674
675
676
677
    unsigned char c = *pBlob;
    *(z++) = hexdigits[(c>>4)&0xf];
    *(z++) = hexdigits[c&0xf];
  }
  *z = 0;
  sqlite3_result_text(context, zHex, n*2, sqlite3_free);
}




























































#ifdef SQLITE_SOUNDEX
/*
** Compute the soundex encoding of a word.
*/
static void soundexFunc(
  sqlite3_context *context,







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
    unsigned char c = *pBlob;
    *(z++) = hexdigits[(c>>4)&0xf];
    *(z++) = hexdigits[c&0xf];
  }
  *z = 0;
  sqlite3_result_text(context, zHex, n*2, sqlite3_free);
}

/*
** The replace() function.  Three arguments are all strings: call
** them A, B, and C. The result is also a string which is derived
** from A by replacing every occurance of B with C.  The match
** must be exact.  Collating sequences are not used.
*/
static void replaceFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  const unsigned char *zStr;        /* The input string A */
  const unsigned char *zPattern;    /* The pattern string B */
  const unsigned char *zRep;        /* The replacement string C */
  unsigned char *zOut;              /* The output */
  int nStr;                /* Size of zStr */
  int nPattern;            /* Size of zPattern */
  int nRep;                /* Size of zRep */
  int nOut;                /* Maximum size of zOut */
  int loopLimit;           /* Last zStr[] that might match zPattern[] */
  int i, j;                /* Loop counters */

  assert( argc==3 );
  if( sqlite3_value_type(argv[0])==SQLITE_NULL ||
      sqlite3_value_type(argv[1])==SQLITE_NULL ||
      sqlite3_value_type(argv[2])==SQLITE_NULL ){
    return;
  }
  nStr = sqlite3_value_bytes(argv[0]);
  zStr = sqlite3_value_text(argv[0]);
  nPattern = sqlite3_value_bytes(argv[1]);
  zPattern = sqlite3_value_text(argv[1]);
  nRep = sqlite3_value_bytes(argv[2]);
  zRep = sqlite3_value_text(argv[2]);
  if( nPattern>=nRep ){
    nOut = nStr;
  }else{
    nOut = (nStr/nPattern + 1)*nRep;
  }
  zOut = sqlite3_malloc(nOut+1);
  if( zOut==0 ) return;
  loopLimit = nStr - nPattern;  
  for(i=j=0; i<=loopLimit; i++){
    if( zStr[i]!=zPattern[0] || memcmp(&zStr[i], zPattern, nPattern) ){
      zOut[j++] = zStr[i];
    }else{
      memcpy(&zOut[j], zRep, nRep);
      j += nRep;
      i += nPattern-1;
    }
  }
  memcpy(&zOut[j], &zStr[i], nStr-i);
  j += nStr - i;
  assert( j<=nOut );
  zOut[j] = 0;
  sqlite3_result_text(context, (char*)zOut, j, sqlite3_free);
}


#ifdef SQLITE_SOUNDEX
/*
** Compute the soundex encoding of a word.
*/
static void soundexFunc(
  sqlite3_context *context,
1079
1080
1081
1082
1083
1084
1085

1086
1087
1088
1089
1090
1091
1092
    { "randomblob",         1, 0, SQLITE_UTF8,    0, randomBlob },
    { "nullif",             2, 0, SQLITE_UTF8,    1, nullifFunc },
    { "sqlite_version",     0, 0, SQLITE_UTF8,    0, versionFunc},
    { "quote",              1, 0, SQLITE_UTF8,    0, quoteFunc  },
    { "last_insert_rowid",  0, 1, SQLITE_UTF8,    0, last_insert_rowid },
    { "changes",            0, 1, SQLITE_UTF8,    0, changes    },
    { "total_changes",      0, 1, SQLITE_UTF8,    0, total_changes },

#ifdef SQLITE_SOUNDEX
    { "soundex",            1, 0, SQLITE_UTF8, 0, soundexFunc},
#endif
#ifndef SQLITE_OMIT_LOAD_EXTENSION
    { "load_extension",     1, 1, SQLITE_UTF8,    0, loadExt },
    { "load_extension",     2, 1, SQLITE_UTF8,    0, loadExt },
#endif







>







1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
    { "randomblob",         1, 0, SQLITE_UTF8,    0, randomBlob },
    { "nullif",             2, 0, SQLITE_UTF8,    1, nullifFunc },
    { "sqlite_version",     0, 0, SQLITE_UTF8,    0, versionFunc},
    { "quote",              1, 0, SQLITE_UTF8,    0, quoteFunc  },
    { "last_insert_rowid",  0, 1, SQLITE_UTF8,    0, last_insert_rowid },
    { "changes",            0, 1, SQLITE_UTF8,    0, changes    },
    { "total_changes",      0, 1, SQLITE_UTF8,    0, total_changes },
    { "replace",            3, 0, SQLITE_UTF8,    0, replaceFunc       },
#ifdef SQLITE_SOUNDEX
    { "soundex",            1, 0, SQLITE_UTF8, 0, soundexFunc},
#endif
#ifndef SQLITE_OMIT_LOAD_EXTENSION
    { "load_extension",     1, 1, SQLITE_UTF8,    0, loadExt },
    { "load_extension",     2, 1, SQLITE_UTF8,    0, loadExt },
#endif
Changes to test/func.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2001 September 15
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing built-in functions.
#
# $Id: func.test,v 1.57 2007/01/29 17:58:28 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Create a table to work with.
#
do_test func-0.0 {













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2001 September 15
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing built-in functions.
#
# $Id: func.test,v 1.58 2007/03/17 13:27:56 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Create a table to work with.
#
do_test func-0.0 {
724
725
726
727
728
729
730
731













































732
  } {
    incr i
    do_test func-20.$i {
      execsql {SELECT soundex($name)}
    } $sdx
  }
}














































finish_test








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
  } {
    incr i
    do_test func-20.$i {
      execsql {SELECT soundex($name)}
    } $sdx
  }
}

# Tests of the REPLACE function.
#
do_test func-21.1 {
  catchsql {
    SELECT replace(1,2);
  }
} {1 {wrong number of arguments to function replace()}}
do_test func-21.2 {
  catchsql {
    SELECT replace(1,2,3,4);
  }
} {1 {wrong number of arguments to function replace()}}
do_test func-21.3 {
  execsql {
    SELECT typeof(replace("This is the main test string", NULL, "ALT"));
  }
} {null}
do_test func-21.4 {
  execsql {
    SELECT typeof(replace(NULL, "main", "ALT"));
  }
} {null}
do_test func-21.5 {
  execsql {
    SELECT typeof(replace("This is the main test string", "main", NULL));
  }
} {null}
do_test func-21.6 {
  execsql {
    SELECT replace("This is the main test string", "main", "ALT");
  }
} {{This is the ALT test string}}
do_test func-21.7 {
  execsql {
    SELECT replace("This is the main test string", "main", "larger-main");
  }
} {{This is the larger-main test string}}
do_test func-21.8 {
  execsql {
    SELECT replace("aaaaaaa", "a", "0123456789");
  }
} {0123456789012345678901234567890123456789012345678901234567890123456789}



finish_test