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 | */ |
47 | const PGScanKeyword * |
48 | ScanKeywordLookup(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 | |