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