class TableFunction extends BuiltInFunction {

    public static final int TABLE = 300, TABLE_DISTINCT = 301;

    public static void init() {
        addFunctionWithNull("TABLE", TABLE, VAR_ARGS, Value.RESULT_SET);
        addFunctionWithNull("TABLE_DISTINCT", TABLE_DISTINCT, VAR_ARGS, Value.RESULT_SET);
    }

    private final boolean distinct;
    private Column[] columnList;

    TableFunction(Database database, FunctionInfo info) {
        super(database, info);
        distinct = info.type == TABLE_DISTINCT;
    }

    @Override
    public Value getValue(ServerSession session) {
        return getTable(session, args, false, distinct);
    }

    @Override
    protected void checkParameterCount(int len) {
        if (len < 1) {
            throw DbException.get(ErrorCode.INVALID_PARAMETER_COUNT_2, getName(), ">0");
        }
    }

    @Override
    public String getSQL() {
        StatementBuilder buff = new StatementBuilder(getName());
        buff.append('(');
        int i = 0;
        for (Expression e : args) {
            buff.appendExceptFirst(", ");
            buff.append(columnList[i++].getCreateSQL()).append('=').append(e.getSQL());
        }
        return buff.append(')').toString();
    }

    @Override
    public String getName() {
        return distinct ? "TABLE_DISTINCT" : "TABLE";
    }

    @Override
    public ValueResultSet getValueForColumnList(ServerSession session, Expression[] args) {
        return getTable(session, args, true, false);
    }

    public void setColumns(ArrayList<Column> columns) {
        this.columnList = new Column[columns.size()];
        columns.toArray(columnList);
    }

    private ValueResultSet getTable(ServerSession session, Expression[] argList, boolean onlyColumnList,
            boolean distinctRows) {
        int len = columnList.length;
        Expression[] header = new Expression[len];
        Database db = session.getDatabase();
        for (int i = 0; i < len; i++) {
            Column c = columnList[i];
            ExpressionColumn col = new ExpressionColumn(db, c);
            header[i] = col;
        }
        LocalResult result = new LocalResult(session, header, len);
        if (distinctRows) {
            result.setDistinct();
        }
        if (!onlyColumnList) {
            Value[][] list = new Value[len][];
            int rows = 0;
            for (int i = 0; i < len; i++) {
                Value v = argList[i].getValue(session);
                if (v == ValueNull.INSTANCE) {
                    list[i] = new Value[0];
                } else {
                    ValueArray array = (ValueArray) v.convertTo(Value.ARRAY);
                    Value[] l = array.getList();
                    list[i] = l;
                    rows = Math.max(rows, l.length);
                }
            }
            for (int row = 0; row < rows; row++) {
                Value[] r = new Value[len];
                for (int j = 0; j < len; j++) {
                    Value[] l = list[j];
                    Value v;
                    if (l.length <= row) {
                        v = ValueNull.INSTANCE;
                    } else {
                        Column c = columnList[j];
                        v = l[row];
                        v = c.convert(v);
                        v = v.convertPrecision(c.getPrecision(), false);
                        v = v.convertScale(true, c.getScale());
                    }
                    r[j] = v;
                }
                result.addRow(r);
            }
        }
        result.done();
        ValueResultSet vr = ValueResultSet.get(getSimpleResultSet(result, Integer.MAX_VALUE));
        return vr;
    }

    private static SimpleResultSet getSimpleResultSet(Result rs, int maxRows) {<FILL_FUNCTION_BODY>}

    @Override
    public Expression[] getExpressionColumns(ServerSession session) {
        return getExpressionColumns(session, getTable(session, getArgs(), true, false).getResultSet());
    }

    @Override
    public <R> R accept(ExpressionVisitor<R> visitor) {
        return visitor.visitTableFunction(this);
    }
}

        int columnCount = rs.getVisibleColumnCount();
        SimpleResultSet simple = new SimpleResultSet();
        for (int i = 0; i < columnCount; i++) {
            String name = rs.getColumnName(i);
            int sqlType = DataType.convertTypeToSQLType(rs.getColumnType(i));
            int precision = MathUtils.convertLongToInt(rs.getColumnPrecision(i));
            int scale = rs.getColumnScale(i);
            simple.addColumn(name, sqlType, precision, scale);
        }
        rs.reset();
        for (int i = 0; i < maxRows && rs.next(); i++) {
            Object[] list = new Object[columnCount];
            for (int j = 0; j < columnCount; j++) {
                list[j] = rs.currentRow()[j].getObject();
            }
            simple.addRow(list);
        }
        return simple;
    
<methods>public R accept(ExpressionVisitor<R>) ,public void doneWithParameters() ,public int getCost() ,public int getDisplaySize() ,public int getFunctionType() ,public java.lang.String getName() ,public long getPrecision() ,public java.lang.String getSQL() ,public int getScale() ,public int getType() ,public com.lealone.db.value.Value getValue(com.lealone.db.session.ServerSession) ,public com.lealone.db.value.ValueResultSet getValueForColumnList(com.lealone.db.session.ServerSession, com.lealone.sql.expression.Expression[]) ,public boolean isDeterministic() ,public com.lealone.sql.expression.Expression optimize(com.lealone.db.session.ServerSession) ,public void setDataType(com.lealone.db.table.Column) ,public void setParameter(int, com.lealone.sql.expression.Expression) <variables>protected int dataType,protected final non-sealed com.lealone.db.Database database,protected int displaySize,protected final non-sealed com.lealone.sql.expression.function.FunctionInfo info,protected long precision,protected int scale,private ArrayList<com.lealone.sql.expression.Expression> varArgs