package org.firesoa.common.schema; import java.io.ByteArrayInputStream; import java.nio.charset.Charset; import java.sql.Connection; import java.sql.ParameterMetaData; import java.sql.PreparedStatement; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; import java.util.Vector; import javax.xml.namespace.QName; import org.apache.commons.lang.StringUtils; import org.apache.ws.commons.schema.XmlSchema; import org.apache.ws.commons.schema.XmlSchemaCollection; import org.apache.ws.commons.schema.XmlSchemaComplexType; import org.apache.ws.commons.schema.XmlSchemaElement; import org.apache.ws.commons.schema.XmlSchemaForm; import org.apache.ws.commons.schema.XmlSchemaSequence; import org.apache.ws.commons.schema.constants.Constants; import org.gibello.zql.ParseException; import org.gibello.zql.ZConstant; import org.gibello.zql.ZDelete; import org.gibello.zql.ZExp; import org.gibello.zql.ZExpression; import org.gibello.zql.ZInsert; import org.gibello.zql.ZQuery; import org.gibello.zql.ZStatement; import org.gibello.zql.ZUpdate; import org.gibello.zql.ZqlParser; public class SQLSchemaGenerator { public static final String DATA_SET_ELEMENT = "DataSet"; public static final String ROW_ELEMENT = "Row"; public static final String WHERE_ELEMENT = "Where"; public static final String SET_ELEMENT = "Set"; public static final String UPDATE_ELEMENT = "Update"; public static final String VALUES_ELEMENT = "Values"; public static ZStatement parseSQL(String sqlArg) throws ParseException { String sql = sqlArg; if (!sql.endsWith(";")) { sql = sql + ";"; } if (StringUtils.isEmpty(sql)) return null; ByteArrayInputStream in = null; try { in = new ByteArrayInputStream(sql.getBytes(Charset.defaultCharset().name())); } catch (Exception e) { } if (in == null) return null; ZqlParser zqlGenerator = new ZqlParser(in); try { ZStatement zstatement = zqlGenerator.readStatement();// Sql语句在设置到DBQuery时,经过了校验 return zstatement; } catch (ParseException e) { throw e; } } public static XmlSchemaCollection generateXmlSchemaCollectionForSQL( String sql, String targetNsUri, Connection conn) throws ParseException, SQLException { ZStatement zstatement = parseSQL(sql); if (zstatement != null && (zstatement instanceof ZQuery)) { return generateQuerySchema((ZQuery) zstatement, sql, targetNsUri, conn); } else if (zstatement != null && (zstatement instanceof ZDelete)) { return generateDeleteSchema((ZDelete) zstatement, sql, targetNsUri, conn); } else if (zstatement != null && (zstatement instanceof ZUpdate)) { return generateUpdateSchema((ZUpdate) zstatement, sql, targetNsUri, conn); }else if (zstatement != null && (zstatement instanceof ZInsert)){ return generateInsertSchema((ZInsert) zstatement, sql, targetNsUri, conn); } return null; } protected static XmlSchemaCollection generateUpdateSchema(ZUpdate zu, String sql, String targetNsUri, Connection conn) throws ParseException, SQLException { ParameterMetaData parameterMetaData = null; PreparedStatement pstmt = conn.prepareStatement(sql); parameterMetaData = pstmt.getParameterMetaData(); // ////////////////////////////////////////////////////////// // /////////////////// 构造xsd schema /////////////////// // ////////////////////////////////////////////////////////// XmlSchemaCollection xmlSchemaCollection = new XmlSchemaCollection(); XmlSchema xmlschema = new XmlSchema(targetNsUri, xmlSchemaCollection); xmlschema.setElementFormDefault(XmlSchemaForm.QUALIFIED); xmlschema.setAttributeFormDefault(XmlSchemaForm.UNQUALIFIED); // /////////////////1、构造set 的schema ////////////////////// int count = zu.getColumnUpdateCount(); Hashtable set = zu.getSet(); int parameterIndex = 0; XmlSchemaSequence setFieldsTypeSequence = new XmlSchemaSequence(); for (int index = 1; index <= count; index++) { String name = zu.getColumnUpdateName(index); ZExp e = (ZExp) set.get(name); if (isPreparedColumn(e)) { parameterIndex++; int sqlType = parameterMetaData .getParameterType(parameterIndex); QName type = DataMapper.SQLTYPES_2_XSD_QNAME_MAP.get(sqlType); XmlSchemaElement fieldElement = new XmlSchemaElement(xmlschema, false); fieldElement.setName(name); fieldElement.setSchemaTypeName(type != null ? type : Constants.XSD_STRING); setFieldsTypeSequence.getItems().add(fieldElement); } } XmlSchemaComplexType setFieldsType = new XmlSchemaComplexType( xmlschema, true); setFieldsType.setName(SET_ELEMENT + "Type"); setFieldsType.setParticle(setFieldsTypeSequence); // /////////////// 2、构造update条件的schema ///////////////// ZExpression w = (ZExpression) zu.getWhere(); List<String> whereColumns = new ArrayList<String>(); if (w != null) { handleWhere(w, whereColumns); } XmlSchemaSequence whereFieldsTypeSequence = new XmlSchemaSequence(); for (int i = 0; i < whereColumns.size(); i++) { String preparedColumn = whereColumns.get(i); XmlSchemaElement fieldElement = new XmlSchemaElement(xmlschema, false); fieldElement.setName(preparedColumn); QName type = DataMapper.SQLTYPES_2_XSD_QNAME_MAP .get(parameterMetaData.getParameterType(i + 1 + parameterIndex)); fieldElement.setSchemaTypeName(type != null ? type : Constants.XSD_STRING); whereFieldsTypeSequence.getItems().add(fieldElement); } XmlSchemaComplexType whereFieldsType = new XmlSchemaComplexType( xmlschema, true); whereFieldsType.setName(WHERE_ELEMENT + "Type"); whereFieldsType.setParticle(whereFieldsTypeSequence); // /////////////// 3、构造整个update的schema ///////////////// XmlSchemaSequence updateTypeSequence = new XmlSchemaSequence(); XmlSchemaElement setFieldsElement = new XmlSchemaElement(xmlschema, false); setFieldsElement.setName(SET_ELEMENT); setFieldsElement.setSchemaTypeName(setFieldsType.getQName()); updateTypeSequence.getItems().add(setFieldsElement); XmlSchemaElement whereFieldsElement = new XmlSchemaElement(xmlschema, false); whereFieldsElement.setName(WHERE_ELEMENT); whereFieldsElement.setSchemaTypeName(whereFieldsType.getQName()); updateTypeSequence.getItems().add(whereFieldsElement); XmlSchemaComplexType updateType = new XmlSchemaComplexType(xmlschema, true); updateType.setName(UPDATE_ELEMENT + "Type"); updateType.setParticle(updateTypeSequence); XmlSchemaElement updateElement = new XmlSchemaElement(xmlschema, true); updateElement.setName(UPDATE_ELEMENT); updateElement.setSchemaTypeName(updateType.getQName()); return xmlSchemaCollection; } protected static XmlSchemaCollection generateInsertSchema(ZInsert zi, String sql, String targetNsUri, Connection conn) throws ParseException, SQLException { ParameterMetaData parameterMetaData = null; PreparedStatement pstmt = conn.prepareStatement(sql); parameterMetaData = pstmt.getParameterMetaData(); // ////////////////////////////////////////////////////////// // /////////////////// 构造xsd schema /////////////////// // ////////////////////////////////////////////////////////// XmlSchemaCollection xmlSchemaCollection = new XmlSchemaCollection(); XmlSchema xmlschema = new XmlSchema(targetNsUri, xmlSchemaCollection); xmlschema.setElementFormDefault(XmlSchemaForm.QUALIFIED); xmlschema.setAttributeFormDefault(XmlSchemaForm.UNQUALIFIED); // /////////////////1、构造set 的schema ////////////////////// Vector values = zi.getValues(); Vector columns = zi.getColumns(); if (columns==null || columns.size()==0){ throw new ParseException("The insert sql style is not supported; column's names are expected. "); } int parameterIndex = 0; XmlSchemaSequence valueFieldsTypeSequence = new XmlSchemaSequence(); for (int index = 0; index < values.size(); index++) { ZExp e = (ZExp) values.get(index); if (isPreparedColumn(e)) { parameterIndex++; int sqlType = parameterMetaData .getParameterType(parameterIndex); QName type = DataMapper.SQLTYPES_2_XSD_QNAME_MAP.get(sqlType); XmlSchemaElement fieldElement = new XmlSchemaElement(xmlschema, false); fieldElement.setName((String)columns.get(index)); fieldElement.setSchemaTypeName(type != null ? type : Constants.XSD_STRING); valueFieldsTypeSequence.getItems().add(fieldElement); } } XmlSchemaComplexType valueFieldsType = new XmlSchemaComplexType( xmlschema, true); valueFieldsType.setName(VALUES_ELEMENT + "Type"); valueFieldsType.setParticle(valueFieldsTypeSequence); XmlSchemaElement valueFieldsElement = new XmlSchemaElement(xmlschema, true); valueFieldsElement.setName(VALUES_ELEMENT); valueFieldsElement.setSchemaTypeName(valueFieldsType.getQName()); return xmlSchemaCollection; } protected static XmlSchemaCollection generateDeleteSchema(ZDelete zd, String sql, String targetNsUri, Connection conn) throws ParseException, SQLException { ParameterMetaData parameterMetaData = null; PreparedStatement pstmt = conn.prepareStatement(sql); parameterMetaData = pstmt.getParameterMetaData(); // ////////////////////////////////////////////////////////// // /////////////////// 构造xsd schema /////////////////// // ////////////////////////////////////////////////////////// XmlSchemaCollection xmlSchemaCollection = new XmlSchemaCollection(); XmlSchema xmlschema = new XmlSchema(targetNsUri, xmlSchemaCollection); xmlschema.setElementFormDefault(XmlSchemaForm.QUALIFIED); xmlschema.setAttributeFormDefault(XmlSchemaForm.UNQUALIFIED); // /////////////// 1、构造删除条件的schema ///////////////// ZExpression w = (ZExpression) zd.getWhere(); List<String> pareparedColumns = new ArrayList<String>(); if (w != null) { handleWhere(w, pareparedColumns); } XmlSchemaSequence whereFieldsTypeSequence = new XmlSchemaSequence(); for (int i = 0; i < pareparedColumns.size(); i++) { String preparedColumn = pareparedColumns.get(i); XmlSchemaElement fieldElement = new XmlSchemaElement(xmlschema, false); fieldElement.setName(preparedColumn); QName type = DataMapper.SQLTYPES_2_XSD_QNAME_MAP .get(parameterMetaData.getParameterType(i + 1)); fieldElement.setSchemaTypeName(type != null ? type : Constants.XSD_STRING); whereFieldsTypeSequence.getItems().add(fieldElement); } XmlSchemaComplexType whereFieldsType = new XmlSchemaComplexType( xmlschema, true); whereFieldsType.setName(WHERE_ELEMENT + "Type"); whereFieldsType.setParticle(whereFieldsTypeSequence); XmlSchemaElement whereFieldsElement = new XmlSchemaElement(xmlschema, true); whereFieldsElement.setName(WHERE_ELEMENT); whereFieldsElement.setSchemaTypeName(whereFieldsType.getQName()); return xmlSchemaCollection; } protected static XmlSchemaCollection generateQuerySchema(ZQuery zq, String sql, String targetNsUri, Connection conn) throws ParseException, SQLException { ParameterMetaData parameterMetaData = null; ResultSetMetaData rsMetaData = null; PreparedStatement pstmt = conn.prepareStatement(sql); parameterMetaData = pstmt.getParameterMetaData(); rsMetaData = pstmt.getMetaData(); // ////////////////////////////////////////////////////////// // /////////////////// 构造xsd schema /////////////////// // ////////////////////////////////////////////////////////// XmlSchemaCollection xmlSchemaCollection = new XmlSchemaCollection(); XmlSchema xmlschema = new XmlSchema(targetNsUri, xmlSchemaCollection); xmlschema.setElementFormDefault(XmlSchemaForm.QUALIFIED); xmlschema.setAttributeFormDefault(XmlSchemaForm.UNQUALIFIED); // /////////////// 1、构造查询条件的schema ///////////////// ZExpression w = (ZExpression) zq.getWhere(); List<String> pareparedColumns = new ArrayList<String>(); if (w != null) { handleWhere(w, pareparedColumns); } XmlSchemaSequence whereFieldsTypeSequence = new XmlSchemaSequence(); for (int i = 0; i < pareparedColumns.size(); i++) { String preparedColumn = pareparedColumns.get(i); XmlSchemaElement fieldElement = new XmlSchemaElement(xmlschema, false); fieldElement.setName(preparedColumn); QName type = DataMapper.SQLTYPES_2_XSD_QNAME_MAP .get(parameterMetaData.getParameterType(i + 1)); fieldElement.setSchemaTypeName(type != null ? type : Constants.XSD_STRING); whereFieldsTypeSequence.getItems().add(fieldElement); } XmlSchemaComplexType whereFieldsType = new XmlSchemaComplexType( xmlschema, true); whereFieldsType.setName(WHERE_ELEMENT + "Type"); whereFieldsType.setParticle(whereFieldsTypeSequence); XmlSchemaElement whereFieldsElement = new XmlSchemaElement(xmlschema, true); whereFieldsElement.setName(WHERE_ELEMENT); whereFieldsElement.setSchemaTypeName(whereFieldsType.getQName()); // /////////////////// 2、构造查询结果的schema ///////////////////// Vector sel = zq.getSelect(); XmlSchemaSequence rowSequence = new XmlSchemaSequence(); int columnCount = rsMetaData.getColumnCount(); for (int i = 1; i <= columnCount; i++) { XmlSchemaElement fieldElement = new XmlSchemaElement(xmlschema, false); fieldElement.setName(rsMetaData.getColumnName(i).toLowerCase()); QName type = DataMapper.SQLTYPES_2_XSD_QNAME_MAP.get(rsMetaData .getColumnType(i)); fieldElement.setSchemaTypeName(type != null ? type : Constants.XSD_STRING); rowSequence.getItems().add(fieldElement); } // 1.1行类型行元素 XmlSchemaComplexType datarowType = new XmlSchemaComplexType(xmlschema, true); datarowType.setName(ROW_ELEMENT + "Type"); datarowType.setParticle(rowSequence); XmlSchemaElement rowElement = new XmlSchemaElement(xmlschema, true); rowElement.setName(ROW_ELEMENT); rowElement.setSchemaTypeName(datarowType.getQName()); // 1.2data_set类型及data_set元素 XmlSchemaElement rowElement_inner = new XmlSchemaElement(xmlschema, false); rowElement_inner.setName(ROW_ELEMENT); rowElement_inner.setSchemaTypeName(datarowType.getQName()); XmlSchemaSequence datasetSequence = new XmlSchemaSequence(); datasetSequence.getItems().add(rowElement_inner); XmlSchemaComplexType datasetType = new XmlSchemaComplexType(xmlschema, true); datasetType.setName(DATA_SET_ELEMENT + "Type"); datasetType.setParticle(datasetSequence); XmlSchemaElement datasetElement = new XmlSchemaElement(xmlschema, true); datasetElement.setName(DATA_SET_ELEMENT); datasetElement.setSchemaTypeName(datasetType.getQName()); // 构造schema结束 return xmlSchemaCollection; } protected static void handleWhere(ZExp e, List<String> pareparedColumns) { // if(meta != null) System.out.println(meta); if (!(e instanceof ZExpression)) return; ZExpression w = (ZExpression) e; Vector operands = w.getOperands(); if (operands == null) return; // Look for prepared column ("?") String prepared = null; for (int i = 0; i < operands.size(); i++) { if (isPreparedColumn((ZExp) operands.elementAt(i))) { prepared = ((ZConstant) operands.elementAt(0)).getValue(); // if (operands.size() != 2) { // throw new Exception("ERROR in where clause ?? found:" // + w.toString()); // } break; } } if (prepared != null) { // prepared contains the (raw) column or alias // name pareparedColumns.add(prepared); } else { // No prepared column, go further analyzing the expression for (int i = 0; i < operands.size(); i++) { handleWhere(w.getOperand(i), pareparedColumns); // WARNING - // Recursive // call... } } } protected static boolean isPreparedColumn(ZExp v) { return (v instanceof ZExpression && ((ZExpression) v).getOperator() .equals("?")); } }