diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 3156a95131427b063d5f36cd3d79880b89e5d4e4..55bbd5f5983334d4c04c4c14a055cbc80319c386 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.95 2000/09/12 21:06:53 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.96 2000/09/15 18:45:25 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1755,6 +1755,20 @@ match_special_index_operator(Expr *clause, Oid opclass, Oid relam, pfree(patt); break; + case OID_TEXT_ICLIKE_OP: + case OID_BPCHAR_ICLIKE_OP: + case OID_VARCHAR_ICLIKE_OP: + case OID_NAME_ICLIKE_OP: + /* the right-hand const is type text for all of these */ + patt = DatumGetCString(DirectFunctionCall1(textout, + constvalue)); + isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Like_IC, + &prefix, &rest) != Pattern_Prefix_None; + if (prefix) + pfree(prefix); + pfree(patt); + break; + case OID_TEXT_REGEXEQ_OP: case OID_BPCHAR_REGEXEQ_OP: case OID_VARCHAR_REGEXEQ_OP: @@ -1797,6 +1811,7 @@ match_special_index_operator(Expr *clause, Oid opclass, Oid relam, switch (expr_op) { case OID_TEXT_LIKE_OP: + case OID_TEXT_ICLIKE_OP: case OID_TEXT_REGEXEQ_OP: case OID_TEXT_ICREGEXEQ_OP: if (!op_class(find_operator(">=", TEXTOID), opclass, relam) || @@ -1805,6 +1820,7 @@ match_special_index_operator(Expr *clause, Oid opclass, Oid relam, break; case OID_BPCHAR_LIKE_OP: + case OID_BPCHAR_ICLIKE_OP: case OID_BPCHAR_REGEXEQ_OP: case OID_BPCHAR_ICREGEXEQ_OP: if (!op_class(find_operator(">=", BPCHAROID), opclass, relam) || @@ -1813,6 +1829,7 @@ match_special_index_operator(Expr *clause, Oid opclass, Oid relam, break; case OID_VARCHAR_LIKE_OP: + case OID_VARCHAR_ICLIKE_OP: case OID_VARCHAR_REGEXEQ_OP: case OID_VARCHAR_ICREGEXEQ_OP: if (!op_class(find_operator(">=", VARCHAROID), opclass, relam) || @@ -1821,6 +1838,7 @@ match_special_index_operator(Expr *clause, Oid opclass, Oid relam, break; case OID_NAME_LIKE_OP: + case OID_NAME_ICLIKE_OP: case OID_NAME_REGEXEQ_OP: case OID_NAME_ICREGEXEQ_OP: if (!op_class(find_operator(">=", NAMEOID), opclass, relam) || @@ -1887,6 +1905,24 @@ expand_indexqual_conditions(List *indexquals) pfree(patt); break; + case OID_TEXT_ICLIKE_OP: + case OID_BPCHAR_ICLIKE_OP: + case OID_VARCHAR_ICLIKE_OP: + case OID_NAME_ICLIKE_OP: + /* the right-hand const is type text for all of these */ + constvalue = ((Const *) rightop)->constvalue; + patt = DatumGetCString(DirectFunctionCall1(textout, + constvalue)); + pstatus = pattern_fixed_prefix(patt, Pattern_Type_Like_IC, + &prefix, &rest); + resultquals = nconc(resultquals, + prefix_quals(leftop, expr_op, + prefix, pstatus)); + if (prefix) + pfree(prefix); + pfree(patt); + break; + case OID_TEXT_REGEXEQ_OP: case OID_BPCHAR_REGEXEQ_OP: case OID_VARCHAR_REGEXEQ_OP: @@ -1955,24 +1991,28 @@ prefix_quals(Var *leftop, Oid expr_op, switch (expr_op) { case OID_TEXT_LIKE_OP: + case OID_TEXT_ICLIKE_OP: case OID_TEXT_REGEXEQ_OP: case OID_TEXT_ICREGEXEQ_OP: datatype = TEXTOID; break; case OID_BPCHAR_LIKE_OP: + case OID_BPCHAR_ICLIKE_OP: case OID_BPCHAR_REGEXEQ_OP: case OID_BPCHAR_ICREGEXEQ_OP: datatype = BPCHAROID; break; case OID_VARCHAR_LIKE_OP: + case OID_VARCHAR_ICLIKE_OP: case OID_VARCHAR_REGEXEQ_OP: case OID_VARCHAR_ICREGEXEQ_OP: datatype = VARCHAROID; break; case OID_NAME_LIKE_OP: + case OID_NAME_ICLIKE_OP: case OID_NAME_REGEXEQ_OP: case OID_NAME_ICREGEXEQ_OP: datatype = NAMEOID; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 301be9eb9b957c787e604ba7f7a723aaee1622f5..c12cf997b757066b47fe56184a57af8d0ac1da5a 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.189 2000/09/12 21:07:01 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.190 2000/09/15 18:45:30 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -365,6 +365,7 @@ static void doNegateFloat(Value *v); %right '=' %nonassoc '<' '>' %nonassoc LIKE ILIKE +%nonassoc ESCAPE %nonassoc OVERLAPS %nonassoc BETWEEN %nonassoc IN @@ -382,7 +383,6 @@ static void doNegateFloat(Value *v); %left '.' %left '[' ']' %left TYPECAST -%left ESCAPE %% /* @@ -4522,76 +4522,48 @@ a_expr: c_expr { $$ = makeA_Expr(NOT, NULL, NULL, $2); } | a_expr LIKE a_expr - { - FuncCall *n = makeNode(FuncCall); - n->funcname = "like"; - n->args = makeList($1, $3, -1); - n->agg_star = FALSE; - n->agg_distinct = FALSE; - $$ = (Node *)n; - } + { $$ = makeA_Expr(OP, "~~", $1, $3); } | a_expr LIKE a_expr ESCAPE a_expr { FuncCall *n = makeNode(FuncCall); - n->funcname = "like"; - n->args = makeList($1, $3, $5, -1); + n->funcname = "like_escape"; + n->args = makeList($3, $5, -1); n->agg_star = FALSE; n->agg_distinct = FALSE; - $$ = (Node *)n; + $$ = makeA_Expr(OP, "~~", $1, (Node *) n); } | a_expr NOT LIKE a_expr - { - FuncCall *n = makeNode(FuncCall); - n->funcname = "notlike"; - n->args = makeList($1, $4, -1); - n->agg_star = FALSE; - n->agg_distinct = FALSE; - $$ = (Node *)n; - } + { $$ = makeA_Expr(OP, "!~~", $1, $4); } | a_expr NOT LIKE a_expr ESCAPE a_expr { FuncCall *n = makeNode(FuncCall); - n->funcname = "notlike"; - n->args = makeList($1, $4, $6, -1); + n->funcname = "like_escape"; + n->args = makeList($4, $6, -1); n->agg_star = FALSE; n->agg_distinct = FALSE; - $$ = (Node *)n; + $$ = makeA_Expr(OP, "!~~", $1, (Node *) n); } | a_expr ILIKE a_expr - { - FuncCall *n = makeNode(FuncCall); - n->funcname = "ilike"; - n->args = makeList($1, $3, -1); - n->agg_star = FALSE; - n->agg_distinct = FALSE; - $$ = (Node *)n; - } + { $$ = makeA_Expr(OP, "~~*", $1, $3); } | a_expr ILIKE a_expr ESCAPE a_expr { FuncCall *n = makeNode(FuncCall); - n->funcname = "ilike"; - n->args = makeList($1, $3, $5, -1); + n->funcname = "like_escape"; + n->args = makeList($3, $5, -1); n->agg_star = FALSE; n->agg_distinct = FALSE; - $$ = (Node *)n; + $$ = makeA_Expr(OP, "~~*", $1, (Node *) n); } | a_expr NOT ILIKE a_expr - { - FuncCall *n = makeNode(FuncCall); - n->funcname = "inotlike"; - n->args = makeList($1, $4, -1); - n->agg_star = FALSE; - n->agg_distinct = FALSE; - $$ = (Node *)n; - } + { $$ = makeA_Expr(OP, "!~~*", $1, $4); } | a_expr NOT ILIKE a_expr ESCAPE a_expr { FuncCall *n = makeNode(FuncCall); - n->funcname = "inotlike"; - n->args = makeList($1, $4, $6, -1); + n->funcname = "like_escape"; + n->args = makeList($4, $6, -1); n->agg_star = FALSE; n->agg_distinct = FALSE; - $$ = (Node *)n; + $$ = makeA_Expr(OP, "!~~*", $1, (Node *) n); } | a_expr ISNULL diff --git a/src/backend/utils/adt/like.c b/src/backend/utils/adt/like.c index e492c58cbadc5162fbe59998fcdfa61a79dab873..41e86648b8789aa449bf549f29a28d20d38f2115 100644 --- a/src/backend/utils/adt/like.c +++ b/src/backend/utils/adt/like.c @@ -11,12 +11,14 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/like.c,v 1.41 2000/08/22 06:33:57 ishii Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/like.c,v 1.42 2000/09/15 18:45:26 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" + #include <ctype.h> + #ifdef MULTIBYTE #include "mb/pg_wchar.h" #endif @@ -28,92 +30,129 @@ #define LIKE_ABORT (-1) -static int MatchText(unsigned char * t, int tlen, unsigned char * p, int plen, char *e); -static int MatchTextLower(unsigned char * t, int tlen, unsigned char * p, int plen, char *e); +static int MatchText(unsigned char * t, int tlen, + unsigned char * p, int plen); +static int MatchTextIC(unsigned char * t, int tlen, + unsigned char * p, int plen); -/* - * interface routines called by the function manager +#ifdef MULTIBYTE +/*-------------------- + * Support routine for MatchText. Compares given multibyte streams + * as wide characters. If they match, returns 1 otherwise returns 0. + *-------------------- */ - -Datum -namelike(PG_FUNCTION_ARGS) +static int wchareq(unsigned char *p1, unsigned char *p2) { - bool result; - Name str = PG_GETARG_NAME(0); - text *pat = PG_GETARG_TEXT_P(1); - unsigned char *s, *p; - int slen, plen; + int l; - s = NameStr(*str); - slen = strlen(s); - p = VARDATA(pat); - plen = (VARSIZE(pat)-VARHDRSZ); + l = pg_mblen(p1); + if (pg_mblen(p2) != l) { + return(0); + } + while (l--) { + if (*p1++ != *p2++) + return(0); + } + return(1); +} - result = (MatchText(s, slen, p, plen, "\\") == LIKE_TRUE); +/*-------------------- + * Support routine for MatchTextIC. Compares given multibyte streams + * as wide characters ignoring case. + * If they match, returns 1 otherwise returns 0. + *-------------------- + */ +#define UCHARMAX 0xff - PG_RETURN_BOOL(result); +static int iwchareq(unsigned char *p1, unsigned char *p2) +{ + int c1, c2; + int l; + + /* short cut. if *p1 and *p2 is lower than UCHARMAX, then + we assume they are ASCII */ + if (*p1 < UCHARMAX && *p2 < UCHARMAX) + return(tolower(*p1) == tolower(*p2)); + + if (*p1 < UCHARMAX) + c1 = tolower(*p1); + else + { + l = pg_mblen(p1); + (void)pg_mb2wchar_with_len(p1, (pg_wchar *)&c1, l); + c1 = tolower(c1); + } + if (*p2 < UCHARMAX) + c2 = tolower(*p2); + else + { + l = pg_mblen(p2); + (void)pg_mb2wchar_with_len(p2, (pg_wchar *)&c2, l); + c2 = tolower(c2); + } + return(c1 == c2); } -Datum -namenlike(PG_FUNCTION_ARGS) -{ - bool result; - Name str = PG_GETARG_NAME(0); - text *pat = PG_GETARG_TEXT_P(1); - unsigned char *s, *p; - int slen, plen; +#endif - s = NameStr(*str); - slen = strlen(s); - p = VARDATA(pat); - plen = (VARSIZE(pat)-VARHDRSZ); +#ifdef MULTIBYTE +#define CHAREQ(p1, p2) wchareq(p1, p2) +#define ICHAREQ(p1, p2) iwchareq(p1, p2) +#define NextChar(p, plen) \ + do { int __l = pg_mblen(p); (p) +=__l; (plen) -=__l; } while (0) +#define CopyAdvChar(dst, src, srclen) \ + do { int __l = pg_mblen(src); \ + (srclen) -= __l; \ + while (__l-- > 0) \ + *(dst)++ = *(src)++; \ + } while (0) +#else +#define CHAREQ(p1, p2) (*(p1) == *(p2)) +#define ICHAREQ(p1, p2) (tolower(*(p1)) == tolower(*(p2))) +#define NextChar(p, plen) ((p)++, (plen)--) +#define CopyAdvChar(dst, src, srclen) (*(dst)++ = *(src)++, (srclen)--) +#endif - result = (MatchText(s, slen, p, plen, "\\") != LIKE_TRUE); - PG_RETURN_BOOL(result); -} +/* + * interface routines called by the function manager + */ Datum -namelike_escape(PG_FUNCTION_ARGS) +namelike(PG_FUNCTION_ARGS) { - bool result; Name str = PG_GETARG_NAME(0); text *pat = PG_GETARG_TEXT_P(1); - text *esc = PG_GETARG_TEXT_P(2); + bool result; unsigned char *s, *p; int slen, plen; - char *e; s = NameStr(*str); slen = strlen(s); p = VARDATA(pat); plen = (VARSIZE(pat)-VARHDRSZ); - e = ((VARSIZE(esc)-VARHDRSZ) > 0? VARDATA(esc): NULL); - result = (MatchText(s, slen, p, plen, e) == LIKE_TRUE); + result = (MatchText(s, slen, p, plen) == LIKE_TRUE); PG_RETURN_BOOL(result); } Datum -namenlike_escape(PG_FUNCTION_ARGS) +namenlike(PG_FUNCTION_ARGS) { - bool result; Name str = PG_GETARG_NAME(0); text *pat = PG_GETARG_TEXT_P(1); - text *esc = PG_GETARG_TEXT_P(2); + bool result; unsigned char *s, *p; int slen, plen; - char *e; s = NameStr(*str); slen = strlen(s); p = VARDATA(pat); plen = (VARSIZE(pat)-VARHDRSZ); - e = ((VARSIZE(esc)-VARHDRSZ) > 0? VARDATA(esc): NULL); - result = (MatchText(s, slen, p, plen, e) != LIKE_TRUE); + result = (MatchText(s, slen, p, plen) != LIKE_TRUE); PG_RETURN_BOOL(result); } @@ -121,28 +160,9 @@ namenlike_escape(PG_FUNCTION_ARGS) Datum textlike(PG_FUNCTION_ARGS) { - bool result; text *str = PG_GETARG_TEXT_P(0); text *pat = PG_GETARG_TEXT_P(1); - unsigned char *s, *p; - int slen, plen; - - s = VARDATA(str); - slen = (VARSIZE(str)-VARHDRSZ); - p = VARDATA(pat); - plen = (VARSIZE(pat)-VARHDRSZ); - - result = (MatchText(s, slen, p, plen, NULL) == LIKE_TRUE); - - PG_RETURN_BOOL(result); -} - -Datum -textnlike(PG_FUNCTION_ARGS) -{ bool result; - text *str = PG_GETARG_TEXT_P(0); - text *pat = PG_GETARG_TEXT_P(1); unsigned char *s, *p; int slen, plen; @@ -151,51 +171,26 @@ textnlike(PG_FUNCTION_ARGS) p = VARDATA(pat); plen = (VARSIZE(pat)-VARHDRSZ); - result = (MatchText(s, slen, p, plen, "\\") != LIKE_TRUE); + result = (MatchText(s, slen, p, plen) == LIKE_TRUE); PG_RETURN_BOOL(result); } Datum -textlike_escape(PG_FUNCTION_ARGS) +textnlike(PG_FUNCTION_ARGS) { - bool result; text *str = PG_GETARG_TEXT_P(0); text *pat = PG_GETARG_TEXT_P(1); - text *esc = PG_GETARG_TEXT_P(2); - unsigned char *s, *p; - int slen, plen; - char *e; - - s = VARDATA(str); - slen = (VARSIZE(str)-VARHDRSZ); - p = VARDATA(pat); - plen = (VARSIZE(pat)-VARHDRSZ); - e = ((VARSIZE(esc)-VARHDRSZ) > 0? VARDATA(esc): NULL); - - result = (MatchText(s, slen, p, plen, e) == LIKE_TRUE); - - PG_RETURN_BOOL(result); -} - -Datum -textnlike_escape(PG_FUNCTION_ARGS) -{ bool result; - text *str = PG_GETARG_TEXT_P(0); - text *pat = PG_GETARG_TEXT_P(1); - text *esc = PG_GETARG_TEXT_P(2); unsigned char *s, *p; int slen, plen; - char *e; s = VARDATA(str); slen = (VARSIZE(str)-VARHDRSZ); p = VARDATA(pat); plen = (VARSIZE(pat)-VARHDRSZ); - e = ((VARSIZE(esc)-VARHDRSZ) > 0? VARDATA(esc): NULL); - result = (MatchText(s, slen, p, plen, e) != LIKE_TRUE); + result = (MatchText(s, slen, p, plen) != LIKE_TRUE); PG_RETURN_BOOL(result); } @@ -205,30 +200,11 @@ textnlike_escape(PG_FUNCTION_ARGS) */ Datum -inamelike(PG_FUNCTION_ARGS) +nameiclike(PG_FUNCTION_ARGS) { - bool result; Name str = PG_GETARG_NAME(0); text *pat = PG_GETARG_TEXT_P(1); - unsigned char *s, *p; - int slen, plen; - - s = NameStr(*str); - slen = strlen(s); - p = VARDATA(pat); - plen = (VARSIZE(pat)-VARHDRSZ); - - result = (MatchTextLower(s, slen, p, plen, "\\") == LIKE_TRUE); - - PG_RETURN_BOOL(result); -} - -Datum -inamenlike(PG_FUNCTION_ARGS) -{ bool result; - Name str = PG_GETARG_NAME(0); - text *pat = PG_GETARG_TEXT_P(1); unsigned char *s, *p; int slen, plen; @@ -237,61 +213,36 @@ inamenlike(PG_FUNCTION_ARGS) p = VARDATA(pat); plen = (VARSIZE(pat)-VARHDRSZ); - result = (MatchTextLower(s, slen, p, plen, "\\") != LIKE_TRUE); + result = (MatchTextIC(s, slen, p, plen) == LIKE_TRUE); PG_RETURN_BOOL(result); } Datum -inamelike_escape(PG_FUNCTION_ARGS) +nameicnlike(PG_FUNCTION_ARGS) { - bool result; Name str = PG_GETARG_NAME(0); text *pat = PG_GETARG_TEXT_P(1); - text *esc = PG_GETARG_TEXT_P(2); - unsigned char *s, *p; - int slen, plen; - char *e; - - s = NameStr(*str); - slen = strlen(s); - p = VARDATA(pat); - plen = (VARSIZE(pat)-VARHDRSZ); - e = ((VARSIZE(esc)-VARHDRSZ) > 0? VARDATA(esc): NULL); - - result = (MatchTextLower(s, slen, p, plen, e) == LIKE_TRUE); - - PG_RETURN_BOOL(result); -} - -Datum -inamenlike_escape(PG_FUNCTION_ARGS) -{ bool result; - Name str = PG_GETARG_NAME(0); - text *pat = PG_GETARG_TEXT_P(1); - text *esc = PG_GETARG_TEXT_P(2); unsigned char *s, *p; int slen, plen; - char *e; s = NameStr(*str); slen = strlen(s); p = VARDATA(pat); plen = (VARSIZE(pat)-VARHDRSZ); - e = ((VARSIZE(esc)-VARHDRSZ) > 0? VARDATA(esc): NULL); - result = (MatchTextLower(s, slen, p, plen, e) != LIKE_TRUE); + result = (MatchTextIC(s, slen, p, plen) != LIKE_TRUE); PG_RETURN_BOOL(result); } Datum -itextlike(PG_FUNCTION_ARGS) +texticlike(PG_FUNCTION_ARGS) { - bool result; text *str = PG_GETARG_TEXT_P(0); text *pat = PG_GETARG_TEXT_P(1); + bool result; unsigned char *s, *p; int slen, plen; @@ -300,17 +251,17 @@ itextlike(PG_FUNCTION_ARGS) p = VARDATA(pat); plen = (VARSIZE(pat)-VARHDRSZ); - result = (MatchTextLower(s, slen, p, plen, "\\") == LIKE_TRUE); + result = (MatchTextIC(s, slen, p, plen) == LIKE_TRUE); PG_RETURN_BOOL(result); } Datum -itextnlike(PG_FUNCTION_ARGS) +texticnlike(PG_FUNCTION_ARGS) { - bool result; text *str = PG_GETARG_TEXT_P(0); text *pat = PG_GETARG_TEXT_P(1); + bool result; unsigned char *s, *p; int slen, plen; @@ -319,53 +270,100 @@ itextnlike(PG_FUNCTION_ARGS) p = VARDATA(pat); plen = (VARSIZE(pat)-VARHDRSZ); - result = (MatchTextLower(s, slen, p, plen, "\\") != LIKE_TRUE); + result = (MatchTextIC(s, slen, p, plen) != LIKE_TRUE); PG_RETURN_BOOL(result); } +/* + * like_escape() --- given a pattern and an ESCAPE string, + * convert the pattern to use Postgres' standard backslash escape convention. + */ Datum -itextlike_escape(PG_FUNCTION_ARGS) +like_escape(PG_FUNCTION_ARGS) { - bool result; - text *str = PG_GETARG_TEXT_P(0); - text *pat = PG_GETARG_TEXT_P(1); - text *esc = PG_GETARG_TEXT_P(2); - unsigned char *s, *p; - int slen, plen; - char *e; + text *pat = PG_GETARG_TEXT_P(0); + text *esc = PG_GETARG_TEXT_P(1); + text *result; + unsigned char *p, *e, *r; + int plen, elen; + bool afterescape; - s = VARDATA(str); - slen = (VARSIZE(str)-VARHDRSZ); p = VARDATA(pat); plen = (VARSIZE(pat)-VARHDRSZ); - e = ((VARSIZE(esc)-VARHDRSZ) > 0? VARDATA(esc): NULL); - - result = (MatchTextLower(s, slen, p, plen, e) == LIKE_TRUE); + e = VARDATA(esc); + elen = (VARSIZE(esc)-VARHDRSZ); - PG_RETURN_BOOL(result); -} - -Datum -itextnlike_escape(PG_FUNCTION_ARGS) -{ - bool result; - text *str = PG_GETARG_TEXT_P(0); - text *pat = PG_GETARG_TEXT_P(1); - text *esc = PG_GETARG_TEXT_P(2); - unsigned char *s, *p; - int slen, plen; - char *e; + /* + * Worst-case pattern growth is 2x --- unlikely, but it's hardly worth + * trying to calculate the size more accurately than that. + */ + result = (text *) palloc(plen * 2 + VARHDRSZ); + r = VARDATA(result); - s = VARDATA(str); - slen = (VARSIZE(str)-VARHDRSZ); - p = VARDATA(pat); - plen = (VARSIZE(pat)-VARHDRSZ); - e = ((VARSIZE(esc)-VARHDRSZ) > 0? VARDATA(esc): NULL); + if (elen == 0) + { + /* + * No escape character is wanted. Double any backslashes in the + * pattern to make them act like ordinary characters. + */ + while (plen > 0) + { + if (*p == '\\') + *r++ = '\\'; + CopyAdvChar(r, p, plen); + } + } + else + { + /* + * The specified escape must be only a single character. + */ + NextChar(e, elen); + if (elen != 0) + elog(ERROR, "ESCAPE string must be empty or one character"); + e = VARDATA(esc); + /* + * If specified escape is '\', just copy the pattern as-is. + */ + if (*e == '\\') + { + memcpy(result, pat, VARSIZE(pat)); + PG_RETURN_TEXT_P(result); + } + /* + * Otherwise, convert occurrences of the specified escape character + * to '\', and double occurrences of '\' --- unless they immediately + * follow an escape character! + */ + afterescape = false; + while (plen > 0) + { + if (CHAREQ(p,e) && !afterescape) + { + *r++ = '\\'; + NextChar(p, plen); + afterescape = true; + } + else if (*p == '\\') + { + *r++ = '\\'; + if (! afterescape) + *r++ = '\\'; + NextChar(p, plen); + afterescape = false; + } + else + { + CopyAdvChar(r, p, plen); + afterescape = false; + } + } + } - result = (MatchTextLower(s, slen, p, plen, e) != LIKE_TRUE); + VARATT_SIZEP(result) = r - ((unsigned char *) result); - PG_RETURN_BOOL(result); + PG_RETURN_TEXT_P(result); } @@ -387,13 +385,14 @@ itextnlike_escape(PG_FUNCTION_ARGS) ** ** Keith Parks. <keith@mtcc.demon.co.uk> ** -** [SQL92 lets you specify the escape character by saying -** LIKE <pattern> ESCAPE <escape character>. We are a small operation -** so we force you to use '\'. - ay 7/95] +** SQL92 lets you specify the escape character by saying +** LIKE <pattern> ESCAPE <escape character>. We are a small operation +** so we force you to use '\'. - ay 7/95 +** +** Now we have the like_escape() function that converts patterns with +** any specified escape character (or none at all) to the internal +** default escape character, which is still '\'. - tgl 9/2000 ** -** OK, we now support the SQL9x LIKE <pattern> ESCAPE <char> syntax. -** We should kill the backslash escaping mechanism since it is non-standard -** and undocumented afaik. ** The code is rewritten to avoid requiring null-terminated strings, ** which in turn allows us to leave out some memcpy() operations. ** This code should be faster and take less memory, but no promises... @@ -401,6 +400,7 @@ itextnlike_escape(PG_FUNCTION_ARGS) ** */ + /*-------------------- * Match text and p, return LIKE_TRUE, LIKE_FALSE, or LIKE_ABORT. * @@ -413,93 +413,18 @@ itextnlike_escape(PG_FUNCTION_ARGS) *-------------------- */ -#ifdef MULTIBYTE -/*-------------------- - * Support routine for MatchText. Compares given multibyte streams - * as wide characters. If they match, returns 1 otherwise returns 0. - *-------------------- - */ -static int wchareq(unsigned char *p1, unsigned char *p2) -{ - int l; - - l = pg_mblen(p1); - if (pg_mblen(p2) != l) { - return(0); - } - while (l--) { - if (*p1++ != *p2++) - return(0); - } - return(1); -} - -/*-------------------- - * Support routine for MatchTextLower. Compares given multibyte streams - * as wide characters ignoring case. - * If they match, returns 1 otherwise returns 0. - *-------------------- - */ -#define UCHARMAX 0xff - -static int iwchareq(unsigned char *p1, unsigned char *p2) -{ - int c1, c2; - int l; - - /* short cut. if *p1 and *p2 is lower than UCHARMAX, then - we assume they are ASCII */ - if (*p1 < UCHARMAX && *p2 < UCHARMAX) - return(tolower(*p1) == tolower(*p2)); - - if (*p1 < UCHARMAX) - c1 = tolower(*p1); - else - { - l = pg_mblen(p1); - (void)pg_mb2wchar_with_len(p1, (pg_wchar *)&c1, l); - c1 = tolower(c1); - } - if (*p2 < UCHARMAX) - c2 = tolower(*p2); - else - { - l = pg_mblen(p2); - (void)pg_mb2wchar_with_len(p2, (pg_wchar *)&c2, l); - c2 = tolower(c2); - } - return(c1 == c2); -} -#endif - -#ifdef MULTIBYTE -#define CHAREQ(p1, p2) wchareq(p1, p2) -#define ICHAREQ(p1, p2) iwchareq(p1, p2) -#define NextChar(p, plen) {int __l = pg_mblen(p); (p) +=__l; (plen) -=__l;} -#else -#define CHAREQ(p1, p2) (*(p1) == *(p2)) -#define ICHAREQ(p1, p2) (tolower(*(p1)) == tolower(*(p2))) -#define NextChar(p, plen) (p)++, (plen)-- -#endif - static int -MatchText(unsigned char * t, int tlen, unsigned char * p, int plen, char *e) +MatchText(unsigned char * t, int tlen, unsigned char * p, int plen) { - /* Fast path for match-everything pattern - * Include weird case of escape character as a percent sign or underscore, - * when presumably that wildcard character becomes a literal. - */ - if ((plen == 1) && (*p == '%') - && ! ((e != NULL) && (*e == '%'))) + /* Fast path for match-everything pattern */ + if ((plen == 1) && (*p == '%')) return LIKE_TRUE; while ((tlen > 0) && (plen > 0)) { - /* If an escape character was specified and we find it here in the pattern, - * then we'd better have an exact match for the next character. - */ - if ((e != NULL) && CHAREQ(p,e)) + if (*p == '\\') { + /* Next pattern char must match literally, whatever it is */ NextChar(p, plen); if ((plen <= 0) || !CHAREQ(t,p)) return LIKE_FALSE; @@ -525,10 +450,9 @@ MatchText(unsigned char * t, int tlen, unsigned char * p, int plen, char *e) * recurse unless first pattern char might match this * text char. */ - if (CHAREQ(t,p) || (*p == '_') - || ((e != NULL) && CHAREQ(p,e))) + if (CHAREQ(t,p) || (*p == '\\') || (*p == '_')) { - int matched = MatchText(t, tlen, p, plen, e); + int matched = MatchText(t, tlen, p, plen); if (matched != LIKE_FALSE) return matched; /* TRUE or ABORT */ @@ -571,24 +495,21 @@ MatchText(unsigned char * t, int tlen, unsigned char * p, int plen, char *e) return LIKE_ABORT; } /* MatchText() */ +/* + * Same as above, but ignore case + */ static int -MatchTextLower(unsigned char * t, int tlen, unsigned char * p, int plen, char *e) +MatchTextIC(unsigned char * t, int tlen, unsigned char * p, int plen) { - /* Fast path for match-everything pattern - * Include weird case of escape character as a percent sign or underscore, - * when presumably that wildcard character becomes a literal. - */ - if ((plen == 1) && (*p == '%') - && ! ((e != NULL) && (*e == '%'))) + /* Fast path for match-everything pattern */ + if ((plen == 1) && (*p == '%')) return LIKE_TRUE; while ((tlen > 0) && (plen > 0)) { - /* If an escape character was specified and we find it here in the pattern, - * then we'd better have an exact match for the next character. - */ - if ((e != NULL) && ICHAREQ(p,e)) + if (*p == '\\') { + /* Next pattern char must match literally, whatever it is */ NextChar(p, plen); if ((plen <= 0) || !ICHAREQ(t,p)) return LIKE_FALSE; @@ -614,10 +535,9 @@ MatchTextLower(unsigned char * t, int tlen, unsigned char * p, int plen, char *e * recurse unless first pattern char might match this * text char. */ - if (ICHAREQ(t,p) || (*p == '_') - || ((e != NULL) && ICHAREQ(p,e))) + if (ICHAREQ(t,p) || (*p == '\\') || (*p == '_')) { - int matched = MatchText(t, tlen, p, plen, e); + int matched = MatchTextIC(t, tlen, p, plen); if (matched != LIKE_FALSE) return matched; /* TRUE or ABORT */ @@ -634,6 +554,9 @@ MatchTextLower(unsigned char * t, int tlen, unsigned char * p, int plen, char *e } else if ((*p != '_') && !ICHAREQ(t,p)) { + /* Not the single-character wildcard and no explicit match? + * Then time to quit... + */ return LIKE_FALSE; } @@ -655,4 +578,4 @@ MatchTextLower(unsigned char * t, int tlen, unsigned char * p, int plen, char *e * start matching this pattern. */ return LIKE_ABORT; -} /* MatchTextLower() */ +} /* MatchTextIC() */ diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index e31860c4d3573346f902f94a8366fc8ef4cb91db..55b0273eb8b6bd141547768972eab700510c81a7 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -15,7 +15,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.78 2000/08/03 16:34:22 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.79 2000/09/15 18:45:26 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -570,6 +570,15 @@ likesel(PG_FUNCTION_ARGS) return patternsel(fcinfo, Pattern_Type_Like); } +/* + * iclikesel - Selectivity of ILIKE pattern match. + */ +Datum +iclikesel(PG_FUNCTION_ARGS) +{ + return patternsel(fcinfo, Pattern_Type_Like_IC); +} + /* * regexnesel - Selectivity of regular-expression pattern non-match. */ @@ -609,6 +618,19 @@ nlikesel(PG_FUNCTION_ARGS) PG_RETURN_FLOAT8(result); } +/* + * icnlikesel - Selectivity of ILIKE pattern non-match. + */ +Datum +icnlikesel(PG_FUNCTION_ARGS) +{ + float8 result; + + result = DatumGetFloat8(patternsel(fcinfo, Pattern_Type_Like_IC)); + result = 1.0 - result; + PG_RETURN_FLOAT8(result); +} + /* * eqjoinsel - Join selectivity of "=" */ @@ -723,6 +745,15 @@ likejoinsel(PG_FUNCTION_ARGS) PG_RETURN_FLOAT8(DEFAULT_MATCH_SEL); } +/* + * iclikejoinsel - Join selectivity of ILIKE pattern match. + */ +Datum +iclikejoinsel(PG_FUNCTION_ARGS) +{ + PG_RETURN_FLOAT8(DEFAULT_MATCH_SEL); +} + /* * regexnejoinsel - Join selectivity of regex non-match. */ @@ -762,6 +793,19 @@ nlikejoinsel(PG_FUNCTION_ARGS) PG_RETURN_FLOAT8(result); } +/* + * icnlikejoinsel - Join selectivity of ILIKE pattern non-match. + */ +Datum +icnlikejoinsel(PG_FUNCTION_ARGS) +{ + float8 result; + + result = DatumGetFloat8(iclikejoinsel(fcinfo)); + result = 1.0 - result; + PG_RETURN_FLOAT8(result); +} + /* * convert_to_scalar @@ -1337,7 +1381,8 @@ getattstatistics(Oid relid, */ static Pattern_Prefix_Status -like_fixed_prefix(char *patt, char **prefix, char **rest) +like_fixed_prefix(char *patt, bool case_insensitive, + char **prefix, char **rest) { char *match; int pos, @@ -1359,7 +1404,12 @@ like_fixed_prefix(char *patt, char **prefix, char **rest) if (patt[pos] == '\0') break; } - + /* + * XXX I suspect isalpha() is not an adequately locale-sensitive + * test for characters that can vary under case folding? + */ + if (case_insensitive && isalpha((int) patt[pos])) + break; /* * NOTE: this code used to think that %% meant a literal %, but * textlike() itself does not think that, and the SQL92 spec @@ -1497,7 +1547,10 @@ pattern_fixed_prefix(char *patt, Pattern_Type ptype, switch (ptype) { case Pattern_Type_Like: - result = like_fixed_prefix(patt, prefix, rest); + result = like_fixed_prefix(patt, false, prefix, rest); + break; + case Pattern_Type_Like_IC: + result = like_fixed_prefix(patt, true, prefix, rest); break; case Pattern_Type_Regex: result = regex_fixed_prefix(patt, false, prefix, rest); @@ -1625,7 +1678,7 @@ prefix_selectivity(char *prefix, #define PARTIAL_WILDCARD_SEL 2.0 static Selectivity -like_selectivity(char *patt) +like_selectivity(char *patt, bool case_insensitive) { Selectivity sel = 1.0; int pos; @@ -1780,7 +1833,10 @@ pattern_selectivity(char *patt, Pattern_Type ptype) switch (ptype) { case Pattern_Type_Like: - result = like_selectivity(patt); + result = like_selectivity(patt, false); + break; + case Pattern_Type_Like_IC: + result = like_selectivity(patt, true); break; case Pattern_Type_Regex: result = regex_selectivity(patt, false); diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index eb067fe50575ff3561b537b2928c7bc12e0617bc..e23b8b9cb5379d31d1fd41f2c51b60c00c8eeae1 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: catversion.h,v 1.45 2000/09/12 21:07:06 tgl Exp $ + * $Id: catversion.h,v 1.46 2000/09/15 18:45:27 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200009121 +#define CATALOG_VERSION_NO 200009151 #endif diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h index 746dd30043421941ad37511011bec5f523b56b15..cf97d29516cc532a6a5b66d2a184de30eb1d2b7b 100644 --- a/src/include/catalog/pg_operator.h +++ b/src/include/catalog/pg_operator.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_operator.h,v 1.81 2000/08/21 04:48:51 tgl Exp $ + * $Id: pg_operator.h,v 1.82 2000/09/15 18:45:27 tgl Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -537,7 +537,7 @@ DATA(insert OID = 1213 ( "~~" PGUID 0 b t f 1043 25 16 0 1214 0 0 textlike #define OID_VARCHAR_LIKE_OP 1213 DATA(insert OID = 1214 ( "!~~" PGUID 0 b t f 1043 25 16 0 1213 0 0 textnlike nlikesel nlikejoinsel )); -/* case-insensitive LIKE hacks */ +/* case-insensitive regex hacks */ DATA(insert OID = 1226 ( "~*" PGUID 0 b t f 19 25 16 0 1227 0 0 nameicregexeq icregexeqsel icregexeqjoinsel )); #define OID_NAME_ICREGEXEQ_OP 1226 DATA(insert OID = 1227 ( "!~*" PGUID 0 b t f 19 25 16 0 1226 0 0 nameicregexne icregexnesel icregexnejoinsel )); @@ -690,6 +690,20 @@ DATA(insert OID = 827 ( "<<=" PGUID 0 b t f 650 650 16 1004 0 0 0 network_ DATA(insert OID = 828 ( ">>" PGUID 0 b t f 650 650 16 826 0 0 0 network_sup - - )); DATA(insert OID = 1004 ( ">>=" PGUID 0 b t f 650 650 16 827 0 0 0 network_supeq - - )); +/* case-insensitive LIKE hacks */ +DATA(insert OID = 1625 ( "~~*" PGUID 0 b t f 19 25 16 0 1626 0 0 nameiclike iclikesel iclikejoinsel )); +#define OID_NAME_ICLIKE_OP 1625 +DATA(insert OID = 1626 ( "!~~*" PGUID 0 b t f 19 25 16 0 1625 0 0 nameicnlike icnlikesel icnlikejoinsel )); +DATA(insert OID = 1627 ( "~~*" PGUID 0 b t f 25 25 16 0 1628 0 0 texticlike iclikesel iclikejoinsel )); +#define OID_TEXT_ICLIKE_OP 1627 +DATA(insert OID = 1628 ( "!~~*" PGUID 0 b t f 25 25 16 0 1627 0 0 texticnlike icnlikesel icnlikejoinsel )); +DATA(insert OID = 1629 ( "~~*" PGUID 0 b t f 1042 25 16 0 1630 0 0 texticlike iclikesel iclikejoinsel )); +#define OID_BPCHAR_ICLIKE_OP 1629 +DATA(insert OID = 1630 ( "!~~*" PGUID 0 b t f 1042 25 16 0 1629 0 0 texticnlike icnlikesel icnlikejoinsel )); +DATA(insert OID = 1631 ( "~~*" PGUID 0 b t f 1043 25 16 0 1632 0 0 texticlike iclikesel iclikejoinsel )); +#define OID_VARCHAR_ICLIKE_OP 1631 +DATA(insert OID = 1632 ( "!~~*" PGUID 0 b t f 1043 25 16 0 1631 0 0 texticnlike icnlikesel icnlikejoinsel )); + /* NUMERIC type - OID's 1700-1799 */ DATA(insert OID = 1751 ( "-" PGUID 0 l t f 0 1700 1700 0 0 0 0 numeric_uminus - - )); DATA(insert OID = 1752 ( "=" PGUID 0 b t f 1700 1700 16 1752 1753 1754 1754 numeric_eq eqsel eqjoinsel )); diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 04109473d8e3730c95801f93287880c00907e41e..ac1dbabef1e0097d74eaa640a2b18ee21fedf64f 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_proc.h,v 1.165 2000/09/05 20:25:13 wieck Exp $ + * $Id: pg_proc.h,v 1.166 2000/09/15 18:45:27 tgl Exp $ * * NOTES * The script catalog/genbki.sh reads this file and generates .bki @@ -2039,30 +2039,16 @@ DATA(insert OID = 1623 ( varchar PGUID 12 f t t t 1 f 1043 "20" 100 0 0 100 DESCR("convert int8 to varchar"); DATA(insert OID = 1624 ( mul_d_interval PGUID 12 f t t t 2 f 1186 "701 1186" 100 0 0 100 mul_d_interval - )); -DATA(insert OID = 1625 ( like PGUID 12 f t t t 3 f 16 "19 25 25" 100 0 0 100 namelike_escape - )); -DESCR("matches LIKE expression"); -DATA(insert OID = 1626 ( notlike PGUID 12 f t t t 3 f 16 "19 25 25" 100 0 0 100 namenlike_escape - )); -DESCR("does not match LIKE expression"); -DATA(insert OID = 1627 ( ilike PGUID 12 f t t t 3 f 16 "19 25 25" 100 0 0 100 inamelike_escape - )); -DESCR("matches case-insensitive LIKE expression"); -DATA(insert OID = 1628 ( inotlike PGUID 12 f t t t 3 f 16 "19 25 25" 100 0 0 100 inamenlike_escape - )); -DESCR("does not match case-insensitive LIKE expression"); -DATA(insert OID = 1629 ( like PGUID 12 f t t t 3 f 16 "25 25 25" 100 0 0 100 textlike_escape - )); -DESCR("matches LIKE expression"); -DATA(insert OID = 1630 ( notlike PGUID 12 f t t t 3 f 16 "25 25 25" 100 0 0 100 textnlike_escape - )); -DESCR("does not match LIKE expression"); -DATA(insert OID = 1631 ( ilike PGUID 12 f t t t 3 f 16 "25 25 25" 100 0 0 100 itextlike_escape - )); -DESCR("matches case-insensitive LIKE expression"); -DATA(insert OID = 1632 ( inotlike PGUID 12 f t t t 3 f 16 "25 25 25" 100 0 0 100 itextnlike_escape - )); -DESCR("does not match case-insensitive LIKE expression"); -DATA(insert OID = 1633 ( ilike PGUID 12 f t t t 2 f 16 "25 25" 100 0 0 100 itextlike - )); -DESCR("matches case-insensitive LIKE expression"); -DATA(insert OID = 1634 ( inotlike PGUID 12 f t t t 2 f 16 "25 25" 100 0 0 100 itextnlike - )); -DESCR("does not match case-insensitive LIKE expression"); -DATA(insert OID = 1635 ( ilike PGUID 12 f t t t 2 f 16 "19 25" 100 0 0 100 inamelike - )); -DESCR("matches case-insensitive LIKE expression"); -DATA(insert OID = 1636 ( inotlike PGUID 12 f t t t 2 f 16 "19 25" 100 0 0 100 inamenlike - )); -DESCR("does not match case-insensitive LIKE expression"); +DATA(insert OID = 1633 ( texticlike PGUID 12 f t t t 2 f 16 "25 25" 100 0 0 100 texticlike - )); +DESCR("matches LIKE expression, case-insensitive"); +DATA(insert OID = 1634 ( texticnlike PGUID 12 f t t t 2 f 16 "25 25" 100 0 0 100 texticnlike - )); +DESCR("does not match LIKE expression, case-insensitive"); +DATA(insert OID = 1635 ( nameiclike PGUID 12 f t t t 2 f 16 "19 25" 100 0 0 100 nameiclike - )); +DESCR("matches LIKE expression, case-insensitive"); +DATA(insert OID = 1636 ( nameicnlike PGUID 12 f t t t 2 f 16 "19 25" 100 0 0 100 nameicnlike - )); +DESCR("does not match LIKE expression, case-insensitive"); +DATA(insert OID = 1637 ( like_escape PGUID 12 f t t t 2 f 25 "25 25" 100 0 0 100 like_escape - )); +DESCR("convert match pattern to use backslash escapes"); DATA(insert OID = 1689 ( update_pg_pwd PGUID 12 f t f t 0 f 0 "" 100 0 0 100 update_pg_pwd - )); DESCR("update pg_pwd file"); @@ -2420,6 +2406,14 @@ DATA(insert OID = 1799 ( oidout PGUID 12 f t t t 1 f 23 "0" 100 0 0 100 oi DESCR("(internal)"); /* Selectivity estimators for LIKE and related operators */ +DATA(insert OID = 1814 ( iclikesel PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100 iclikesel - )); +DESCR("restriction selectivity of ILIKE"); +DATA(insert OID = 1815 ( icnlikesel PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100 icnlikesel - )); +DESCR("restriction selectivity of NOT ILIKE"); +DATA(insert OID = 1816 ( iclikejoinsel PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100 iclikejoinsel - )); +DESCR("join selectivity of ILIKE"); +DATA(insert OID = 1817 ( icnlikejoinsel PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100 icnlikejoinsel - )); +DESCR("join selectivity of NOT ILIKE"); DATA(insert OID = 1818 ( regexeqsel PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100 regexeqsel - )); DESCR("restriction selectivity of regex match"); DATA(insert OID = 1819 ( likesel PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100 likesel - )); diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index cbb0aabe498ea9946fa262210e597ff219dbc798..054f3d5a7aacef1fef342b2c35354a6f68756367 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: builtins.h,v 1.136 2000/09/05 20:25:14 wieck Exp $ + * $Id: builtins.h,v 1.137 2000/09/15 18:45:29 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -320,9 +320,11 @@ extern Datum scalargtsel(PG_FUNCTION_ARGS); extern Datum regexeqsel(PG_FUNCTION_ARGS); extern Datum icregexeqsel(PG_FUNCTION_ARGS); extern Datum likesel(PG_FUNCTION_ARGS); +extern Datum iclikesel(PG_FUNCTION_ARGS); extern Datum regexnesel(PG_FUNCTION_ARGS); extern Datum icregexnesel(PG_FUNCTION_ARGS); extern Datum nlikesel(PG_FUNCTION_ARGS); +extern Datum icnlikesel(PG_FUNCTION_ARGS); extern Datum eqjoinsel(PG_FUNCTION_ARGS); extern Datum neqjoinsel(PG_FUNCTION_ARGS); @@ -331,9 +333,11 @@ extern Datum scalargtjoinsel(PG_FUNCTION_ARGS); extern Datum regexeqjoinsel(PG_FUNCTION_ARGS); extern Datum icregexeqjoinsel(PG_FUNCTION_ARGS); extern Datum likejoinsel(PG_FUNCTION_ARGS); +extern Datum iclikejoinsel(PG_FUNCTION_ARGS); extern Datum regexnejoinsel(PG_FUNCTION_ARGS); extern Datum icregexnejoinsel(PG_FUNCTION_ARGS); extern Datum nlikejoinsel(PG_FUNCTION_ARGS); +extern Datum icnlikejoinsel(PG_FUNCTION_ARGS); extern Datum btcostestimate(PG_FUNCTION_ARGS); extern Datum rtcostestimate(PG_FUNCTION_ARGS); @@ -343,7 +347,8 @@ extern Datum gistcostestimate(PG_FUNCTION_ARGS); /* selfuncs.c supporting routines that are also used by optimizer code */ typedef enum { - Pattern_Type_Like, Pattern_Type_Regex, Pattern_Type_Regex_IC + Pattern_Type_Like, Pattern_Type_Like_IC, + Pattern_Type_Regex, Pattern_Type_Regex_IC } Pattern_Type; typedef enum @@ -432,20 +437,13 @@ extern Datum pgsql_version(PG_FUNCTION_ARGS); /* like.c */ extern Datum namelike(PG_FUNCTION_ARGS); extern Datum namenlike(PG_FUNCTION_ARGS); -extern Datum namelike_escape(PG_FUNCTION_ARGS); -extern Datum namenlike_escape(PG_FUNCTION_ARGS); -extern Datum inamelike(PG_FUNCTION_ARGS); -extern Datum inamenlike(PG_FUNCTION_ARGS); -extern Datum inamelike_escape(PG_FUNCTION_ARGS); -extern Datum inamenlike_escape(PG_FUNCTION_ARGS); +extern Datum nameiclike(PG_FUNCTION_ARGS); +extern Datum nameicnlike(PG_FUNCTION_ARGS); extern Datum textlike(PG_FUNCTION_ARGS); extern Datum textnlike(PG_FUNCTION_ARGS); -extern Datum textlike_escape(PG_FUNCTION_ARGS); -extern Datum textnlike_escape(PG_FUNCTION_ARGS); -extern Datum itextlike(PG_FUNCTION_ARGS); -extern Datum itextnlike(PG_FUNCTION_ARGS); -extern Datum itextlike_escape(PG_FUNCTION_ARGS); -extern Datum itextnlike_escape(PG_FUNCTION_ARGS); +extern Datum texticlike(PG_FUNCTION_ARGS); +extern Datum texticnlike(PG_FUNCTION_ARGS); +extern Datum like_escape(PG_FUNCTION_ARGS); /* oracle_compat.c */ extern Datum lower(PG_FUNCTION_ARGS); diff --git a/src/test/regress/expected/strings.out b/src/test/regress/expected/strings.out index 398303694bdfb32e9e3a569ea9922c33fc986cc1..e59ba8e1df5f8494f7884339319af1098b17635f 100644 --- a/src/test/regress/expected/strings.out +++ b/src/test/regress/expected/strings.out @@ -443,13 +443,13 @@ SELECT 'hawkeye' NOT ILIKE 'H%' AS "false"; SELECT 'hawkeye' ILIKE 'H%Eye' AS "true"; true ------ - f + t (1 row) SELECT 'hawkeye' NOT ILIKE 'H%Eye' AS "false"; false ------- - t + f (1 row) SELECT 'Hawkeye' ILIKE 'h%' AS "true";