/*------------------------------------------------------------------------- * * like.c-- * like expression handling code. * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * /usr/local/devel/pglite/cvs/src/backend/utils/adt/like.c,v 1.1 1995/07/30 23:55:36 emkxp01 Exp * * * NOTES * A big hack of the regexp.c code!! Contributed by * Keith Parks (7/95). * * *------------------------------------------------------------------------- */ #include #include "postgres.h" /* postgres system include file */ #include "utils/palloc.h" #include "utils/builtins.h" /* where the function declarations go */ /* * interface routines called by the function manager */ /* fixedlen_like: a generic fixed length like routine s - the string to match against (not necessarily null-terminated) p - the pattern charlen - the length of the string */ static bool fixedlen_like(char *s, struct varlena* p, int charlen) { char *sterm, *pterm; int result; if (!s || !p) return FALSE; /* be sure sterm is null-terminated */ sterm = (char *) palloc(charlen + 1); strNcpy(sterm, s, charlen); /* p is a text = varlena, not a string so we have to make * a string from the vl_data field of the struct. */ /* palloc the length of the text + the null character */ pterm = (char *) palloc(VARSIZE(p) - VARHDRSZ + 1); memmove(pterm, VARDATA(p), VARSIZE(p) - VARHDRSZ); *(pterm + VARSIZE(p) - VARHDRSZ) = (char)NULL; /* do the regexp matching */ result = like(sterm, pterm); pfree(sterm); pfree(pterm); return ((bool) result); } bool char2like(uint16 arg1, struct varlena *p) { char *s = (char *) &arg1; return (fixedlen_like(s, p, 2)); } bool char2nlike(uint16 arg1, struct varlena *p) { return (!char2like(arg1, p)); } bool char4like(uint32 arg1, struct varlena *p) { char *s = (char *) &arg1; return (fixedlen_like(s, p, 4)); } bool char4nlike(uint32 arg1, struct varlena *p) { return (!char4like(arg1, p)); } bool char8like(char *s, struct varlena *p) { return (fixedlen_like(s, p, 8)); } bool char8nlike(char *s, struct varlena *p) { return (!char8like(s, p)); } bool char16like(char *s, struct varlena *p) { return (fixedlen_like(s, p, 16)); } bool char16nlike(char *s, struct varlena *p) { return (!char16like(s, p)); } bool namelike(NameData *n, struct varlena *p) { if (!n) return FALSE; return (fixedlen_like(n->data, p, NAMEDATALEN)); } bool namenlike(NameData *s, struct varlena *p) { return (!namelike(s, p)); } bool textlike(struct varlena *s, struct varlena *p) { if (!s) return FALSE; return (fixedlen_like(VARDATA(s), p, VARSIZE(s) - VARHDRSZ)); } bool textnlike(struct varlena *s, struct varlena *p) { return (!textlike(s, p)); } /* $Revision: 1.5 $ ** "like.c" A first attempt at a LIKE operator for Postgres95. ** ** Originally written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986. ** Rich $alz is now . ** Special thanks to Lars Mathiesen for the LABORT code. ** ** This code was shamelessly stolen from the "pql" code by myself and ** slightly modified :) ** ** All references to the word "star" were replaced by "percent" ** All references to the word "wild" were replaced by "like" ** ** All the nice shell RE matching stuff was replaced by just "_" and "%" ** ** As I don't have a copy of the SQL standard handy I wasn't sure whether ** to leave in the '\' escape character handling. (I suspect the standard ** handles "%%" as a single literal percent) ** ** Keith Parks. ** ** [SQL92 lets you specify the escape character by saying ** LIKE ESCAPE . We are a small operation ** so we force you to use '\'. - ay 7/95] ** */ #define LIKE_TRUE 1 #define LIKE_FALSE 0 #define LIKE_ABORT -1 /* ** Match text and p, return LIKE_TRUE, LIKE_FALSE, or LIKE_ABORT. */ static int DoMatch(register char *text, register char *p) { register int matched; for ( ; *p; text++, p++) { if (*text == '\0' && *p != '%') return LIKE_ABORT; switch (*p) { case '\\': /* Literal match with following character. */ p++; /* FALLTHROUGH */ default: if (*text != *p) return LIKE_FALSE; continue; case '_': /* Match anything. */ continue; case '%': while (*++p == '%') /* Consecutive percents act just like one. */ continue; if (*p == '\0') /* Trailing percent matches everything. */ return LIKE_TRUE; while (*text) if ((matched = DoMatch(text++, p)) != LIKE_FALSE) return matched; return LIKE_ABORT; } } return *text == '\0'; } /* ** User-level routine. Returns TRUE or FALSE. */ int like(char *text, char *p) { if (p[0] == '%' && p[1] == '\0') return TRUE; return (DoMatch(text, p) == LIKE_TRUE); }