34
42
43:-module(sql_tokenizer,
44 [sql_tokens//1]). 45
46:-use_module(library(cql/cql), [sql_gripe/3]). 47
49sql_tokens([], [], []):- !.
50sql_tokens([Token|Tokens])-->
51 optional_whitespace,
52 sql_token(Token),
53 optional_whitespace,
54 sql_tokens(Tokens).
55
56optional_whitespace-->
57 char_in(_, " \t\n\r"),
58 !,
59 optional_whitespace.
60optional_whitespace--> [].
61
63
64:- if(current_prolog_flag(double_quotes,string)). 65:- multifile check:valid_string_goal/1. 66check:valid_string_goal(sql_tokenizer:read_until(S,_,_,_)) :- string(S).
67
68read_until(Terminator, Codes) -->
69 { string_codes(Terminator, List)
70 },
71 read_until_(List, Codes).
72:- else. 73read_until(Terminator, Codes) -->
74 read_until_(Terminator, Codes).
75:- endif. 76
77read_until_(_, [], [], []).
78read_until_(Terminator, [])-->
79 Terminator, !.
80read_until_(Terminator, [Code|Codes])-->
81 [Code],
82 read_until_(Terminator, Codes).
83
84
85numeric_codes([Code|Codes])-->
86 char_in(Code, "0123456789."),
87 !,
88 numeric_codes(Codes).
89numeric_codes([])--> [], !.
97char_in(Code, Set) -->
98 [Code],
99 { code_in_set(Code, Set) }.
100
101:- if(current_prolog_flag(double_quotes,string)). 102:- multifile check:valid_string_goal/1. 103
104check:valid_string_goal(sql_tokenizer:char_in(_,S,_,_)) :- string(S).
105check:valid_string_goal(sql_tokenizer:code_in_set(_,S)) :- string(S).
106
107code_in_set(Code, Set) :-
108 string_code(_, Set, Code), !.
109
110:- else. 111
112code_in_set(Code, Set) :-
113 memberchk(Code, Set).
114
115:- endif. 116
117quoted_literal([39|Codes], [39, 39|In], Out):-
118 !,
119 quoted_literal(Codes, In, Out).
120quoted_literal([], [39|In], In):-!.
121quoted_literal([Code|Codes])-->
122 [Code],
123 quoted_literal(Codes).
124
125
126sql_token(comment(long, Codes))-->
127 "/*", !, read_until("*/", Codes).
128
129sql_token(comment(short, Codes))-->
130 "--", !, read_until("\n", Codes).
131
133sql_token('=')--> "=", !.
134sql_token('<>')--> "!=", !, {sql_gripe(1,'The not-equals operator in SQL is <> and not !=', [])}.
135sql_token('<>')--> "! =", !, {sql_gripe(1,'The not-equals operator in SQL is <> and not ! =', [])}.
137sql_token('>=')--> "! <", !, {sql_gripe(1,'The greater-than-or-equal-to operator in SQL is >= and not ! <', [])}.
138sql_token('>=')--> "!<", !, {sql_gripe(1,'The greater-than-or-equal-to operator in SQL is >= and not !<', [])}.
139sql_token('<=')--> "!>", !, {sql_gripe(1,'The less-than-or-equal-to operator in SQL is <= and not !>', [])}.
140sql_token('<=')--> "! >", !, {sql_gripe(1,'The less-than-or-equal-to operator in SQL is <= and not ! >', [])}.
141sql_token('<>')--> "<>", !.
142sql_token('>=')--> ">=", !.
143sql_token('<=')--> "<=", !.
144sql_token('<')--> "<", !.
145sql_token('>')--> ">", !.
146sql_token('.')--> ".", !.
147sql_token(',')--> ",", !.
148sql_token('(')--> "(", !.
149sql_token(')')--> ")", !.
150sql_token('/')--> "/", !.
151sql_token('+')--> "+", !.
152sql_token('*')--> "*", !.
153sql_token('-')--> "-", !.
154sql_token('{')--> "{", !.
155sql_token('}')--> "}", !.
156
157
158sql_token(literal(Literal, string))-->
159 "'",
160 !,
161 quoted_literal(Codes),
162 {atom_codes(Literal, Codes)}.
163
164
165sql_token(literal(Literal, identifier))-->
166 "\"",
167 !,
168 read_until("\"", Codes),
169 {atom_codes(Literal, Codes)}.
170
173sql_token(literal(Literal, Type))-->
174 char_in(Code, "0123456789"),
175 !,
176 numeric_codes(Codes),
177 {number_codes(Literal, [Code|Codes])},
178 {(integer(Literal)->
179 length(Codes, L),
180 LL is L+1,
181 ( LL > 10->
182 Type = decimal(LL, 0)
183 ; otherwise->
184 Type = int(LL)
185 )
186 ; Code == 0'0, Codes = [0'.|_]->
187 188 length(Codes, L),
189 P is L - 1,
190 Type = decimal(P, P)
191 ; otherwise->
192 nth1(P, Codes, 0'.), 193
194 length(Codes, L),
195 S is L - P,
196 PP is P + S,
197 Type = decimal(PP, S)
198 )}.
199
200sql_token(literal(Literal, identifier))-->
201 "[",
202 !,
203 read_until("]", Codes),
204 {atom_codes(Literal, Codes)}.
205
206sql_token(Token)-->
207 !,
208 sql_token_1(Codes),
209 {atom_codes(Token, Codes)}.
210
211sql_token_1([], [], []):- !.
214sql_token_1([], [Terminator|Codes], [Terminator|Codes]):-
215 code_in_set(Terminator, ".,()*+-/<=> \t\n\r"), !.
216
218sql_token_1([Code|Codes])-->
219 [Code],
220 sql_token_1(Codes)