improved sql parser for postgresql

This commit is contained in:
wenshao
2014-11-16 17:43:03 +08:00
parent 8e6dbe121b
commit 39bb9e2d7f
17 changed files with 740 additions and 1 deletions
@@ -0,0 +1,56 @@
package com.alibaba.druid.sql.dialect.postgresql.ast.expr;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGASTVisitor;
public class PGCidrExpr extends PGExprImpl {
private SQLExpr value;
public SQLExpr getValue() {
return value;
}
public void setValue(SQLExpr value) {
this.value = value;
}
@Override
public void accept0(PGASTVisitor visitor) {
if (visitor.visit(this)) {
acceptChild(visitor, value);
}
visitor.endVisit(this);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
PGCidrExpr other = (PGCidrExpr) obj;
if (value == null) {
if (other.value != null) {
return false;
}
} else if (!value.equals(other.value)) {
return false;
}
return true;
}
}
@@ -0,0 +1,56 @@
package com.alibaba.druid.sql.dialect.postgresql.ast.expr;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGASTVisitor;
public class PGCircleExpr extends PGExprImpl {
private SQLExpr value;
public SQLExpr getValue() {
return value;
}
public void setValue(SQLExpr value) {
this.value = value;
}
@Override
public void accept0(PGASTVisitor visitor) {
if (visitor.visit(this)) {
acceptChild(visitor, value);
}
visitor.endVisit(this);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
PGCircleExpr other = (PGCircleExpr) obj;
if (value == null) {
if (other.value != null) {
return false;
}
} else if (!value.equals(other.value)) {
return false;
}
return true;
}
}
@@ -0,0 +1,56 @@
package com.alibaba.druid.sql.dialect.postgresql.ast.expr;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGASTVisitor;
public class PGInetExpr extends PGExprImpl {
private SQLExpr value;
public SQLExpr getValue() {
return value;
}
public void setValue(SQLExpr value) {
this.value = value;
}
@Override
public void accept0(PGASTVisitor visitor) {
if (visitor.visit(this)) {
acceptChild(visitor, value);
}
visitor.endVisit(this);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
PGInetExpr other = (PGInetExpr) obj;
if (value == null) {
if (other.value != null) {
return false;
}
} else if (!value.equals(other.value)) {
return false;
}
return true;
}
}
@@ -0,0 +1,56 @@
package com.alibaba.druid.sql.dialect.postgresql.ast.expr;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGASTVisitor;
public class PGLineSegmentsExpr extends PGExprImpl {
private SQLExpr value;
public SQLExpr getValue() {
return value;
}
public void setValue(SQLExpr value) {
this.value = value;
}
@Override
public void accept0(PGASTVisitor visitor) {
if (visitor.visit(this)) {
acceptChild(visitor, value);
}
visitor.endVisit(this);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
PGLineSegmentsExpr other = (PGLineSegmentsExpr) obj;
if (value == null) {
if (other.value != null) {
return false;
}
} else if (!value.equals(other.value)) {
return false;
}
return true;
}
}
@@ -0,0 +1,58 @@
package com.alibaba.druid.sql.dialect.postgresql.ast.expr;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGASTVisitor;
public class PGMacAddrExpr extends PGExprImpl {
private SQLExpr value;
public SQLExpr getValue() {
return value;
}
public void setValue(SQLExpr value) {
this.value = value;
}
@Override
public void accept0(PGASTVisitor visitor) {
if (visitor.visit(this)) {
acceptChild(visitor, value);
}
visitor.endVisit(this);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
PGMacAddrExpr other = (PGMacAddrExpr) obj;
if (value == null) {
if (other.value != null) {
return false;
}
} else if (!value.equals(other.value)) {
return false;
}
return true;
}
}
@@ -0,0 +1,58 @@
package com.alibaba.druid.sql.dialect.postgresql.ast.expr;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGASTVisitor;
public class PGPolygonExpr extends PGExprImpl {
private SQLExpr value;
public SQLExpr getValue() {
return value;
}
public void setValue(SQLExpr value) {
this.value = value;
}
@Override
public void accept0(PGASTVisitor visitor) {
if (visitor.visit(this)) {
acceptChild(visitor, value);
}
visitor.endVisit(this);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
PGPolygonExpr other = (PGPolygonExpr) obj;
if (value == null) {
if (other.value != null) {
return false;
}
} else if (!value.equals(other.value)) {
return false;
}
return true;
}
}
@@ -25,12 +25,17 @@ import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.PGOrderBy;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGArrayExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGBoxExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGCidrExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGCircleExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGDateField;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGExtractExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGInetExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGLineSegmentsExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGMacAddrExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGPointExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGPolygonExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGTypeCastExpr;
import com.alibaba.druid.sql.parser.Lexer;
import com.alibaba.druid.sql.parser.ParserException;
import com.alibaba.druid.sql.parser.SQLExprParser;
import com.alibaba.druid.sql.parser.Token;
import com.alibaba.druid.util.JdbcConstants;
@@ -181,6 +186,36 @@ public class PGExprParser extends SQLExprParser {
PGBoxExpr box = new PGBoxExpr();
box.setValue(value);
return primaryRest(box);
} else if ("macaddr".equalsIgnoreCase(ident)) {
SQLExpr value = this.primary();
PGMacAddrExpr macaddr = new PGMacAddrExpr();
macaddr.setValue(value);
return primaryRest(macaddr);
} else if ("inet".equalsIgnoreCase(ident)) {
SQLExpr value = this.primary();
PGInetExpr inet = new PGInetExpr();
inet.setValue(value);
return primaryRest(inet);
} else if ("cidr".equalsIgnoreCase(ident)) {
SQLExpr value = this.primary();
PGCidrExpr cidr = new PGCidrExpr();
cidr.setValue(value);
return primaryRest(cidr);
} else if ("polygon".equalsIgnoreCase(ident)) {
SQLExpr value = this.primary();
PGPolygonExpr polygon = new PGPolygonExpr();
polygon.setValue(value);
return primaryRest(polygon);
} else if ("circle".equalsIgnoreCase(ident)) {
SQLExpr value = this.primary();
PGCircleExpr circle = new PGCircleExpr();
circle.setValue(value);
return primaryRest(circle);
} else if ("lseg".equalsIgnoreCase(ident)) {
SQLExpr value = this.primary();
PGLineSegmentsExpr lseg = new PGLineSegmentsExpr();
lseg.setValue(value);
return primaryRest(lseg);
}
}
@@ -19,9 +19,15 @@ import com.alibaba.druid.sql.dialect.postgresql.ast.PGWithClause;
import com.alibaba.druid.sql.dialect.postgresql.ast.PGWithQuery;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGArrayExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGBoxExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGCidrExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGCircleExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGExtractExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGInetExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGLineSegmentsExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGMacAddrExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGParameter;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGPointExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGPolygonExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGTypeCastExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGDeleteStatement;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGFunctionTableSource;
@@ -109,5 +115,29 @@ public interface PGASTVisitor extends SQLASTVisitor {
void endVisit(PGPointExpr x);
boolean visit(PGPointExpr x);
void endVisit(PGMacAddrExpr x);
boolean visit(PGMacAddrExpr x);
void endVisit(PGInetExpr x);
boolean visit(PGInetExpr x);
void endVisit(PGCidrExpr x);
boolean visit(PGCidrExpr x);
void endVisit(PGPolygonExpr x);
boolean visit(PGPolygonExpr x);
void endVisit(PGCircleExpr x);
boolean visit(PGCircleExpr x);
void endVisit(PGLineSegmentsExpr x);
boolean visit(PGLineSegmentsExpr x);
}
@@ -19,9 +19,15 @@ import com.alibaba.druid.sql.dialect.postgresql.ast.PGWithClause;
import com.alibaba.druid.sql.dialect.postgresql.ast.PGWithQuery;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGArrayExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGBoxExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGCidrExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGCircleExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGExtractExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGInetExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGLineSegmentsExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGMacAddrExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGParameter;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGPointExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGPolygonExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGTypeCastExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGDeleteStatement;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGFunctionTableSource;
@@ -232,5 +238,65 @@ public class PGASTVisitorAdapter extends SQLASTVisitorAdapter implements PGASTVi
public boolean visit(PGPointExpr x) {
return true;
}
@Override
public void endVisit(PGMacAddrExpr x) {
}
@Override
public boolean visit(PGMacAddrExpr x) {
return true;
}
@Override
public void endVisit(PGInetExpr x) {
}
@Override
public boolean visit(PGInetExpr x) {
return true;
}
@Override
public void endVisit(PGCidrExpr x) {
}
@Override
public boolean visit(PGCidrExpr x) {
return true;
}
@Override
public void endVisit(PGPolygonExpr x) {
}
@Override
public boolean visit(PGPolygonExpr x) {
return true;
}
@Override
public void endVisit(PGCircleExpr x) {
}
@Override
public boolean visit(PGCircleExpr x) {
return true;
}
@Override
public void endVisit(PGLineSegmentsExpr x) {
}
@Override
public boolean visit(PGLineSegmentsExpr x) {
return true;
}
}
@@ -22,9 +22,15 @@ import com.alibaba.druid.sql.dialect.postgresql.ast.PGWithClause;
import com.alibaba.druid.sql.dialect.postgresql.ast.PGWithQuery;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGArrayExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGBoxExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGCidrExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGCircleExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGExtractExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGInetExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGLineSegmentsExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGMacAddrExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGParameter;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGPointExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGPolygonExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGTypeCastExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGDeleteStatement;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGFunctionTableSource;
@@ -567,4 +573,76 @@ public class PGOutputVisitor extends SQLASTOutputVisitor implements PGASTVisitor
public void endVisit(PGPointExpr x) {
}
@Override
public boolean visit(PGMacAddrExpr x) {
print("macaddr ");
x.getValue().accept(this);
return false;
}
@Override
public void endVisit(PGMacAddrExpr x) {
}
@Override
public boolean visit(PGInetExpr x) {
print("inet ");
x.getValue().accept(this);
return false;
}
@Override
public void endVisit(PGInetExpr x) {
}
@Override
public boolean visit(PGCidrExpr x) {
print("cidr ");
x.getValue().accept(this);
return false;
}
@Override
public void endVisit(PGCidrExpr x) {
}
@Override
public boolean visit(PGPolygonExpr x) {
print("polygon ");
x.getValue().accept(this);
return false;
}
@Override
public void endVisit(PGPolygonExpr x) {
}
@Override
public boolean visit(PGCircleExpr x) {
print("circle ");
x.getValue().accept(this);
return false;
}
@Override
public void endVisit(PGCircleExpr x) {
}
@Override
public boolean visit(PGLineSegmentsExpr x) {
print("lseg ");
x.getValue().accept(this);
return false;
}
@Override
public void endVisit(PGLineSegmentsExpr x) {
}
}
@@ -25,9 +25,15 @@ import com.alibaba.druid.sql.dialect.postgresql.ast.PGWithClause;
import com.alibaba.druid.sql.dialect.postgresql.ast.PGWithQuery;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGArrayExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGBoxExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGCidrExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGCircleExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGExtractExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGInetExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGLineSegmentsExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGMacAddrExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGParameter;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGPointExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGPolygonExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGTypeCastExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGDeleteStatement;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGFunctionTableSource;
@@ -338,6 +344,66 @@ public class PGSchemaStatVisitor extends SchemaStatVisitor implements PGASTVisit
}
@Override
public boolean visit(PGMacAddrExpr x) {
return true;
}
@Override
public void endVisit(PGMacAddrExpr x) {
}
@Override
public boolean visit(PGInetExpr x) {
return true;
}
@Override
public void endVisit(PGInetExpr x) {
}
@Override
public boolean visit(PGCidrExpr x) {
return true;
}
@Override
public void endVisit(PGCidrExpr x) {
}
@Override
public boolean visit(PGPolygonExpr x) {
return true;
}
@Override
public void endVisit(PGPolygonExpr x) {
}
@Override
public boolean visit(PGCircleExpr x) {
return true;
}
@Override
public void endVisit(PGCircleExpr x) {
}
@Override
public boolean visit(PGLineSegmentsExpr x) {
return true;
}
@Override
public void endVisit(PGLineSegmentsExpr x) {
}
@Override
public boolean visit(PGPointExpr x) {
return true;
@@ -0,0 +1,20 @@
package com.alibaba.druid.bvt.sql.postgresql.expr;
import org.junit.Assert;
import com.alibaba.druid.sql.PGTest;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGCidrExpr;
import com.alibaba.druid.sql.dialect.postgresql.parser.PGExprParser;
public class CidrTest extends PGTest {
public void test_timestamp() throws Exception {
String sql = "cidr '10.1.0.0/16'";
PGExprParser parser = new PGExprParser(sql);
PGCidrExpr expr = (PGCidrExpr) parser.expr();
Assert.assertEquals("cidr '10.1.0.0/16'", expr.toString());
}
}
@@ -0,0 +1,20 @@
package com.alibaba.druid.bvt.sql.postgresql.expr;
import org.junit.Assert;
import com.alibaba.druid.sql.PGTest;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGCircleExpr;
import com.alibaba.druid.sql.dialect.postgresql.parser.PGExprParser;
public class CircleTest extends PGTest {
public void test_timestamp() throws Exception {
String sql = "circle '((0,0),2)'";
PGExprParser parser = new PGExprParser(sql);
PGCircleExpr expr = (PGCircleExpr) parser.expr();
Assert.assertEquals("circle '((0,0),2)'", expr.toString());
}
}
@@ -0,0 +1,20 @@
package com.alibaba.druid.bvt.sql.postgresql.expr;
import org.junit.Assert;
import com.alibaba.druid.sql.PGTest;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGInetExpr;
import com.alibaba.druid.sql.dialect.postgresql.parser.PGExprParser;
public class InetTest extends PGTest {
public void test_timestamp() throws Exception {
String sql = "inet '0.0.0.255'";
PGExprParser parser = new PGExprParser(sql);
PGInetExpr expr = (PGInetExpr) parser.expr();
Assert.assertEquals("inet '0.0.0.255'", expr.toString());
}
}
@@ -0,0 +1,22 @@
package com.alibaba.druid.bvt.sql.postgresql.expr;
import org.junit.Assert;
import com.alibaba.druid.sql.PGTest;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGBoxExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGLineSegmentsExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGPointExpr;
import com.alibaba.druid.sql.dialect.postgresql.parser.PGExprParser;
public class LineSegmentsTest extends PGTest {
public void test_timestamp() throws Exception {
String sql = "lseg '((-1,0),(1,0))'";
PGExprParser parser = new PGExprParser(sql);
PGLineSegmentsExpr expr = (PGLineSegmentsExpr) parser.expr();
Assert.assertEquals("lseg '((-1,0),(1,0))'", expr.toString());
}
}
@@ -0,0 +1,22 @@
package com.alibaba.druid.bvt.sql.postgresql.expr;
import org.junit.Assert;
import com.alibaba.druid.sql.PGTest;
import com.alibaba.druid.sql.ast.expr.SQLUnaryExpr;
import com.alibaba.druid.sql.ast.expr.SQLUnaryOperator;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGMacAddrExpr;
import com.alibaba.druid.sql.dialect.postgresql.parser.PGExprParser;
public class MacAddrTest extends PGTest {
public void test_timestamp() throws Exception {
String sql = "macaddr '12:34:56:78:90:ab'";
PGExprParser parser = new PGExprParser(sql);
PGMacAddrExpr expr = (PGMacAddrExpr) parser.expr();
Assert.assertEquals("macaddr '12:34:56:78:90:ab'", expr.toString());
}
}
@@ -0,0 +1,20 @@
package com.alibaba.druid.bvt.sql.postgresql.expr;
import org.junit.Assert;
import com.alibaba.druid.sql.PGTest;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGPolygonExpr;
import com.alibaba.druid.sql.dialect.postgresql.parser.PGExprParser;
public class PolygonTest2 extends PGTest {
public void test_timestamp() throws Exception {
String sql = "polygon '((0,0),(1,1))'";
PGExprParser parser = new PGExprParser(sql);
PGPolygonExpr expr = (PGPolygonExpr) parser.expr();
Assert.assertEquals("polygon '((0,0),(1,1))'", expr.toString());
}
}