diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/expr/PGParameter.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/expr/PGParameter.java new file mode 100644 index 0000000000..b2c1b7a854 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/expr/PGParameter.java @@ -0,0 +1,39 @@ +package com.alibaba.druid.sql.dialect.postgresql.ast.expr; + +import com.alibaba.druid.sql.ast.SQLDataType; +import com.alibaba.druid.sql.ast.SQLExpr; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGSQLObjectImpl; +import com.alibaba.druid.sql.dialect.postgresql.visitor.PGASTVisitor; + +public class PGParameter extends PGSQLObjectImpl { + + private static final long serialVersionUID = 1L; + private SQLExpr name; + private SQLDataType dataType; + + + public SQLExpr getName() { + return name; + } + + public void setName(SQLExpr name) { + this.name = name; + } + + public SQLDataType getDataType() { + return dataType; + } + + public void setDataType(SQLDataType dataType) { + this.dataType = dataType; + } + + @Override + public void accept0(PGASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, name); + acceptChild(visitor, dataType); + } + visitor.endVisit(this); + } +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/stmt/PGFunctionTableSource.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/stmt/PGFunctionTableSource.java new file mode 100644 index 0000000000..14e4663677 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/stmt/PGFunctionTableSource.java @@ -0,0 +1,43 @@ +package com.alibaba.druid.sql.dialect.postgresql.ast.stmt; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.druid.sql.ast.SQLExpr; +import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGSQLObject; +import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGParameter; +import com.alibaba.druid.sql.dialect.postgresql.visitor.PGASTVisitor; +import com.alibaba.druid.sql.visitor.SQLASTVisitor; + +public class PGFunctionTableSource extends SQLExprTableSource implements PGSQLObject { + + private static final long serialVersionUID = 1L; + + private final List parameters = new ArrayList(); + + public PGFunctionTableSource(){ + + } + + public PGFunctionTableSource(SQLExpr expr){ + this.expr = expr; + } + + public List getParameters() { + return parameters; + } + + @Override + protected void accept0(SQLASTVisitor visitor) { + this.accept0((PGASTVisitor) visitor); + } + + public void accept0(PGASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, this.expr); + acceptChild(visitor, this.parameters); + } + visitor.endVisit(this); + } +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGLexer.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGLexer.java index 7cd1aad304..a4a253bc46 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGLexer.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGLexer.java @@ -1,5 +1,7 @@ package com.alibaba.druid.sql.dialect.postgresql.parser; +import static com.alibaba.druid.sql.parser.Token.LITERAL_CHARS; + import java.util.HashMap; import java.util.Map; @@ -51,4 +53,90 @@ public class PGLexer extends Lexer { super(input); super.keywods = DEFAULT_PG_KEYWORDS; } + + protected void scanString() { + np = bp; + boolean hasSpecial = false; + + for (;;) { + if (bp >= buflen) { + lexError(tokenPos, "unclosed.str.lit"); + return; + } + + ch = buf[++bp]; + + if (ch == '\\') { + scanChar(); + if (!hasSpecial) { + System.arraycopy(buf, np + 1, sbuf, 0, sp); + hasSpecial = true; + } + + switch (ch) { + case '\0': + putChar('\0'); + break; + case '\'': + putChar('\''); + break; + case '"': + putChar('"'); + break; + case 'b': + putChar('\b'); + break; + case 'n': + putChar('\n'); + break; + case 'r': + putChar('\r'); + break; + case 't': + putChar('\t'); + break; + case '\\': + putChar('\\'); + break; + case 'Z': + putChar((char) 0x1A); // ctrl + Z + break; + default: + putChar(ch); + break; + } + scanChar(); + } + + if (ch == '\'') { + scanChar(); + if (ch != '\'') { + token = LITERAL_CHARS; + break; + } else { + System.arraycopy(buf, np + 1, sbuf, 0, sp); + hasSpecial = true; + putChar('\''); + continue; + } + } + + if (!hasSpecial) { + sp++; + continue; + } + + if (sp == sbuf.length) { + putChar(ch); + } else { + sbuf[sp++] = ch; + } + } + + if (!hasSpecial) { + stringVal = new String(buf, np + 1, sp); + } else { + stringVal = new String(sbuf, 0, sp); + } + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGSelectParser.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGSelectParser.java index 2bc5012191..ab50576731 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGSelectParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGSelectParser.java @@ -1,10 +1,15 @@ package com.alibaba.druid.sql.dialect.postgresql.parser; +import java.util.List; + import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLSetQuantifier; import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; import com.alibaba.druid.sql.ast.statement.SQLSelectQuery; +import com.alibaba.druid.sql.ast.statement.SQLTableSource; +import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGParameter; +import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGFunctionTableSource; import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock; import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock.IntoOption; import com.alibaba.druid.sql.parser.ParserException; @@ -200,4 +205,44 @@ public class PGSelectParser extends SQLSelectParser { return queryRest(queryBlock); } + protected SQLTableSource parseTableSourceRest(SQLTableSource tableSource) throws ParserException { + if (lexer.token() == Token.AS && tableSource instanceof SQLExprTableSource) { + String alias = this.as(); + + if (lexer.token() == Token.LPAREN) { + SQLExprTableSource exprTableSource = (SQLExprTableSource) tableSource; + + PGFunctionTableSource functionTableSource = new PGFunctionTableSource(exprTableSource.getExpr()); + functionTableSource.setAlias(alias); + + lexer.nextToken(); + parserParameters(functionTableSource.getParameters()); + accept(Token.RPAREN); + + return super.parseTableSourceRest(functionTableSource); + } + } + + return super.parseTableSourceRest(tableSource); + } + + private void parserParameters(List parameters) { + for (;;) { + PGParameter parameter = new PGParameter(); + + parameter.setName(this.exprParser.name()); + parameter.setDataType(this.exprParser.parseDataType()); + + parameters.add(parameter); + if (lexer.token() == Token.COMMA || lexer.token() == Token.SEMI) { + lexer.nextToken(); + } + + if (lexer.token() != Token.BEGIN && lexer.token() != Token.RPAREN) { + continue; + } + + break; + } + } } \ No newline at end of file diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGASTVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGASTVisitor.java index 5a3ea640b8..eba812cc80 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGASTVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGASTVisitor.java @@ -4,7 +4,9 @@ import com.alibaba.druid.sql.dialect.postgresql.ast.PGAggregateExpr; 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.PGAnalytic; +import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGParameter; import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGDeleteStatement; +import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGFunctionTableSource; import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGInsertStatement; import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock; import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectStatement; @@ -17,9 +19,9 @@ public interface PGASTVisitor extends SQLASTVisitor { void endVisit(PGSelectQueryBlock x); boolean visit(PGSelectQueryBlock x); - + void endVisit(PGSelectQueryBlock.WindowClause x); - + boolean visit(PGSelectQueryBlock.WindowClause x); void endVisit(PGSelectQueryBlock.FetchClause x); @@ -57,14 +59,21 @@ public interface PGASTVisitor extends SQLASTVisitor { void endVisit(PGUpdateStatement x); boolean visit(PGUpdateStatement x); - + void endVisit(PGAggregateExpr x); boolean visit(PGAggregateExpr x); - + void endVisit(PGAnalytic x); boolean visit(PGAnalytic x); - - + + void endVisit(PGParameter x); + + boolean visit(PGParameter x); + + void endVisit(PGFunctionTableSource x); + + boolean visit(PGFunctionTableSource x); + } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGASTVisitorAdapter.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGASTVisitorAdapter.java index b6ff67d9e7..ec410c32ad 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGASTVisitorAdapter.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGASTVisitorAdapter.java @@ -4,7 +4,9 @@ import com.alibaba.druid.sql.dialect.postgresql.ast.PGAggregateExpr; 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.PGAnalytic; +import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGParameter; import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGDeleteStatement; +import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGFunctionTableSource; import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGInsertStatement; import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock; import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock.FetchClause; @@ -126,7 +128,7 @@ public class PGASTVisitorAdapter extends SQLASTVisitorAdapter implements PGASTVi @Override public void endVisit(PGSelectQueryBlock x) { - + } @Override @@ -134,23 +136,43 @@ public class PGASTVisitorAdapter extends SQLASTVisitorAdapter implements PGASTVi return true; } - @Override - public void endVisit(PGAggregateExpr x) { - } + @Override + public void endVisit(PGAggregateExpr x) { + } - @Override - public boolean visit(PGAggregateExpr x) { - return false; - } + @Override + public boolean visit(PGAggregateExpr x) { + return true; + } - @Override - public void endVisit(PGAnalytic x) { - } + @Override + public void endVisit(PGAnalytic x) { + } - @Override - public boolean visit(PGAnalytic x) { + @Override + public boolean visit(PGAnalytic x) { - return false; - } + return true; + } + + @Override + public void endVisit(PGParameter x) { + + } + + @Override + public boolean visit(PGParameter x) { + return true; + } + + @Override + public void endVisit(PGFunctionTableSource x) { + + } + + @Override + public boolean visit(PGFunctionTableSource x) { + return true; + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java index bebdd2cc7c..38ddec0c02 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java @@ -7,7 +7,9 @@ import com.alibaba.druid.sql.dialect.postgresql.ast.PGAggregateExpr; 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.PGAnalytic; +import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGParameter; import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGDeleteStatement; +import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGFunctionTableSource; import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGInsertStatement; import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock; import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock.FetchClause; @@ -163,7 +165,7 @@ public class PGOutputVisitor extends SQLASTOutputVisitor implements PGASTVisitor print(x.getIntoOption().name()); print(" "); } - + x.getInto().accept(this); } @@ -221,7 +223,6 @@ public class PGOutputVisitor extends SQLASTOutputVisitor implements PGASTVisitor return false; } - @Override public void endVisit(PGTruncateStatement x) { @@ -291,7 +292,7 @@ public class PGOutputVisitor extends SQLASTOutputVisitor implements PGASTVisitor x.getWhere().setParent(x); x.getWhere().accept(this); } - + if (x.isReturning()) { println(); print("RETURNING *"); @@ -302,16 +303,16 @@ public class PGOutputVisitor extends SQLASTOutputVisitor implements PGASTVisitor @Override public void endVisit(PGInsertStatement x) { - + } - + @Override public boolean visit(PGInsertStatement x) { if (x.getWith() != null) { x.getWith().accept(this); println(); } - + print("INSERT INTO "); x.getTableName().accept(this); @@ -343,7 +344,7 @@ public class PGOutputVisitor extends SQLASTOutputVisitor implements PGASTVisitor x.getQuery().accept(this); } } - + if (x.getReturning() != null) { println(); print("RETURNING "); @@ -352,36 +353,36 @@ public class PGOutputVisitor extends SQLASTOutputVisitor implements PGASTVisitor return false; } - + @Override public void endVisit(PGSelectStatement x) { - + } - + @Override public boolean visit(PGSelectStatement x) { if (x.getWith() != null) { x.getWith().accept(this); println(); } - + return visit((SQLSelectStatement) x); } - + @Override public void endVisit(PGUpdateStatement x) { - + } - + @Override public boolean visit(PGUpdateStatement x) { if (x.getWith() != null) { x.getWith().accept(this); println(); } - + print("UPDATE "); - + if (x.isOnly()) { print("ONLY "); } @@ -396,7 +397,7 @@ public class PGOutputVisitor extends SQLASTOutputVisitor implements PGASTVisitor } x.getItems().get(i).accept(this); } - + if (x.getFrom() != null) { println(); print("FROM "); @@ -409,7 +410,7 @@ public class PGOutputVisitor extends SQLASTOutputVisitor implements PGASTVisitor x.getWhere().setParent(x); x.getWhere().accept(this); } - + if (x.getReturning().size() > 0) { println(); print("RETURNING "); @@ -421,48 +422,86 @@ public class PGOutputVisitor extends SQLASTOutputVisitor implements PGASTVisitor @Override public void endVisit(PGSelectQueryBlock x) { - + } - @Override - public void endVisit(PGAggregateExpr x) { - - } + @Override + public void endVisit(PGAggregateExpr x) { - @Override - public boolean visit(PGAggregateExpr x) { + } + + @Override + public boolean visit(PGAggregateExpr x) { print(x.getMethodName()); print("("); printAndAccept(x.getArguments(), ", "); print(")"); - if(x.getOver() != null){ - x.getOver().accept(this); + if (x.getOver() != null) { + x.getOver().accept(this); } return false; - } + } - @Override - public void endVisit(PGAnalytic x) { + @Override + public void endVisit(PGAnalytic x) { - - } + } + + @Override + public boolean visit(PGAnalytic x) { + print(" OVER ("); + if (x.getPartitionBy().size() > 0) { + int mark = 0; + for (SQLExpr e : x.getPartitionBy()) { + if (mark++ != 0) { + print(", "); + } + e.accept(this); + } + } + if (x.getOrderBy() != null) { + x.getOrderBy().accept(this); + } + print(")"); + return false; + } + + @Override + public void endVisit(PGParameter x) { + + } + + @Override + public boolean visit(PGParameter x) { + x.getName().accept(this); + print(" "); + + x.getDataType().accept(this); + + return false; + } + + @Override + public boolean visit(PGFunctionTableSource x) { + x.getExpr().accept(this); + + if (x.getAlias() != null) { + print(" AS "); + print(x.getAlias()); + } + + if (x.getParameters().size() > 0) { + print('('); + printAndAccept(x.getParameters(), ", "); + print(')'); + } + + return false; + } + + @Override + public void endVisit(PGFunctionTableSource x) { + + } - @Override - public boolean visit(PGAnalytic x) { - print(" OVER ("); - if(x.getPartitionBy().size() > 0){ - int mark = 0; - for(SQLExpr e:x.getPartitionBy()){ - if(mark++ != 0){ - print(", "); - } - e.accept(this); - } - } - if(x.getOrderBy() != null){ - x.getOrderBy().accept(this); - } - print(")"); - return false; - } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGSchemaStatVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGSchemaStatVisitor.java index 252bcbaf05..ed3919a727 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGSchemaStatVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGSchemaStatVisitor.java @@ -11,7 +11,9 @@ import com.alibaba.druid.sql.dialect.postgresql.ast.PGAggregateExpr; 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.PGAnalytic; +import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGParameter; import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGDeleteStatement; +import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGFunctionTableSource; import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGInsertStatement; import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock; import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock.FetchClause; @@ -262,4 +264,24 @@ public class PGSchemaStatVisitor extends SchemaStatVisitor implements PGASTVisit public boolean visit(PGAnalytic x) { return false; } + + @Override + public void endVisit(PGParameter x) { + + } + + @Override + public boolean visit(PGParameter x) { + return false; + } + + @Override + public void endVisit(PGFunctionTableSource x) { + + } + + @Override + public boolean visit(PGFunctionTableSource x) { + return true; + } } diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java index 0c9623da41..3d8f089750 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java @@ -1081,6 +1081,11 @@ public class SQLExprParser extends SQLParser { SQLName typeExpr = name(); String typeName = typeExpr.toString(); + + if ("character".equalsIgnoreCase(typeName) && "varying".equalsIgnoreCase(lexer.stringVal())) { + typeName += ' ' + lexer.stringVal(); + lexer.nextToken(); + } SQLDataType dataType = new SQLDataTypeImpl(typeName); return parseDataTypeRest(dataType); diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SQLShardingContext.java b/src/main/java/com/alibaba/druid/sql/visitor/SQLShardingContext.java new file mode 100644 index 0000000000..1a1bcff83e --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLShardingContext.java @@ -0,0 +1,6 @@ +package com.alibaba.druid.sql.visitor; + + +public class SQLShardingContext { + +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest.java b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest.java new file mode 100644 index 0000000000..80ca862691 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest.java @@ -0,0 +1,61 @@ +package com.alibaba.druid.bvt.sql.postgresql; + +import java.util.List; + +import junit.framework.Assert; + +import com.alibaba.druid.sql.PGTest; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.postgresql.parser.PGSQLStatementParser; +import com.alibaba.druid.sql.dialect.postgresql.visitor.PGSchemaStatVisitor; + + +public class PGSelectTest extends PGTest { + + public void test_0() throws Exception { + String sql = "select categoryId , offerIds from cnres.function_select_get_spt_p4p_offer_list (' 1031918 , 1031919 , 1037004 ') as a(categoryId numeric,offerIds character varying(4000))"; + + PGSQLStatementParser parser = new PGSQLStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement statemen = statementList.get(0); + print(statementList); + + Assert.assertEquals(1, statementList.size()); + + PGSchemaStatVisitor visitor = new PGSchemaStatVisitor(); + statemen.accept(visitor); + + System.out.println("Tables : " + visitor.getTables()); + System.out.println("fields : " + visitor.getColumns()); + System.out.println("coditions : " + visitor.getConditions()); + + + Assert.assertEquals(2, visitor.getColumns().size()); + } + + public void test_1() throws Exception { + String sql = "select memberId , offerIds from cnres.function_select_get_seller_hot_offer_list('\\'gzyyd168\\'') as a(memberId character varying(20),offerIds character varying(4000))"; + + PGSQLStatementParser parser = new PGSQLStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement statemen = statementList.get(0); + print(statementList); + + Assert.assertEquals(1, statementList.size()); + + PGSchemaStatVisitor visitor = new PGSchemaStatVisitor(); + statemen.accept(visitor); + + System.out.println("Tables : " + visitor.getTables()); + System.out.println("fields : " + visitor.getColumns()); + System.out.println("coditions : " + visitor.getConditions()); + + + Assert.assertEquals(2, visitor.getColumns().size()); + } + +} + +//select categoryId , offerIds from cnres.function_select_get_spt_p4p_offer_list (' 1031918 , 1031919 , 1037004 ') as a(categoryId numeric,offerIds character varying(4000)) +// select memberId , offerIds from cnres.function_select_get_seller_hot_offer_list('\'gzyyd168\'') as a(memberId character varying(20),offerIds character varying(4000)) +