Go back to using a separate method for doing ILIKE for single byte
authorAndrew Dunstan <andrew@dunslane.net>
Sat, 22 Sep 2007 03:58:34 +0000 (03:58 +0000)
committerAndrew Dunstan <andrew@dunslane.net>
Sat, 22 Sep 2007 03:58:34 +0000 (03:58 +0000)
character encodings that doesn't involve calling lower(). This should
cure the performance regression in this case complained of by Guillaume
Smet. It still leaves the horrid performance for multi-byte encodings
introduced in 8.2, but there's no obvious solution for that in sight.

src/backend/utils/adt/like.c
src/backend/utils/adt/like_match.c

index 1603a4e61ae786d882db6a0b8fed800f2e06e0ae..4c4ca2c19363e59d67fde32ee341aa30579a8589 100644 (file)
@@ -11,7 +11,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *     $PostgreSQL: pgsql/src/backend/utils/adt/like.c,v 1.70 2007/09/21 22:52:52 tgl Exp $
+ *     $PostgreSQL: pgsql/src/backend/utils/adt/like.c,v 1.71 2007/09/22 03:58:34 adunstan Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -36,6 +36,8 @@ static text *MB_do_like_escape(text *, text *);
 
 static int     UTF8_MatchText(char *t, int tlen, char *p, int plen);
 
+static int     SB_IMatchText(char *t, int tlen, char *p, int plen);
+
 static int     GenericMatchText(char *s, int slen, char* p, int plen);
 static int     Generic_Text_IC_like(text *str, text *pat);
 
@@ -104,6 +106,12 @@ wchareq(char *p1, char *p2)
 
 #include "like_match.c"
 
+/* setup to compile like_match.c for single byte case insensitive matches */
+#define MATCH_LOWER
+#define NextChar(p, plen) NextByte((p), (plen))
+#define MatchText SB_IMatchText
+
+#include "like_match.c"
 
 /* setup to compile like_match.c for UTF8 encoding, using fast NextChar */
 
@@ -132,16 +140,33 @@ Generic_Text_IC_like(text *str, text *pat)
        int                     slen,
                                plen;
 
-       /* Force inputs to lower case to achieve case insensitivity */
-       str = DatumGetTextP(DirectFunctionCall1(lower, PointerGetDatum(str)));
-       pat = DatumGetTextP(DirectFunctionCall1(lower, PointerGetDatum(pat)));
-       /* lower's result is never packed, so OK to use old macros here */
-       s = VARDATA(str);
-       slen = (VARSIZE(str) - VARHDRSZ);
-       p = VARDATA(pat);
-       plen = (VARSIZE(pat) - VARHDRSZ);
+       /* For efficiency reasons, in the single byte case we don't call
+        * lower() on the pattern and text, but instead call to_lower on each
+        * character.  In the multi-byte case we don't have much choice :-(
+        */
 
-       return GenericMatchText(s, slen, p, plen);
+       if (pg_database_encoding_max_length() > 1)
+       {
+               /* lower's result is never packed, so OK to use old macros here */
+               pat = DatumGetTextP(DirectFunctionCall1(lower, PointerGetDatum(pat)));
+               p = VARDATA(pat);
+               plen = (VARSIZE(pat) - VARHDRSZ);
+               str = DatumGetTextP(DirectFunctionCall1(lower, PointerGetDatum(str)));
+               s = VARDATA(str);
+               slen = (VARSIZE(str) - VARHDRSZ);
+               if (GetDatabaseEncoding() == PG_UTF8)
+                       return UTF8_MatchText(s, slen, p, plen);
+               else
+                       return MB_MatchText(s, slen, p, plen);
+       }
+       else
+       {
+               p = VARDATA_ANY(pat);
+               plen = VARSIZE_ANY_EXHDR(pat);
+               s = VARDATA_ANY(str);
+               slen = VARSIZE_ANY_EXHDR(str);
+               return SB_IMatchText(s, slen, p, plen);
+       }
 }
 
 /*
index 7ab29623f3c9985856503d2aa67176b6773f8e11..f2ee0bae0ec434c19dd329e413fe409e1573c895 100644 (file)
@@ -3,8 +3,9 @@
  * like_match.c
  *       like expression handling internal code.
  *
- * This file is included by like.c three times, to provide natching code for
- * single-byte encodings, UTF8, and for other multi-byte encodings.
+ * This file is included by like.c four times, to provide natching code for
+ * single-byte encodings, UTF8, and for other multi-byte encodings,
+ * and case insensitive matches for single byte encodings.
  * UTF8 is a special case because we can use a much more efficient version
  * of NextChar than can be used for other multi-byte encodings.
  *
  * NextChar 
  * MatchText - to name of function wanted
  * do_like_escape - name of function if wanted - needs CHAREQ and CopyAdvChar
+ * MATCH_LOWER - define iff using to_lower on text chars
  *
  * Copyright (c) 1996-2007, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *     $PostgreSQL: pgsql/src/backend/utils/adt/like_match.c,v 1.17 2007/09/21 22:52:52 tgl Exp $
+ *     $PostgreSQL: pgsql/src/backend/utils/adt/like_match.c,v 1.18 2007/09/22 03:58:34 adunstan Exp $
  *
  *-------------------------------------------------------------------------
  */
  *--------------------
  */
 
+#ifdef MATCH_LOWER
+#define TCHAR(t) tolower((t))
+#else
+#define TCHAR(t) (t)
+#endif
+
 static int
 MatchText(char *t, int tlen, char *p, int plen)
 {
@@ -143,13 +151,13 @@ MatchText(char *t, int tlen, char *p, int plen)
                        else
                        {
 
-                               char firstpat = *p ;
+                               char firstpat = TCHAR(*p) ;
 
                                if (*p == '\\')
                                {
                                        if (plen < 2)
                                                return LIKE_FALSE;
-                                       firstpat = p[1];
+                                       firstpat = TCHAR(p[1]);
                                }
 
                                while (tlen > 0)
@@ -158,7 +166,7 @@ MatchText(char *t, int tlen, char *p, int plen)
                                         * Optimization to prevent most recursion: don't recurse
                                         * unless first pattern byte matches first text byte.
                                         */
-                                       if (*t == firstpat)
+                                       if (TCHAR(*t) == firstpat)
                                        {
                                                int                     matched = MatchText(t, tlen, p, plen);
                                                
@@ -183,7 +191,7 @@ MatchText(char *t, int tlen, char *p, int plen)
                        NextByte(p, plen);
                        continue;
                }
-               else if (*t != *p)
+               else if (TCHAR(*t) != TCHAR(*p))
                {
                        /*
                         * Not the single-character wildcard and no explicit match? Then
@@ -338,3 +346,8 @@ do_like_escape(text *pat, text *esc)
 #undef do_like_escape
 #endif
 
+#undef TCHAR
+
+#ifdef MATCH_LOWER
+#undef MATCH_LOWER
+#endif