1/*--------------------------------------------------------------------
2 * Symbols referenced in this file:
3 * - ScanKeywords
4 * - NumScanKeywords
5 * - ScanKeywordLookup
6 *--------------------------------------------------------------------
7 */
8
9/*-------------------------------------------------------------------------
10 *
11 * keywords.c
12 * lexical token lookup for key words in PostgreSQL
13 *
14 *
15 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development PGGroup
16 * Portions Copyright (c) 1994, Regents of the University of California
17 *
18 *
19 * IDENTIFICATION
20 * src/common/keywords.c
21 *
22 *-------------------------------------------------------------------------
23 */
24#include "pg_functions.hpp"
25#include <string.h>
26
27#include "parser/gramparse.hpp"
28
29#include "parser/kwlist.hpp"
30
31
32/*
33 * ScanKeywordLookup - see if a given word is a keyword
34 *
35 * The table to be searched is passed explicitly, so that this can be used
36 * to search keyword lists other than the standard list appearing above.
37 *
38 * Returns a pointer to the PGScanKeyword table entry, or NULL if no match.
39 *
40 * The match is done case-insensitively. Note that we deliberately use a
41 * dumbed-down case conversion that will only translate 'A'-'Z' into 'a'-'z',
42 * even if we are in a locale where tolower() would produce more or different
43 * translations. This is to conform to the SQL99 spec, which says that
44 * keywords are to be matched in this way even though non-keyword identifiers
45 * receive a different case-normalization mapping.
46 */
47const PGScanKeyword *
48ScanKeywordLookup(const char *text,
49 const PGScanKeyword *keywords,
50 int num_keywords)
51{
52 int len,
53 i;
54 char word[NAMEDATALEN];
55 const PGScanKeyword *low;
56 const PGScanKeyword *high;
57
58 len = strlen(text);
59 /* We assume all keywords are shorter than NAMEDATALEN. */
60 if (len >= NAMEDATALEN)
61 return NULL;
62
63 /*
64 * Apply an ASCII-only downcasing. We must not use tolower() since it may
65 * produce the wrong translation in some locales (eg, Turkish).
66 */
67 for (i = 0; i < len; i++)
68 {
69 char ch = text[i];
70
71 if (ch >= 'A' && ch <= 'Z')
72 ch += 'a' - 'A';
73 word[i] = ch;
74 }
75 word[len] = '\0';
76
77 /*
78 * Now do a binary search using plain strcmp() comparison.
79 */
80 low = keywords;
81 high = keywords + (num_keywords - 1);
82 while (low <= high)
83 {
84 const PGScanKeyword *middle;
85 int difference;
86
87 middle = low + (high - low) / 2;
88 difference = strcmp(middle->name, word);
89 if (difference == 0)
90 return middle;
91 else if (difference < 0)
92 low = middle + 1;
93 else
94 high = middle - 1;
95 }
96
97 return NULL;
98}
99