like.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:5k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * like.c
  4.  *   like expression handling code.
  5.  *
  6.  *  NOTES
  7.  * A big hack of the regexp.c code!! Contributed by
  8.  * Keith Parks <emkxp01@mtcc.demon.co.uk> (7/95).
  9.  *
  10.  * Copyright (c) 1994, Regents of the University of California
  11.  *
  12.  * IDENTIFICATION
  13.  * $Header: /usr/local/cvsroot/pgsql/src/backend/utils/adt/like.c,v 1.25.2.2 1999/09/07 19:12:16 tgl Exp $
  14.  *
  15.  *-------------------------------------------------------------------------
  16.  */
  17. #include "postgres.h"
  18. #include "mb/pg_wchar.h"
  19. #include "utils/builtins.h"
  20. static int like(pg_wchar * text, pg_wchar * p);
  21. /*
  22.  * interface routines called by the function manager
  23.  */
  24. /*
  25.    fixedlen_like:
  26.    a generic fixed length like routine
  27.  s - the string to match against  (not necessarily null-terminated)
  28.  p    - the pattern
  29.  charlen   - the length of the string
  30. */
  31. static bool
  32. fixedlen_like(char *s, struct varlena * p, int charlen)
  33. {
  34. pg_wchar   *sterm,
  35.    *pterm;
  36. int result;
  37. int len;
  38. if (!s || !p)
  39. return FALSE;
  40. /* be sure sterm is null-terminated */
  41. #ifdef MULTIBYTE
  42. sterm = (pg_wchar *) palloc((charlen + 1) * sizeof(pg_wchar));
  43. (void) pg_mb2wchar_with_len((unsigned char *) s, sterm, charlen);
  44. #else
  45. sterm = (char *) palloc(charlen + 1);
  46. StrNCpy(sterm, s, charlen + 1);
  47. #endif
  48. /*
  49.  * p is a text = varlena, not a string so we have to make a string
  50.  * from the vl_data field of the struct.
  51.  */
  52. /* palloc the length of the text + the null character */
  53. len = VARSIZE(p) - VARHDRSZ;
  54. #ifdef MULTIBYTE
  55. pterm = (pg_wchar *) palloc((len + 1) * sizeof(pg_wchar));
  56. (void) pg_mb2wchar_with_len((unsigned char *) VARDATA(p), pterm, len);
  57. #else
  58. pterm = (char *) palloc(len + 1);
  59. memmove(pterm, VARDATA(p), len);
  60. *(pterm + len) = (char) NULL;
  61. #endif
  62. /* do the regexp matching */
  63. result = like(sterm, pterm);
  64. pfree(sterm);
  65. pfree(pterm);
  66. return (bool) result;
  67. }
  68. bool
  69. namelike(NameData *n, struct varlena * p)
  70. {
  71. if (!n)
  72. return FALSE;
  73. return fixedlen_like(n->data, p, NAMEDATALEN);
  74. }
  75. bool
  76. namenlike(NameData *s, struct varlena * p)
  77. {
  78. return !namelike(s, p);
  79. }
  80. bool
  81. textlike(struct varlena * s, struct varlena * p)
  82. {
  83. if (!s)
  84. return FALSE;
  85. return fixedlen_like(VARDATA(s), p, VARSIZE(s) - VARHDRSZ);
  86. }
  87. bool
  88. textnlike(struct varlena * s, struct varlena * p)
  89. {
  90. return !textlike(s, p);
  91. }
  92. /*
  93. ** Originally written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
  94. ** Rich $alz is now <rsalz@bbn.com>.
  95. ** Special thanks to Lars Mathiesen <thorinn@diku.dk> for the LABORT code.
  96. **
  97. ** This code was shamelessly stolen from the "pql" code by myself and
  98. ** slightly modified :)
  99. **
  100. ** All references to the word "star" were replaced by "percent"
  101. ** All references to the word "wild" were replaced by "like"
  102. **
  103. ** All the nice shell RE matching stuff was replaced by just "_" and "%"
  104. **
  105. ** As I don't have a copy of the SQL standard handy I wasn't sure whether
  106. ** to leave in the '' escape character handling.
  107. **
  108. ** Keith Parks. <keith@mtcc.demon.co.uk>
  109. **
  110. ** [SQL92 lets you specify the escape character by saying
  111. **  LIKE <pattern> ESCAPE <escape character>. We are a small operation
  112. **  so we force you to use ''. - ay 7/95]
  113. **
  114. */
  115. #define LIKE_TRUE 1
  116. #define LIKE_FALSE 0
  117. #define LIKE_ABORT -1
  118. /*--------------------
  119.  * Match text and p, return LIKE_TRUE, LIKE_FALSE, or LIKE_ABORT.
  120.  *
  121.  * LIKE_TRUE: they match
  122.  * LIKE_FALSE: they don't match
  123.  * LIKE_ABORT: not only don't they match, but the text is too short.
  124.  *
  125.  * If LIKE_ABORT is returned, then no suffix of the text can match the
  126.  * pattern either, so an upper-level % scan can stop scanning now.
  127.  *--------------------
  128.  */
  129. static int
  130. DoMatch(pg_wchar * text, pg_wchar * p)
  131. {
  132. for (; *p && *text; text++, p++)
  133. {
  134. switch (*p)
  135. {
  136. case '\':
  137. /* Literal match with following character. */
  138. p++;
  139. /* FALLTHROUGH */
  140. default:
  141. if (*text != *p)
  142. return LIKE_FALSE;
  143. break;
  144. case '_':
  145. /* Match any single character. */
  146. break;
  147. case '%':
  148. /* %% is the same as % according to the SQL standard */
  149. /* Advance past all %'s */
  150. while (*p == '%')
  151. p++;
  152. /* Trailing percent matches everything. */
  153. if (*p == '')
  154. return LIKE_TRUE;
  155. /* Otherwise, scan for a text position at which we
  156.  * can match the rest of the pattern.
  157.  */
  158. for (; *text; text++)
  159. {
  160. /* Optimization to prevent most recursion: don't recurse
  161.  * unless first pattern char might match this text char.
  162.  */
  163. if (*text == *p || *p == '\' || *p == '_')
  164. {
  165. int matched = DoMatch(text, p);
  166. if (matched != LIKE_FALSE)
  167. return matched; /* TRUE or ABORT */
  168. }
  169. }
  170. /* End of text with no match, so no point in trying later
  171.  * places to start matching this pattern.
  172.  */
  173. return LIKE_ABORT;
  174. }
  175. }
  176. if (*text != '')
  177. return LIKE_FALSE; /* end of pattern, but not of text */
  178. /* End of input string.  Do we have matching pattern remaining? */
  179. while (*p == '%') /* allow multiple %'s at end of pattern */
  180. p++;
  181. if (*p == '')
  182. return LIKE_TRUE;
  183. /* End of text with no match, so no point in trying later
  184.  * places to start matching this pattern.
  185.  */
  186. return LIKE_ABORT;
  187. }
  188. /*
  189. ** User-level routine.  Returns TRUE or FALSE.
  190. */
  191. static int
  192. like(pg_wchar * text, pg_wchar * p)
  193. {
  194. /* Fast path for match-everything pattern */
  195. if (p[0] == '%' && p[1] == '')
  196. return TRUE;
  197. return DoMatch(text, p) == LIKE_TRUE;
  198. }