Hi,
   Firstly, thanks for the great tool that H2 is. I would like to report 
what looks like a bug in H2. 
The following query works but when compose it within a nested expression 
(e.g. with <viewname> as (...) <some additional query>, shown highlighted 
in yellow below), I get a NullPointer expression. Will it be possible to 
take a look. The query relies on two function aliases defined in the 
attached script.The attached script also has the insert statements required 
to reproduce the issue. [*Warning! *the script has "drop all objects" at 
the beginning to clean up the database at the beginning]

select "companyId","name","age" 
  from flatten('name,age,companyId', $$select  xmlreadtable(s.payroll, 
'//Employee[age>30]', 'name', './name', 'age', './age' ), s.id 
      from company s 
    $$) ;
companyId   
<http://localhost:8085/query.do?jsessionid=1f2e2f79260a7aa01184bf3792df6492#>
name   
<http://localhost:8085/query.do?jsessionid=1f2e2f79260a7aa01184bf3792df6492#>
age   
<http://localhost:8085/query.do?jsessionid=1f2e2f79260a7aa01184bf3792df6492#>
1 Lisa 35
1 Tom 40
2 Rupert 37
2 Anna 35
2 Darren 40(5 rows, 19 ms)

     
with xmltable as ( 
select "companyId","name","age" 
  from flatten('name,age,companyId', $$select  xmlreadtable(s.payroll, 
'//Employee[age>30]', 'name', './name', 'age', './age' ), s.id 
      from company s 
    $$)) 
  select * from xmltable;
View "(
    SELECT
        ""companyId"",
        ""name"",
        ""age""
    FROM PUBLIC.FLATTEN('name,age,companyId', STRINGDECODE('select 
 xmlreadtable(s.payroll, ''//Employee[age>30]'', ''name'', ''./name'', 
''age'', ''./age'' ), s.id \r\n      from company s\r\n    '))
        /* function */
)" is invalid: "General error: ""java.lang.NullPointerException""; SQL 
statement:
select  xmlreadtable(s.payroll, '//Employee[age>30]', 'name', './name', 
'age', './age' ), s.id 
      from company s 
     [50000-197]"; SQL statement:
with xmltable as ( 
select "companyId","name","age" 
  from flatten('name,age,companyId', $$select  xmlreadtable(s.payroll, 
'//Employee[age>30]', 'name', './name', 'age', './age' ), s.id 
      from company s 
    $$)) 
  select * from xmltable [90109-197] 
<http://localhost:8085/query.do?jsessionid=1f2e2f79260a7aa01184bf3792df6492#>
 90109/90109 (Help) 
<http://h2database.com/javadoc/org/h2/api/ErrorCode.html#c90109>

-- 
You received this message because you are subscribed to the Google Groups "H2 
Database" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/h2-database.
For more options, visit https://groups.google.com/d/optout.
-- Start with a blank slate
drop all objects;

-- DROP ALIAS XMLREADTABLE;
CREATE ALIAS XMLREADTABLE AS $$
import java.sql.SQLException;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import org.h2.value.ValueResultSet;
import org.h2.tools.Csv;
import java.io.StringReader;
import org.h2.message.DbException;
import org.h2.tools.SimpleResultSet;
import java.io.*;
import java.lang.*;
import java.util.*;
import org.h2.util.JdbcUtils;
import org.xml.sax.InputSource;
@CODE
SimpleResultSet xmlreadtable(String xml, String path, String ...cols) throws Exception {
    
    try 
    {
        StringBuilder debug = new StringBuilder();
        javax.xml.parsers.DocumentBuilderFactory factory = javax.xml.parsers.DocumentBuilderFactory.newInstance();
        javax.xml.parsers.DocumentBuilder builder = factory.newDocumentBuilder();
        InputSource is = new InputSource(new StringReader(xml));
        org.w3c.dom.Document doc = builder.parse(is);
    
        // Create XPathFactory object
        javax.xml.xpath.XPathFactory xpathFactory = javax.xml.xpath.XPathFactory.newInstance();
    
        // Create XPath object
        javax.xml.xpath.XPath xpath = xpathFactory.newXPath();
        javax.xml.xpath.XPathExpression expr = xpath.compile(path);
        org.w3c.dom.NodeList nodes = (org.w3c.dom.NodeList) expr.evaluate(doc, javax.xml.xpath.XPathConstants.NODESET);
                                   
        ArrayList<javax.xml.xpath.XPathExpression> xpaths = new ArrayList<javax.xml.xpath.XPathExpression>();                                              
        
        int idx = 0;
        int columnCount = 0;
        SimpleResultSet simple = new SimpleResultSet();
        simple.setAutoClose(false);
        for (String col : cols)
        {
            if (idx % 2 == 0)
            {
                debug.append("\ncol="+col);
                simple.addColumn(col, 12, 4000, 0);
                ++columnCount;
               
            }
            else 
            {
                javax.xml.xpath.XPath xpath1 = xpathFactory.newXPath();
                javax.xml.xpath.XPathExpression colexpr = xpath1.compile(col);
                xpaths.add(colexpr);
            }
            idx = (idx+1);
        }
        
        
        String result = new String();
        for (int i = 0; i < nodes.getLength(); i++)
        {
            Object[] rowList = new Object[columnCount];
            int colidx = 0;
            debug.append("\nbegin_row");
            for(javax.xml.xpath.XPathExpression xpr : xpaths)
            {
            
                org.w3c.dom.NodeList inodes = (org.w3c.dom.NodeList) xpr.evaluate(nodes.item(i).cloneNode(true), javax.xml.xpath.XPathConstants.NODESET);
                   
                if (inodes.getLength() != 0)
                {
                     rowList[colidx]  = inodes.item(0).getTextContent();
                }
                else
                {
                    rowList[colidx] = new String();
                }
                debug.append("\nvalue="+rowList[colidx]);
                ++colidx;
            }
            simple.addRow(rowList);
            debug.append("\nend_row");
        }
        return simple;
        //return debug;    
    } 
    catch (Exception e) {
        throw e;
    } 
}
$$; 

-- drop alias flatten
CREATE ALIAS FLATTEN AS $$
import java.sql.*;
import org.h2.value.ValueResultSet;
import org.h2.tools.Csv;
import java.io.StringReader;
import org.h2.message.DbException;
import org.h2.tools.SimpleResultSet;
import java.io.*;
import java.lang.*;
import java.util.*;
import org.h2.util.JdbcUtils;
import org.xml.sax.InputSource;

@CODE
SimpleResultSet flatten(Connection conn, String columns, String sql) throws SQLException {
    ResultSet rs = conn.createStatement().executeQuery(sql);
    SimpleResultSet simple = new SimpleResultSet();
    StringBuilder debug = new StringBuilder();
    String [] colnames = columns.split(",");
    for (String col : colnames)
    {
        simple.addColumn(col, 12, 40000, 0);
    }

    try {

        // Load the result-set into a SimpleResultSet
        ResultSetMetaData meta = rs.getMetaData();
        int columnCount = meta.getColumnCount();
        simple.setAutoClose(false);

        for (int i = 0; i < columnCount; i++) {
            String name = meta.getColumnLabel(i + 1);
            int sqlType = meta.getColumnType(i + 1);
            int precision = meta.getPrecision(i + 1);
            int scale = meta.getScale(i + 1);
            simple.addColumn(name, sqlType, precision, scale);
            debug.append("\ncolname="+name+" sqltype="+sqlType+" precision="+precision);
        }
        for (int i = 0; rs.next(); i++) {
            
            ArrayList<ArrayList<Object>> newrows = new ArrayList<ArrayList<Object>>();
            
            flattenRow(rs, newrows, 0, columnCount, debug); 
            
            for (ArrayList<Object> newrow : newrows)
            {
                Object[] rowArr = new Object[newrow.size()];
                newrow.toArray(rowArr);
                for (Object val : rowArr) { debug.append("\nval="+val) ;}
                simple.addRow(rowArr);
                debug.append("\nend row");
            }
            
        }
        //rs.close();
        return simple;
    } catch (Exception e)
    {
        throw e;
        //return e.getMessage() + " debug = " + debug;
    }
}


static ArrayList<ArrayList<Object>> deepcopy(ArrayList<ArrayList<Object>> rows)
{
    ArrayList<ArrayList<Object>> result = new ArrayList<ArrayList<Object>>();
    for(ArrayList<Object> row : rows)
    {
        result.add((ArrayList<Object>)row.clone());
    }
    return result;
}
    
static void flattenRow(ResultSet rs,  ArrayList<ArrayList<Object>> newrows, int j, int columnCount, StringBuilder debug) throws SQLException
{
    
    if (j >= columnCount)
    {
        return;
    }
    if (newrows.size() == 0)
    {
        newrows.add(new ArrayList<Object>());
    }
    
    Object obj = rs.getObject(j + 1);
    debug.append("obj="+obj) ;
    if (obj instanceof org.h2.tools.SimpleResultSet)
    {
        SimpleResultSet srs = (SimpleResultSet) obj;
        srs.setAutoClose(false);
        debug.append("\nabout to get metadata");
        ResultSetMetaData srsmeta = srs.getMetaData();
        debug.append("\ngot metadata");
        int srscolumnCount = srsmeta.getColumnCount();
        debug.append("\nsrs column count="+srscolumnCount);
        boolean firstRow = true;
        
        ArrayList<ArrayList<Object>> preexistingRowsMasterCopy = deepcopy(newrows);
        while(srs.next())
        {
            if (firstRow)
            {
                for (int k = 0; k < srscolumnCount; ++k)
                {
                    for (ArrayList<Object> row : newrows)
                    {
                        row.add(srs.getObject(k+1));
                    }
                }
            }
            else
            {
                ArrayList<ArrayList<Object>> newadditionalrows = deepcopy(preexistingRowsMasterCopy);
                for (int k = 0; k < srscolumnCount; ++k)
                {
                    for (ArrayList<Object> additionalrow : newadditionalrows)
                    {
                        additionalrow.add(srs.getObject(k+1));
                    }
                }
                
                for (ArrayList<Object> additionalrow : newadditionalrows)
                {
                    newrows.add((ArrayList<Object>)additionalrow);
                }
            }
            firstRow = false;
        }
    }
    else if (obj instanceof Clob)
    {
         Clob clob = (Clob)obj;
         String clobString = clob.getSubString (1, (int) clob.length ());
         for (ArrayList<Object> row : newrows)
         {
             row.add(clobString);
         }
    }
    else
    {
        for (ArrayList<Object> row : newrows)
         {
             row.add(obj == null? null: obj.toString());
         }
    }
    
    flattenRow(rs, newrows, j+1, columnCount,debug);
}

$$;   

create table company
(
    id NUMBER,
    payroll CLOB
);

insert into company(id,payroll) values (1, '<Employees>                            
                  <Employee id="1">                  
                      <age>29</age>                  
                      <name>Pankaj</name>            
                      <gender>Male</gender>          
                      <role>Java Developer</role>    
                  </Employee>                        
                  <Employee id="2">                  
                      <age>35</age>                  
                      <name>Lisa</name>              
                      <gender>Female</gender>        
                      <role>CEO</role>               
                  </Employee>                        
                  <Employee id="3">                  
                      <age>40</age>                  
                      <name>Tom</name>               
                      <gender>Male</gender>          
                      <role>Manager</role>           
                  </Employee>                        
                  <Employee id="4">                  
                      <age>25</age>                  
                      <name>Meghan</name>            
                      <gender>Female</gender>        
                      <role>Manager</role>           
                  </Employee>                        
              </Employees>                            
    ');
insert into company(id,payroll) values (2, '
              <Employees>                            
                  <Employee id="1">                  
                      <age>37</age>                  
                      <name>Rupert</name>            
                      <gender>Male</gender>          
                      <role>Java Developer</role>    
                  </Employee>                        
                  <Employee id="2">                  
                      <age>35</age>                  
                      <name>Anna</name>              
                      <gender>Female</gender>        
                      <role>CEO</role>               
                  </Employee>                        
                  <Employee id="3">                  
                      <age>40</age>                  
                      <name>Darren</name>               
                      <gender>Male</gender>          
                      <role>Front End Developer</role>           
                  </Employee>                        
                  <Employee id="4">                  
                      <age>25</age>                  
                      <name>Kimberley</name>            
                      <gender>Female</gender>        
                      <role>Customer Support</role>           
                  </Employee>                        
              </Employees>                            
    ');
    
select  xmlreadtable(s.payroll, '//Employee', 'name', './name', 'age', './age' ), s.id 
      from company s;
          
select "companyId","name","age" 
  from flatten('name,age,companyId', $$select  xmlreadtable(s.payroll, '//Employee', 'name', './name', 'age', './age' ), s.id 
      from company s
    $$) ;

select "companyId","name","age" 
  from flatten('name,age,companyId', $$select  xmlreadtable(s.payroll, '//Employee[age>30]', 'name', './name', 'age', './age' ), s.id 
      from company s
    $$) ;
    
with xmltable as (
select "companyId","name","age" 
  from flatten('name,age,companyId', $$select  xmlreadtable(s.payroll, '//Employee[age>30]', 'name', './name', 'age', './age' ), s.id 
      from company s
    $$))
  select * from xmltable;
      

Reply via email to