[GRASS5] sql expression weirdnesses

Glynn Clements glynn at gclements.plus.com
Mon Jun 6 23:39:41 EDT 2005


Daniel Calvelo Aros wrote:

> I'm baffled by the following:
> 
> <session>
> GRASS 6.0.0 (pe):~/t/ > db.select dist2002 sql="select cat from dist2002 where
> (ALT_DIST < 500)" |wc #Ok.
>      421     421    1809
> GRASS 6.0.0 (pe):~/t/ > db.select dist2002 sql="select cat from dist2002 where
> (ALT_DIST/2+ALT_DIST/2 < 500)" |wc #Ooops.
>     1829    1829    8033
> GRASS 6.0.0 (pe):~/t/ > db.select dist2002 sql="select cat from dist2002 where
> (ALT_DIST*2 < 1000)" |wc #Ok
>      421     421    1809
> GRASS 6.0.0 (pe):~/t/ > db.select dist2002 sql="select cat from dist2002 where
> (ALT_DIST+ALT_DIST < 1000)" |wc #Still ok.
>      421     421    1809
> GRASS 6.0.0 (pe):~/t/ > db.select dist2002 sql="select cat from dist2002 where
> (ALT_DIST+ALT_DIST/2 < 750)" |wc #Still ok.
>      421     421    1809
> GRASS 6.0.0 (pe):~/t/ > db.select dist2002 sql="select cat from dist2002 where
> (ALT_DIST/2+ALT_DIST < 750)" |wc #Ooops. Non-commuting sum
>     1829    1829    8033
> GRASS 6.0.0 (pe):~/t/ > db.select dist2002 sql="select cat from dist2002 where
> ((ALT_DIST/2)+ALT_DIST < 750)" |wc #Puzzled...
> DBMI-DBF driver error:
> SQL parser error in statement:
> select cat from dist2002 where ((ALT_DIST/2)+ALT_DIST < 750)
> Error in db_open_select_cursor()
> 
>        0       0       0
> </session>
> 
> Is there a (hopefully documented) limitation in the sql parser that provokes
> these things? Is it some NULL-related weirdness?

The SQL parser doesn't implement the normal precedence rules for
arithmetic operators, so e.g.:

	(ALT_DIST/2+ALT_DIST/2 < 500)

parses as:

	((((ALT_DIST/2)+ALT_DIST)/2) < 500)

Also, it doesn't allow parentheses within arithmetic expressions, only
logical (boolean) expressions.

I don't have a copy of the SQL standard, but I'm pretty sure that both
of those are bugs.

At a glance, I would guess that the y_expression rule at the bottom of
lib/db/sqlp/yac.y should be split into something like:

y_expression:
		y_product			{ $$ = $1; }
	|	y_expression '+' y_product {
		    $$ = sqpNewExpressionNode ( sqpOperatorCode("+"), $1, $3 );
		}
	|	y_expression '-' y_product {
		    $$ = sqpNewExpressionNode ( sqpOperatorCode("-"), $1, $3 );
		}
	;

y_product:
		y_atom				{ $$ = $1; }
	|	y_expression '*' y_atom {
		    $$ = sqpNewExpressionNode ( sqpOperatorCode("*"), $1, $3 );
		}
	|	y_expression '/' y_atom {
		    $$ = sqpNewExpressionNode ( sqpOperatorCode("/"), $1, $3 );
		}
	;

y_atom:
		y_value				{ $$ = $1; }
	|	y_column			{ $$ = $1; }
	|	'(' y_expression ')'		{ $$ = $2; }
	;

Also the ARITHMETICAL_OPERATOR token would need to be removed from
lex.l and yac.y, as its current definition makes it impossible to
treat / differently to + and -.

This gives * and / precedence of over + and -, forces
left-associativity, and allows parenthesised expressions.

-- 
Glynn Clements <glynn at gclements.plus.com>




More information about the grass-dev mailing list