Hey Brian.  I had some time this morning to look at it.  Try whacking this
new concat_replace into your SQLite build in either func.c or sqlite3.c
amalgam.  Also remember to hook it up with a new entry after say,
group_concat, as follows.

    AGGREGATE(group_replace,     3, 0, 0,
groupReplaceStep,groupReplaceFinalize),

[This is a first pass so there could be an edge case with NULL/empty that I
missed... pls test it!  Honestly, the original replace() that I borrowed
from might also be a bit shaky with the NULL/empty edge cases.]

Here's a tester snippet you can play with:

sqlite> WITH T(pattern,replacement) AS (VALUES
('a','This'),('b','is'),('c','a'),('d','test')) SELECT group_replace('a b c
d',pattern,replacement) FROM T;
This is a test

---all C code below this point---

struct StrRepl {
  const unsigned char* zStr;
  u32 nStr;
  u8 replError; /* STRREPL_NOMEM or STRREPL_TOOBIG */
};
typedef struct StrRepl StrRepl;
#define STRREPL_NOMEM   1
#define STRREPL_TOOBIG  2

/*
 ** Aggregate group_replace(A,B,C) result string is derived from A by
replacing
 ** every exact match occurrence of B with C.  A is presumed constant over
the group
 ** while B and C may vary at each step.  Collating sequences are not used.
 */
static void groupReplaceStep(
  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 *zRepl; /* The replacement string C */
  unsigned char *zOut; /* The output */
  int nStr; /* Size of zStr */
  int nPattern; /* Size of zPattern */
  int nRepl; /* Size of zRep */
  i64 nOut; /* Maximum size of zOut */
  int loopLimit; /* Last zStr[] that might match zPattern[] */
  int i, j; /* Loop counters */

  assert(argc == 3);
  UNUSED_PARAMETER(argc);
  zStr = sqlite3_value_text(argv[0]);
  if (zStr == 0) return;
  nStr = sqlite3_value_bytes(argv[0]);
  assert(zStr == sqlite3_value_text(argv[0])); /* No encoding change */
  zPattern = sqlite3_value_text(argv[1]);
  if (zPattern == 0) {
    assert(sqlite3_value_type(argv[1]) == SQLITE_NULL
      || sqlite3_context_db_handle(context)->mallocFailed);

    return;
  }
  if (zPattern[0] == 0) {
    assert(sqlite3_value_type(argv[1]) != SQLITE_NULL);
    sqlite3_result_value(context, argv[0]);
    return;
  }
  nPattern = sqlite3_value_bytes(argv[1]);
  assert(zPattern == sqlite3_value_text(argv[1])); /* No encoding change */
  zRepl = sqlite3_value_text(argv[2]);
  if (zRepl == 0) return;
  nRepl = sqlite3_value_bytes(argv[2]);
  assert(zRepl == sqlite3_value_text(argv[2]));

  StrRepl* pStrRepl = (StrRepl*) sqlite3_aggregate_context(context, sizeof
(StrRepl));
  if (pStrRepl) {
    if (pStrRepl->replError) return;
    if (!pStrRepl->zStr) {
      if (sqlite3_value_type(argv[0]) == SQLITE_NULL
        || sqlite3_value_type(argv[1]) == SQLITE_NULL) return;
      pStrRepl->nStr = sqlite3_value_bytes(argv[0]);
      pStrRepl->zStr = contextMalloc(context,pStrRepl->nStr);

memcpy((void*)pStrRepl->zStr,sqlite3_value_text(argv[0]),pStrRepl->nStr);
/* No encoding change */
    }
    zPattern = sqlite3_value_text(argv[1]);
    nPattern = sqlite3_value_bytes(argv[1]);
    assert(zPattern == sqlite3_value_text(argv[1])); /* No encoding change
*/
    if (0 == pStrRepl->nStr || 0 == nPattern) return;
    zRepl = sqlite3_value_text(argv[2]);
    nRepl = sqlite3_value_bytes(argv[2]);
    if (0 == zRepl) return;
    nOut = pStrRepl->nStr + 1;
    assert(nOut < SQLITE_MAX_LENGTH);
    zOut = contextMalloc(context, (i64) nOut);
    if (0 == zOut) return;
    loopLimit = pStrRepl->nStr - nPattern;
    for (i = j = 0; i <= loopLimit; i++) {
      if (pStrRepl->zStr[i] != zPattern[0] || memcmp(&(pStrRepl->zStr)[i],
zPattern, nPattern)) {
        zOut[j++] = pStrRepl->zStr[i];
      } else {
        u8 *zOld;
        sqlite3 *db = sqlite3_context_db_handle(context);
        nOut += nRepl - nPattern;
        testcase(nOut - 1 == db->aLimit[SQLITE_LIMIT_LENGTH]);
        testcase(nOut - 2 == db->aLimit[SQLITE_LIMIT_LENGTH]);
        if (nOut - 1 > db->aLimit[SQLITE_LIMIT_LENGTH]) {
          pStrRepl->replError = STRREPL_TOOBIG;
          sqlite3_free(zOut);
          return;
        }
        zOld = zOut;
        zOut = sqlite3_realloc64(zOut, (int) nOut);
        if (zOut == 0) {
          pStrRepl->replError = STRREPL_NOMEM;
          sqlite3_free(zOld);
          return;
        }
        memcpy(&zOut[j], zRepl, nRepl);
        j += nRepl;
        i += nPattern - 1;
      }
    }
    assert(j + pStrRepl->nStr - i + 1 == nOut);
    memcpy(&zOut[j], &pStrRepl->zStr[i], pStrRepl->nStr - i);
    j += pStrRepl->nStr - i;
    assert(j <= nOut);
    zOut[j] = 0;
    void* pFree = (void*)pStrRepl->zStr;
    pStrRepl->zStr = zOut;
    pStrRepl->nStr = nOut;
    sqlite3_free(pFree);
  }
}

static void groupReplaceFinalize(sqlite3_context *context) {
  const char **pzVal;
  StrRepl* pStrRepl = sqlite3_aggregate_context(context, 0);
  if (pStrRepl) {
    if (pStrRepl->replError == STRREPL_TOOBIG) {
      sqlite3_result_error_toobig(context);
    } else if (pStrRepl->replError == STRREPL_NOMEM) {
      sqlite3_result_error_nomem(context);
    } else {
      sqlite3_result_text(context, pStrRepl->zStr, -1, sqlite3_free);
    }
  }
}









On Mon, Aug 7, 2017 at 2:02 AM, Brian Clifford <
brian.cliff...@thinksmartbox.com> wrote:

> Thank Simon,
>
> I have looked into using a user defined function however it was very slow.
> I tried to create an expression index unfortunately I was not able as the
> function was seen as non deterministic. (I am using the C# interface and
> its not possible to define a user defined function as Determinstic from C#
> (Feature request!?))
>
> Thanks
> Brian
>
>
>
> --
>
>
> <http://www.thinksmartbox.com>
>
> www.thinksmartbox.com
>
> Facebook <https://www.facebook.com/thinksmartbox>  Twitter
> <https://twitter.com/ThinkSmartbox>  LinkedIn
> <https://www.linkedin.com/company/smartbox-assistive-technology>  YouTube
> <https://www.youtube.com/user/SmartboxAT>
>
> Smartbox Assistive Technology, Ysobel House, Enigma Commercial Centre,
> Sandys
> Road, Malvern, WR14 1JJ
>
> Tel: +44 (0) 1684 578868
> _______________________________________________
> sqlite-users mailing list
> sqlite-users@mailinglists.sqlite.org
> http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
>
_______________________________________________
sqlite-users mailing list
sqlite-users@mailinglists.sqlite.org
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to