sqldk-relpipe convergence started v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Tue, 05 Mar 2019 21:22:33 +0100
branchv_0
changeset 245b6ff5b7a8422
parent 244 6bdb45af26d9
child 246 277c18b48762
sqldk-relpipe convergence started
java/sql-dk/src/main/java/info/globalcode/sql/dk/Xmlns.java
java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/AbstractXmlFormatter.java
java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/ColumnDescriptor.java
java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/ColumnsHeader.java
java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/XhtmlFormatter.java
java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/XmlFormatter.java
     1.1 --- a/java/sql-dk/src/main/java/info/globalcode/sql/dk/Xmlns.java	Mon Mar 04 22:28:29 2019 +0100
     1.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/Xmlns.java	Tue Mar 05 21:22:33 2019 +0100
     1.3 @@ -25,7 +25,8 @@
     1.4  public class Xmlns {
     1.5  
     1.6  	public static final String CONFIGURATION = "https://sql-dk.globalcode.info/xmlns/configuration";
     1.7 -	public static final String BATCH_RESULT = "https://sql-dk.globalcode.info/xmlns/batchResult";
     1.8 +	public static final String RELPIPE = "tag:globalcode.info,2018:relpipe";
     1.9 +	public static final String SQLDK = "tag:globalcode.info,2018:sqldk";
    1.10  	public static final String XHTML = "http://www.w3.org/1999/xhtml";
    1.11  
    1.12  	private Xmlns() {
     2.1 --- a/java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/AbstractXmlFormatter.java	Mon Mar 04 22:28:29 2019 +0100
     2.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/AbstractXmlFormatter.java	Tue Mar 05 21:22:33 2019 +0100
     2.3 @@ -61,7 +61,7 @@
     2.4  	private static final TerminalColor ATTRIBUTE_VALUE_COLOR = TerminalColor.Yellow;
     2.5  	private static final TerminalColor XML_DECLARATION_COLOR = TerminalColor.Red;
     2.6  	private static final TerminalColor XML_DOCTYPE_COLOR = TerminalColor.Cyan;
     2.7 -	private Stack<QName> treePosition = new Stack<>();
     2.8 +	private final Stack<QName> treePosition = new Stack<>();
     2.9  	private final ColorfulPrintWriter out;
    2.10  	private final String indent;
    2.11  	private final boolean indentText;
    2.12 @@ -205,14 +205,6 @@
    2.13  		}
    2.14  	}
    2.15  
    2.16 -	protected static QName qname(String name) {
    2.17 -		return new QName(name);
    2.18 -	}
    2.19 -
    2.20 -	protected static QName qname(String prefix, String name) {
    2.21 -		return new QName(null, name, prefix);
    2.22 -	}
    2.23 -
    2.24  	private String toString(QName name) {
    2.25  		if (isEmpty(name.getPrefix(), true)) {
    2.26  			return escapeName(name.getLocalPart());
     3.1 --- a/java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/ColumnDescriptor.java	Mon Mar 04 22:28:29 2019 +0100
     3.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/ColumnDescriptor.java	Tue Mar 05 21:22:33 2019 +0100
     3.3 @@ -32,6 +32,7 @@
     3.4  	private boolean firstColumn;
     3.5  	private boolean lastColumn;
     3.6  	private int columnNumber;
     3.7 +	private String tableName;
     3.8  
     3.9  	/**
    3.10  	 * @return column name
    3.11 @@ -99,6 +100,14 @@
    3.12  		this.columnNumber = columnNumber;
    3.13  	}
    3.14  
    3.15 +	public String getTableName() {
    3.16 +		return tableName;
    3.17 +	}
    3.18 +
    3.19 +	public void setTableName(String tableName) {
    3.20 +		this.tableName = tableName;
    3.21 +	}
    3.22 +
    3.23  	public boolean isBoolean() {
    3.24  		return type == Types.BOOLEAN;
    3.25  	}
     4.1 --- a/java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/ColumnsHeader.java	Mon Mar 04 22:28:29 2019 +0100
     4.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/ColumnsHeader.java	Tue Mar 05 21:22:33 2019 +0100
     4.3 @@ -27,13 +27,13 @@
     4.4   * @author Ing. František Kučera (frantovo.cz)
     4.5   */
     4.6  public class ColumnsHeader {
     4.7 -	
     4.8 -	private ResultSetMetaData metaData;
     4.9 -	
    4.10 +
    4.11 +	private final ResultSetMetaData metaData;
    4.12 +
    4.13  	public ColumnsHeader(ResultSetMetaData metaData) {
    4.14  		this.metaData = metaData;
    4.15  	}
    4.16 -	
    4.17 +
    4.18  	public int getColumnCount() {
    4.19  		try {
    4.20  			return metaData.getColumnCount();
    4.21 @@ -41,27 +41,27 @@
    4.22  			throw new IllegalStateException("Error during getting column count.", e);
    4.23  		}
    4.24  	}
    4.25 -	
    4.26 +
    4.27  	public List<ColumnDescriptor> getColumnDescriptors() {
    4.28  		try {
    4.29  			int count = metaData.getColumnCount();
    4.30  			List<ColumnDescriptor> list = new ArrayList<>(count);
    4.31 -			
    4.32 +
    4.33  			for (int i = 1; i <= count; i++) {
    4.34  				ColumnDescriptor cd = new ColumnDescriptor();
    4.35 -				
    4.36 +
    4.37  				cd.setFirstColumn(i == 1);
    4.38  				cd.setLastColumn(i == count);
    4.39  				cd.setColumnNumber(i);
    4.40 -				
    4.41 +
    4.42  				cd.setLabel(metaData.getColumnLabel(i));
    4.43  				cd.setName(metaData.getColumnName(i));
    4.44  				cd.setType(metaData.getColumnType(i));
    4.45  				cd.setTypeName(metaData.getColumnTypeName(i));
    4.46 -				/** TODO: more properties */
    4.47 +				cd.setTableName(metaData.getTableName(i));
    4.48  				list.add(cd);
    4.49  			}
    4.50 -			
    4.51 +
    4.52  			return list;
    4.53  		} catch (SQLException e) {
    4.54  			throw new IllegalStateException("Error during building column descriptors.", e);
     5.1 --- a/java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/XhtmlFormatter.java	Mon Mar 04 22:28:29 2019 +0100
     5.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/XhtmlFormatter.java	Tue Mar 05 21:22:33 2019 +0100
     5.3 @@ -24,7 +24,6 @@
     5.4  import info.globalcode.sql.dk.configuration.DatabaseDefinition;
     5.5  import info.globalcode.sql.dk.configuration.Properties;
     5.6  import info.globalcode.sql.dk.configuration.Property;
     5.7 -import static info.globalcode.sql.dk.formatting.AbstractXmlFormatter.qname;
     5.8  import java.sql.Array;
     5.9  import java.sql.SQLException;
    5.10  import java.util.Date;
    5.11 @@ -55,6 +54,10 @@
    5.12  	public XhtmlFormatter(FormatterContext formatterContext) {
    5.13  		super(addDefaults(formatterContext));
    5.14  	}
    5.15 +	
    5.16 +	private QName qname(String localPart) {
    5.17 +		return new QName(Xmlns.XHTML, localPart);
    5.18 +	}
    5.19  
    5.20  	/**
    5.21  	 * Do not indent text – preserve whitespace for pre elements
     6.1 --- a/java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/XmlFormatter.java	Mon Mar 04 22:28:29 2019 +0100
     6.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/XmlFormatter.java	Tue Mar 05 21:22:33 2019 +0100
     6.3 @@ -23,12 +23,14 @@
     6.4  import static info.globalcode.sql.dk.Functions.notNull;
     6.5  import info.globalcode.sql.dk.NamedParameter;
     6.6  import info.globalcode.sql.dk.configuration.PropertyDeclaration;
     6.7 -import static info.globalcode.sql.dk.formatting.AbstractXmlFormatter.qname;
     6.8  import java.sql.Array;
     6.9  import java.sql.ResultSet;
    6.10  import java.sql.SQLException;
    6.11  import java.sql.SQLXML;
    6.12 +import java.sql.Types;
    6.13  import java.util.ArrayList;
    6.14 +import java.util.Collections;
    6.15 +import java.util.HashMap;
    6.16  import java.util.LinkedHashMap;
    6.17  import java.util.List;
    6.18  import java.util.Map;
    6.19 @@ -42,28 +44,73 @@
    6.20   * choice for further processing – e.g. XSL transformation.</p>
    6.21   *
    6.22   * <p>
    6.23 - * TODO: XSD</p>
    6.24 + * XML format is defined in the <a href="https://relational-pipes.globalcode.info/">Relational
    6.25 + * pipes</a> specification.
    6.26 + * </p>
    6.27   *
    6.28   * @author Ing. František Kučera (frantovo.cz)
    6.29   */
    6.30  @PropertyDeclaration(name = XmlFormatter.PROPERTY_LABELED_COLUMNS, defaultValue = "false", type = Boolean.class, description = "whether to add 'label' attribute to each 'column' element")
    6.31  public class XmlFormatter extends AbstractXmlFormatter {
    6.32  
    6.33 +	private static final String XML_ELEMENT_RELATION = "relation";
    6.34 +	private static final String XML_ELEMENT_NAME = "name";
    6.35 +	private static final String XML_ELEMENT_RECORD = "record";
    6.36 +	private static final String XML_ELEMENT_ATTRIBUTE = "attribute";
    6.37 +	private static final String XML_ATTRIBUTE_NAME = "name";
    6.38 +	private static final String XML_ATTRIBUTE_TYPE = "type";
    6.39 +	private static final String XML_ATTRIBUTE_STATEMENT = "statement";
    6.40 +	private static final String XML_NS_PREFIX_SQLDK = "sql-dk";
    6.41 +
    6.42 +	private static final String RELPIPE_TYPE_BOOLEAN = "boolean";
    6.43 +	private static final String RELPIPE_TYPE_INTEGER = "integer";
    6.44 +	private static final String RELPIPE_TYPE_STRING = "string";
    6.45 +	private static final Map<Integer, String> RELPIPE_TYPES;
    6.46 +
    6.47 +	static {
    6.48 +		Map<Integer, String> m = new HashMap<>();
    6.49 +		m.put(Types.BOOLEAN, RELPIPE_TYPE_BOOLEAN);
    6.50 +		m.put(Types.BIT, RELPIPE_TYPE_BOOLEAN); // TODO: relpipe "boolean" can not be null in the current version
    6.51 +		// m.put(Types.INTEGER, RELPIPE_TYPE_INTEGER); // relpipe "integer" is unsigned
    6.52 +		// TODO: add more types when supported in Relational pipes
    6.53 +		m.put(Types.CHAR, RELPIPE_TYPE_STRING);
    6.54 +		m.put(Types.VARCHAR, RELPIPE_TYPE_STRING);
    6.55 +		RELPIPE_TYPES = Collections.unmodifiableMap(m);
    6.56 +	}
    6.57 +
    6.58  	public static final String NAME = "xml"; // bash-completion:formatter
    6.59  	public static final String PROPERTY_LABELED_COLUMNS = "labeledColumns";
    6.60  	private static final Logger log = Logger.getLogger(XmlFormatter.class.getName());
    6.61  	private final boolean labeledColumns;
    6.62  
    6.63 +	private String currentDatabaseName;
    6.64 +	private int statementCounter;
    6.65 +	private int resultSetCounter;
    6.66 +
    6.67  	public XmlFormatter(FormatterContext formatterContext) {
    6.68  		super(formatterContext);
    6.69  		labeledColumns = formatterContext.getProperties().getBoolean(PROPERTY_LABELED_COLUMNS, false);
    6.70  	}
    6.71  
    6.72 +	private QName qname(String localPart) {
    6.73 +		return new QName(Xmlns.RELPIPE, localPart);
    6.74 +	}
    6.75 +
    6.76 +	private QName qnameDK(String localPart) {
    6.77 +		return new QName(Xmlns.SQLDK, localPart, XML_NS_PREFIX_SQLDK);
    6.78 +	}
    6.79 +
    6.80  	@Override
    6.81  	public void writeStartBatch() {
    6.82  		super.writeStartBatch();
    6.83  		printStartDocument();
    6.84 -		printStartElement(qname("batchResult"), singleAttribute(qname("xmlns"), Xmlns.BATCH_RESULT));
    6.85 +		Map<QName, String> attributes = new LinkedHashMap<>(2);
    6.86 +		attributes.put(qname("xmlns"), Xmlns.RELPIPE);
    6.87 +		attributes.put(new QName(null, XML_NS_PREFIX_SQLDK, "xmlns"), Xmlns.SQLDK);
    6.88 +		printStartElement(qname("relpipe"), attributes);
    6.89 +		statementCounter = 0;
    6.90 +		resultSetCounter = 0;
    6.91 +
    6.92  	}
    6.93  
    6.94  	@Override
    6.95 @@ -76,64 +123,101 @@
    6.96  	@Override
    6.97  	public void writeStartDatabase(DatabaseDefinition databaseDefinition) {
    6.98  		super.writeStartDatabase(databaseDefinition);
    6.99 +		currentDatabaseName = databaseDefinition.getName();
   6.100  		Map<QName, String> attributes = databaseDefinition.getName() == null ? null : singleAttribute(qname("name"), databaseDefinition.getName());
   6.101 -		printStartElement(qname("database"), attributes);
   6.102 +		printEmptyElement(qnameDK("database-start"), attributes);
   6.103  	}
   6.104  
   6.105  	@Override
   6.106  	public void writeEndDatabase() {
   6.107  		super.writeEndDatabase();
   6.108 -		printEndElement();
   6.109 +		Map<QName, String> attributes = currentDatabaseName == null ? null : singleAttribute(qname("name"), currentDatabaseName);
   6.110 +		printEmptyElement(qnameDK("database-end"), attributes);
   6.111 +	}
   6.112 +
   6.113 +	private String getCurrentStatementName() {
   6.114 +		return "s" + statementCounter;
   6.115  	}
   6.116  
   6.117  	@Override
   6.118  	public void writeStartStatement() {
   6.119  		super.writeStartStatement();
   6.120 -		printStartElement(qname("statement"));
   6.121 +		statementCounter++;
   6.122 +		printEmptyElement(qnameDK("statement-start"), singleAttribute(qname("id"), getCurrentStatementName()));
   6.123  	}
   6.124  
   6.125  	@Override
   6.126  	public void writeEndStatement() {
   6.127  		super.writeEndStatement();
   6.128 -		printEndElement();
   6.129 +		printEmptyElement(qnameDK("statement-end"), singleAttribute(qname("id"), getCurrentStatementName()));
   6.130  	}
   6.131  
   6.132  	@Override
   6.133  	public void writeQuery(String sql) {
   6.134  		super.writeQuery(sql);
   6.135 -		printTextElement(qname("sql"), null, sql);
   6.136 +		printTextElement(qnameDK("sql"), singleAttribute(qname(XML_ATTRIBUTE_STATEMENT), getCurrentStatementName()), sql);
   6.137  	}
   6.138  
   6.139  	@Override
   6.140  	public void writeParameters(List<? extends Parameter> parameters) {
   6.141  		super.writeParameters(parameters);
   6.142  
   6.143 -		for (Parameter p : notNull(parameters)) {
   6.144 +		if (parameters != null && parameters.size() > 0) {
   6.145  
   6.146 -			Map<QName, String> attributes = new LinkedHashMap<>(2);
   6.147 -			if (p instanceof NamedParameter) {
   6.148 -				attributes.put(qname("name"), ((NamedParameter) p).getName());
   6.149 +			printStartElement(qnameDK("parameters"), singleAttribute(qname(XML_ATTRIBUTE_STATEMENT), getCurrentStatementName()));
   6.150 +
   6.151 +			for (Parameter p : notNull(parameters)) {
   6.152 +
   6.153 +				Map<QName, String> attributes = new LinkedHashMap<>(2);
   6.154 +				if (p instanceof NamedParameter) {
   6.155 +					attributes.put(qname(XML_ATTRIBUTE_NAME), ((NamedParameter) p).getName());
   6.156 +				}
   6.157 +				attributes.put(qname(XML_ATTRIBUTE_TYPE), p.getType().name());
   6.158 +
   6.159 +				printTextElement(qnameDK("parameter"), attributes, String.valueOf(p.getValue()));
   6.160  			}
   6.161 -			attributes.put(qname("type"), p.getType().name());
   6.162  
   6.163 -			printTextElement(qname("parameter"), attributes, String.valueOf(p.getValue()));
   6.164 +			printEndElement();
   6.165 +
   6.166  		}
   6.167  
   6.168  	}
   6.169  
   6.170 +	private String getCurrentRelationName() {
   6.171 +		// TODO: support custom names (add CLI option)
   6.172 +		return "r" + resultSetCounter;
   6.173 +	}
   6.174 +
   6.175  	@Override
   6.176  	public void writeStartResultSet(ColumnsHeader header) {
   6.177  		super.writeStartResultSet(header);
   6.178 -		printStartElement(qname("resultSet"));
   6.179 +		resultSetCounter++;
   6.180 +		printStartElement(qname(XML_ELEMENT_RELATION), singleAttribute(qnameDK(XML_ATTRIBUTE_STATEMENT), getCurrentStatementName()));
   6.181 +		printTextElement(qname(XML_ELEMENT_NAME), null, getCurrentRelationName());
   6.182  
   6.183 +		printStartElement(qname("attributes-metadata"));
   6.184  		for (ColumnDescriptor cd : header.getColumnDescriptors()) {
   6.185 -			Map<QName, String> attributes = new LinkedHashMap<>(4);
   6.186 -			attributes.put(qname("label"), cd.getLabel());
   6.187 -			attributes.put(qname("name"), cd.getName());
   6.188 -			attributes.put(qname("typeName"), cd.getTypeName());
   6.189 -			attributes.put(qname("type"), String.valueOf(cd.getType()));
   6.190 -			printEmptyElement(qname("columnHeader"), attributes);
   6.191 +			Map<QName, String> attributes = new LinkedHashMap<>(6);
   6.192 +
   6.193 +			attributes.put(qname(XML_ATTRIBUTE_NAME), cd.getLabel());
   6.194 +			attributes.put(qname(XML_ATTRIBUTE_TYPE), toRelpipeType(cd.getType()));
   6.195 +
   6.196 +			attributes.put(qnameDK("tableName"), cd.getTableName());
   6.197 +			attributes.put(qnameDK("columnName"), cd.getName());
   6.198 +			attributes.put(qnameDK("jdbcTypeName"), cd.getTypeName());
   6.199 +			attributes.put(qnameDK("jdbcType"), String.valueOf(cd.getType()));
   6.200 +
   6.201 +			printEmptyElement(qname("attribute-metadata"), attributes);
   6.202  		}
   6.203 +		printEndElement();
   6.204 +	}
   6.205 +
   6.206 +	/**
   6.207 +	 * @param jdbcType value from {@linkplain Types}
   6.208 +	 * @return
   6.209 +	 */
   6.210 +	private String toRelpipeType(int jdbcType) {
   6.211 +		return RELPIPE_TYPES.getOrDefault(jdbcType, RELPIPE_TYPE_STRING);
   6.212  	}
   6.213  
   6.214  	@Override
   6.215 @@ -145,7 +229,7 @@
   6.216  	@Override
   6.217  	public void writeStartRow() {
   6.218  		super.writeStartRow();
   6.219 -		printStartElement(qname("row"));
   6.220 +		printStartElement(qname(XML_ELEMENT_RECORD));
   6.221  	}
   6.222  
   6.223  	@Override
   6.224 @@ -155,21 +239,23 @@
   6.225  		Map<QName, String> attributes = null;
   6.226  		if (labeledColumns) {
   6.227  			attributes = new LinkedHashMap<>(2);
   6.228 -			attributes.put(qname("label"), getCurrentColumnsHeader().getColumnDescriptors().get(getCurrentColumnsCount() - 1).getLabel());
   6.229 +			attributes.put(qname(XML_ATTRIBUTE_NAME), getCurrentColumnsHeader().getColumnDescriptors().get(getCurrentColumnsCount() - 1).getLabel());
   6.230 +			attributes.put(qname(XML_ATTRIBUTE_TYPE), toRelpipeType(getCurrentColumnsHeader().getColumnDescriptors().get(getCurrentColumnsCount() - 1).getType()));
   6.231  		}
   6.232  
   6.233  		if (value == null) {
   6.234  			if (attributes == null) {
   6.235  				attributes = new LinkedHashMap<>(2);
   6.236  			}
   6.237 -			attributes.put(qname("null"), "true");
   6.238 -			printEmptyElement(qname("column"), attributes);
   6.239 +			// TODO: synchronize syntax with Relational pipes (after adding support of null values)
   6.240 +			attributes.put(qnameDK("null"), "true");
   6.241 +			printEmptyElement(qname(XML_ELEMENT_ATTRIBUTE), attributes);
   6.242  		} else if (value instanceof Array) {
   6.243  
   6.244  			Array sqlArray = (Array) value;
   6.245  			try {
   6.246  				Object[] array = (Object[]) sqlArray.getArray();
   6.247 -				printStartElement(qname("column"), attributes);
   6.248 +				printStartElement(qname(XML_ELEMENT_ATTRIBUTE), attributes);
   6.249  				printArray(array);
   6.250  				printEndElement();
   6.251  			} catch (SQLException e) {
   6.252 @@ -186,7 +272,7 @@
   6.253  						// }
   6.254  					}
   6.255  
   6.256 -					printStartElement(qname("column"), attributes);
   6.257 +					printStartElement(qname(XML_ELEMENT_ATTRIBUTE), attributes);
   6.258  					// FIXME: instanceof SQLXML, see below
   6.259  					printArray(arrayList.toArray());
   6.260  					printEndElement();
   6.261 @@ -203,25 +289,26 @@
   6.262  			SQLXML xml = (SQLXML) value;
   6.263  			// TODO: parse DOM/SAX and transplant XML, don't escape (optional)
   6.264  			try {
   6.265 -				printTextElement(qname("column"), attributes, xml.getString());
   6.266 +				printTextElement(qname(XML_ELEMENT_ATTRIBUTE), attributes, xml.getString());
   6.267  			} catch (SQLException e) {
   6.268  				log.log(Level.SEVERE, "Unable to format XML", e);
   6.269  				writeColumnValue(String.valueOf(value));
   6.270  			}
   6.271  		} else {
   6.272 -			printTextElement(qname("column"), attributes, toString(value));
   6.273 +			printTextElement(qname(XML_ELEMENT_ATTRIBUTE), attributes, toString(value));
   6.274  		}
   6.275  	}
   6.276  
   6.277  	private void printArray(Object[] array) {
   6.278 -		printStartElement(qname("array"));
   6.279 +		// TODO: synchronize array syntax with Relational pipes
   6.280 +		printStartElement(qnameDK("array"));
   6.281  		for (Object o : array) {
   6.282  			if (o instanceof Object[]) {
   6.283 -				printStartElement(qname("item"));
   6.284 +				printStartElement(qnameDK("item"));
   6.285  				printArray((Object[]) o);
   6.286  				printEndElement();
   6.287  			} else {
   6.288 -				printTextElement(qname("item"), null, String.valueOf(o));
   6.289 +				printTextElement(qnameDK("item"), null, String.valueOf(o));
   6.290  			}
   6.291  		}
   6.292  		printEndElement();
   6.293 @@ -236,7 +323,7 @@
   6.294  	@Override
   6.295  	public void writeUpdatesResult(int updatedRowsCount) {
   6.296  		super.writeUpdatesResult(updatedRowsCount);
   6.297 -		printTextElement(qname("updatedRows"), null, String.valueOf(updatedRowsCount));
   6.298 +		printTextElement(qnameDK("updatedRecords"), singleAttribute(qnameDK(XML_ATTRIBUTE_STATEMENT), getCurrentStatementName()), String.valueOf(updatedRowsCount));
   6.299  	}
   6.300  
   6.301  	protected String toString(Object value) {