1
2 /*****************************************************************************
3 *
4 * MODULE: SQL statement parser library
5 *
6 * AUTHOR(S): lex.l and yac.y were originally taken from unixODBC and
7 * probably written by Peter Harvey <pharvey@codebydesigns.com>,
8 * original modifications & added code by
9 * Radim Blazek <radim.blazek gmail.com>
10 * Glynn Clements <glynn gclements.plus.com>,
11 * Markus Neteler <neteler itc.it>,
12 * Martin Landa <landa.martin gmail.com>,
13 * Moritz Lennert <mlennert club.worldonline.be>,
14 * Hamish Bowman <hamish_b yahoo.com>,
15 * Daniel Calvelo Aros <dca.gis gmail.com>,
16 * Paul Kelly <paul-grass stjohnspoint.co.uk>,
17 * Alex Shevlakov <sixote yahoo.com>
18 *
19 * PURPOSE: Parse input string containing SQL statement to
20 * SQLPSTMT structure.
21 * SQL parser may be used by simple database drivers.
22 *
23 * COPYRIGHT: (C) 2000-2007 by the GRASS Development Team
24 *
25 * This program is free software under the GNU General Public
26 * License (>=v2). Read the file COPYING that comes with GRASS
27 * for details.
28 *
29 *****************************************************************************/
30
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <assert.h>
36 #include <grass/sqlp.h>
37
38 SQLPSTMT *sqlpStmt;
39
40 /* save string to value */
sqpSaveStr(SQLPVALUE * val,char * c)41 int sqpSaveStr(SQLPVALUE * val, char *c)
42 {
43 int len = 0;
44
45 len = strlen(c) + 1;
46 val->s = (char *)realloc(val->s, len);
47
48 strcpy(val->s, c);
49
50 return (1);
51 }
52
sqpInitValue(SQLPVALUE * val)53 void sqpInitValue(SQLPVALUE * val)
54 {
55 val->type = SQLP_NULL;
56 val->s = NULL;
57 val->i = 0;
58 val->d = 0.0;
59 }
60
sqpCopyValue(SQLPVALUE * from,SQLPVALUE * to)61 void sqpCopyValue(SQLPVALUE * from, SQLPVALUE * to)
62 {
63 to->type = from->type;
64
65 if (to->s)
66 free(to->s);
67
68 if (from->s)
69 to->s = strdup(from->s);
70
71 to->i = from->i;
72 to->d = from->d;
73 }
74
sqpInitParser(SQLPSTMT * st)75 int sqpInitParser(SQLPSTMT * st)
76 {
77 sqlpStmt = st;
78 sqlpStmt->cur = sqlpStmt->stmt;
79
80 sqlpStmt->errmsg[0] = '\0';
81 sqlpStmt->table[0] = '\0';
82 sqlpStmt->nCol = 0;
83 sqlpStmt->nVal = 0;
84 sqlpStmt->upperNodeptr = NULL;
85 sqlpStmt->orderCol = NULL;
86
87 return (1);
88 }
89
sqpCommand(int command)90 void sqpCommand(int command)
91 {
92 sqlpStmt->command = command;
93 return;
94 }
95
sqpTable(char * tbl)96 void sqpTable(char *tbl)
97 {
98 strncpy(sqlpStmt->table, tbl, SQLP_MAX_TABLE);
99 return;
100 }
101
sqpColumn(char * col)102 void sqpColumn(char *col)
103 {
104 int i;
105
106 i = sqlpStmt->nCol;
107 sqpAllocCol(sqlpStmt, i + 1);
108 sqpSaveStr(&(sqlpStmt->Col[i]), col);
109
110 sqlpStmt->nCol++;
111 return;
112 }
113
sqpColumnDef(char * col,int type,int width,int decimals)114 void sqpColumnDef(char *col, int type, int width, int decimals)
115 {
116 int i;
117
118 i = sqlpStmt->nCol;
119 sqpAllocCol(sqlpStmt, i + 1);
120 sqpSaveStr(&(sqlpStmt->Col[i]), col);
121 sqlpStmt->ColType[i] = type;
122 sqlpStmt->ColWidth[i] = width;
123 sqlpStmt->ColDecim[i] = decimals;
124
125 sqlpStmt->nCol++;
126 return;
127 }
128
sqpValue(char * strval,int intval,double dblval,int type)129 void sqpValue(char *strval, int intval, double dblval, int type)
130 {
131 int i;
132
133 i = sqlpStmt->nVal;
134
135 /* allocate space for cols because if in INSERT cols were not
136 * specified array for ColNum would not be allocated */
137 sqpAllocCol(sqlpStmt, i + 1);
138
139 sqpAllocVal(sqlpStmt, i + 1);
140 sqlpStmt->Val[i].s = NULL;
141 sqlpStmt->Val[i].i = 0; /* not necessay I think */
142 sqlpStmt->Val[i].d = 0.0; /* not necessay I think */
143
144 sqlpStmt->Val[i].type = type;
145 switch (type) {
146 case (SQLP_S):
147 sqpSaveStr(&(sqlpStmt->Val[i]), strval);
148 break;
149 case (SQLP_I):
150 sqlpStmt->Val[i].i = intval;
151 break;
152 case (SQLP_D):
153 sqlpStmt->Val[i].d = dblval;
154 break;
155 /* SQLP_NULL, nothing to do */
156 }
157
158 sqlpStmt->nVal++;
159 return;
160 }
161
sqpAssignment(char * col,char * strval,int intval,double dblval,SQLPNODE * expval,int type)162 void sqpAssignment(char *col, char *strval, int intval, double dblval,
163 SQLPNODE * expval, int type)
164 {
165 int i;
166
167 i = sqlpStmt->nCol;
168
169 sqpAllocCol(sqlpStmt, i + 1);
170 sqpSaveStr(&(sqlpStmt->Col[i]), col);
171
172 sqpAllocVal(sqlpStmt, i + 1);
173 sqlpStmt->Val[i].s = NULL;
174 sqlpStmt->Val[i].i = 0; /* not necessay I think */
175 sqlpStmt->Val[i].d = 0.0; /* not necessay I think */
176
177 sqlpStmt->Val[i].type = type;
178 switch (type) {
179 case (SQLP_S):
180 sqpSaveStr(&(sqlpStmt->Val[i]), strval);
181 break;
182 case (SQLP_I):
183 sqlpStmt->Val[i].i = intval;
184 break;
185 case (SQLP_D):
186 sqlpStmt->Val[i].d = dblval;
187 break;
188 case (SQLP_EXPR):
189 sqlpStmt->Val[i].expr = expval;
190 /* Don't do anything right now; come back to this when executing */
191 break;
192 /* SQLP_NULL, nothing to do */
193 }
194
195 sqlpStmt->nCol++;
196 sqlpStmt->nVal++;
197 return;
198 }
199
sqpOrderColumn(char * col,int dir)200 void sqpOrderColumn(char *col, int dir)
201 {
202 sqlpStmt->orderCol = (char *)realloc(sqlpStmt->orderCol, strlen(col) + 1);
203 strcpy(sqlpStmt->orderCol, col);
204 sqlpStmt->orderDir = dir;
205 return;
206 }
207
208 /* Create and init new node */
sqpNewNode(void)209 SQLPNODE *sqpNewNode(void)
210 {
211 SQLPNODE *np;
212
213 np = (SQLPNODE *) calloc(1, sizeof(SQLPNODE));
214 return np;
215 }
216
sqpNewExpressionNode(int oper,SQLPNODE * left,SQLPNODE * right)217 SQLPNODE *sqpNewExpressionNode(int oper, SQLPNODE * left, SQLPNODE * right)
218 {
219 SQLPNODE *np;
220
221 np = sqpNewNode();
222
223 np->node_type = SQLP_NODE_EXPRESSION;
224 np->oper = oper;
225 np->left = left;
226 np->right = right;
227
228 return np;
229 }
230
sqpNewColumnNode(char * name)231 SQLPNODE *sqpNewColumnNode(char *name)
232 {
233 SQLPNODE *np;
234
235 np = sqpNewNode();
236
237 np->node_type = SQLP_NODE_COLUMN;
238 np->column_name = strdup(name);
239
240 return np;
241 }
242
sqpNewValueNode(char * strval,int intval,double dblval,int type)243 SQLPNODE *sqpNewValueNode(char *strval, int intval, double dblval, int type)
244 {
245 SQLPNODE *np;
246
247 np = sqpNewNode();
248
249 np->node_type = SQLP_NODE_VALUE;
250
251 np->value.type = type;
252 if (strval)
253 np->value.s = strdup(strval);
254 np->value.i = intval;
255 np->value.d = dblval;
256
257 return np;
258 }
259
sqpFreeNode(SQLPNODE * np)260 void sqpFreeNode(SQLPNODE * np)
261 {
262 if (!np)
263 return;
264
265 if (np->left)
266 sqpFreeNode(np->left);
267
268 if (np->right)
269 sqpFreeNode(np->right);
270
271 if (np->column_name)
272 free(np->column_name);
273
274 if (np->value.s)
275 free(np->value.s);
276
277 free(np);
278 }
279
sqpOperatorCode(char * oper)280 int sqpOperatorCode(char *oper)
281 {
282 char *tmp, *ptr;
283
284 /* Convert to lower case */
285 tmp = strdup(oper);
286 ptr = tmp;
287 while (*ptr) {
288 *ptr = tolower(*ptr);
289 ptr++;
290 }
291
292 if (strcmp(oper, "=") == 0)
293 return SQLP_EQ;
294 else if (strcmp(oper, "<") == 0)
295 return SQLP_LT;
296 else if (strcmp(oper, "<=") == 0)
297 return SQLP_LE;
298 else if (strcmp(oper, ">") == 0)
299 return SQLP_GT;
300 else if (strcmp(oper, ">=") == 0)
301 return SQLP_GE;
302 else if (strcmp(oper, "<>") == 0)
303 return SQLP_NE;
304 else if (strcmp(oper, "~") == 0)
305 return SQLP_MTCH;
306 else if (strcmp(oper, "+") == 0)
307 return SQLP_ADD;
308 else if (strcmp(oper, "-") == 0)
309 return SQLP_SUBTR;
310 else if (strcmp(oper, "*") == 0)
311 return SQLP_MLTP;
312 else if (strcmp(oper, "/") == 0)
313 return SQLP_DIV;
314 else if (strcmp(oper, "and") == 0)
315 return SQLP_AND;
316 else if (strcmp(oper, "or") == 0)
317 return SQLP_OR;
318 else if (strcmp(oper, "not") == 0)
319 return SQLP_NOT;
320
321 free(tmp);
322
323 return 0;
324 }
325
sqpOperatorName(int oper)326 char *sqpOperatorName(int oper)
327 {
328 switch (oper) {
329 case SQLP_EQ:
330 return "=";
331 break;
332 case SQLP_LT:
333 return "<";
334 break;
335 case SQLP_LE:
336 return "<=";
337 break;
338 case SQLP_GT:
339 return ">";
340 break;
341 case SQLP_GE:
342 return ">=";
343 break;
344 case SQLP_NE:
345 return "<>";
346 break;
347 case SQLP_MTCH:
348 return "~";
349 break;
350 case SQLP_ADD:
351 return "+";
352 break;
353 case SQLP_SUBTR:
354 return "-";
355 break;
356 case SQLP_MLTP:
357 return "*";
358 break;
359 case SQLP_DIV:
360 return "/";
361 break;
362 case SQLP_AND:
363 return "AND";
364 break;
365 case SQLP_OR:
366 return "OR";
367 break;
368 case SQLP_NOT:
369 return "NOT";
370 break;
371 }
372 return "?";
373 }
374