View Javadoc

1   /*
2    ORDI - Ontology Repository and Data Integration
3   
4    Copyright (c) 2004-2007, OntoText Lab. / SIRMA
5   
6    This library is free software; you can redistribute it and/or modify it under
7    the terms of the GNU Lesser General Public License as published by the Free
8    Software Foundation; either version 2.1 of the License, or (at your option)
9    any later version.
10   This library is distributed in the hope that it will be useful, but WITHOUT
11   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12   FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
13   details.
14   You should have received a copy of the GNU Lesser General Public License along
15   with this library; if not, write to the Free Software Foundation, Inc.,
16   59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17   */
18  package com.ontotext.ordi.mapper.rdbms;
19  
20  import java.util.HashMap;
21  import java.util.Iterator;
22  import java.util.List;
23  import java.util.Map;
24  
25  import org.eclipse.datatools.modelbase.sql.query.PredicateLike;
26  import org.eclipse.datatools.modelbase.sql.query.QueryExpressionBody;
27  import org.eclipse.datatools.modelbase.sql.query.QuerySearchCondition;
28  import org.eclipse.datatools.modelbase.sql.query.QuerySelect;
29  import org.eclipse.datatools.modelbase.sql.query.QuerySelectStatement;
30  import org.eclipse.datatools.modelbase.sql.query.QueryStatement;
31  import org.eclipse.datatools.modelbase.sql.query.ResultColumn;
32  import org.eclipse.datatools.modelbase.sql.query.SQLQueryModelFactory;
33  import org.eclipse.datatools.modelbase.sql.query.SearchConditionCombined;
34  import org.eclipse.datatools.modelbase.sql.query.SearchConditionCombinedOperator;
35  import org.eclipse.datatools.modelbase.sql.query.ValueExpressionColumn;
36  import org.eclipse.datatools.modelbase.sql.query.ValueExpressionVariable;
37  import org.eclipse.datatools.modelbase.sql.query.helper.StatementHelper;
38  import org.eclipse.datatools.sqltools.parsers.sql.SQLParseErrorInfo;
39  import org.eclipse.datatools.sqltools.parsers.sql.SQLParserException;
40  import org.eclipse.datatools.sqltools.parsers.sql.SQLParserInternalException;
41  import org.eclipse.datatools.sqltools.parsers.sql.query.SQLQueryParseResult;
42  import org.eclipse.datatools.sqltools.parsers.sql.query.SQLQueryParserManager;
43  import org.eclipse.datatools.sqltools.parsers.sql.query.SQLQueryParserManagerProvider;
44  import org.eclipse.emf.common.util.EList;
45  
46  import com.ontotext.ordi.exception.ORDIRuntimeException;
47  import com.ontotext.ordi.mapper.exceptions.IllegalQueryFormatException;
48  
49  public class SqlGenerator {
50  
51      private QuerySelectStatement query;
52      private ResultColumn subjectColumn;
53      private ResultColumn objectColumn;
54      private String sqlQuery;
55      private Map<Integer, String> generatedQueries;
56  
57      public SqlGenerator(String sqlQuery) {
58          if (sqlQuery == null) {
59              throw new IllegalArgumentException();
60          }
61          this.sqlQuery = sqlQuery;
62      }
63  
64      public String generateSQL(boolean hasSubject, boolean hasObject) {
65          if (query == null) {
66              validate();
67          }
68          if (generatedQueries == null) {
69              generateAllVariations();
70          }
71          int type = 0;
72          if (hasSubject)
73              type = type ^ 1;
74          if (hasObject)
75              type = type << 1 ^ 1;
76          return generatedQueries.get(type);
77      }
78  
79      /**
80       * Checks whether the query is valid SQL select query with two columns.
81       */
82      @SuppressWarnings("unchecked")
83      public void validate() {
84          try {
85              SQLQueryParserManager parserManager = SQLQueryParserManagerProvider
86                      .getInstance().getParserManager(null, null);
87              SQLQueryParseResult parseResult = parserManager
88                      .parseQuery(sqlQuery);
89              QueryStatement queryStatement = parseResult.getQueryStatement();
90              if (queryStatement instanceof QuerySelectStatement) {
91                  query = (QuerySelectStatement) queryStatement;
92              } else {
93                  throw new IllegalQueryFormatException(String.format(
94                          "Only select queries are allowed!\n%s", sqlQuery));
95              }
96              QuerySelect querySelect = null;
97              QueryExpressionBody queryBody = query.getQueryExpr().getQuery();
98              if (queryBody instanceof QuerySelect) {
99                  querySelect = (QuerySelect) queryBody;
100             } else {
101                 throw new IllegalQueryFormatException(String.format(
102                         "Only single select queris are allowed!\n%s", sqlQuery));
103             }
104             EList resultColumns = querySelect.getSelectClause();
105             if (resultColumns.size() != 2) {
106                 String msg = resultColumns.size() == 0 ? "Wildcards in select queries are not supported!"
107                         : String.format(
108                                 "The query has only %d result columns:\n%s",
109                                 resultColumns, query.getSQL());
110                 throw new IllegalQueryFormatException(msg);
111             }
112             subjectColumn = (ResultColumn) resultColumns.get(0);
113             objectColumn = (ResultColumn) resultColumns.get(1);
114         } catch (SQLParserException spe) {
115             List syntacticErrors = spe.getErrorInfoList();
116             Iterator itr = syntacticErrors.iterator();
117             StringBuffer buffer = new StringBuffer();
118             while (itr.hasNext()) {
119                 SQLParseErrorInfo errorInfo = (SQLParseErrorInfo) itr.next();
120                 buffer.append(String.format(
121                         "Error at line %d position %d\nError mesage: %s\n",
122                         errorInfo.getLineNumberStart(), errorInfo
123                                 .getColumnNumberStart(), errorInfo
124                                 .getParserErrorMessage()));
125             }
126             throw new IllegalQueryFormatException(buffer.toString(), spe);
127         } catch (SQLParserInternalException spie) {
128             throw new ORDIRuntimeException("An internal excpetion occured!",
129                     spie);
130         }
131     }
132 
133     protected PredicateLike generatePredicateLikeWihVariable(
134             ResultColumn resultColumn) {
135         PredicateLike like = SQLQueryModelFactory.eINSTANCE
136                 .createPredicateLike();
137         ValueExpressionVariable variable = SQLQueryModelFactory.eINSTANCE
138                 .createValueExpressionVariable();
139         ValueExpressionColumn column = StatementHelper
140                 .createColumnExpression(resultColumn.getValueExpr().getName());
141         like.setNotLike(false);
142         like.setMatchingValueExpr(column);
143         like.setPatternValueExpr(variable);
144         return like;
145     }
146 
147     /**
148      * This method generates all combinations between two independent args:
149      * argument 1: the existence of original where clause argument 2: the
150      * specification of subject or object clause
151      */
152     protected void generateAllVariations() {
153         if (query == null) {
154             validate();
155         }
156         generatedQueries = new HashMap<Integer, String>(5);
157 
158         // Generates the WHERE clauses
159         QuerySelect querySelect = (QuerySelect) subjectColumn.getContainer();
160         QuerySearchCondition originalWhere = querySelect.getWhereClause();
161         PredicateLike subjecWhere = generatePredicateLikeWihVariable(subjectColumn);
162         PredicateLike objectWhere = generatePredicateLikeWihVariable(objectColumn);
163         SearchConditionCombined combinedWhere = SQLQueryModelFactory.eINSTANCE
164                 .createSearchConditionCombined();
165         combinedWhere
166                 .setCombinedOperator(SearchConditionCombinedOperator.AND_LITERAL);
167         combinedWhere.setLeftCondition(subjecWhere);
168         combinedWhere
169                 .setRightCondition(generatePredicateLikeWihVariable(objectColumn));
170         QuerySearchCondition newWhere = null;
171 
172         // This loop generates all combinations between two independent args:
173         // arg1: originalWhere = yes/no AND
174         // arg2: newWhere = no/subject/object/subject&object
175         for (int i = 0; i < 2 * 2; i++) {
176 
177             if (i == 0) { // Original where clause
178 
179                 newWhere = originalWhere;
180 
181             } else if (i == 1) { // Only subject where clause
182 
183                 if (originalWhere == null) {
184                     newWhere = subjecWhere;
185                 } else {
186                     SearchConditionCombined combined = SQLQueryModelFactory.eINSTANCE
187                             .createSearchConditionCombined();
188                     combined.setLeftCondition(subjecWhere);
189                     combined.setRightCondition(originalWhere);
190                     newWhere = combined;
191                 }
192 
193             } else if (i == 2) { // Only object where clause
194 
195                 if (originalWhere == null) {
196                     newWhere = objectWhere;
197                 } else {
198                     SearchConditionCombined combined = SQLQueryModelFactory.eINSTANCE
199                             .createSearchConditionCombined();
200                     combined.setLeftCondition(objectWhere);
201                     combined.setRightCondition(originalWhere);
202                     newWhere = combined;
203                 }
204 
205             } else if (i == 3) { // Both subject and object where clauses
206 
207                 if (originalWhere == null) {
208                     SearchConditionCombined combined = SQLQueryModelFactory.eINSTANCE
209                             .createSearchConditionCombined();
210                     combined.setLeftCondition(subjecWhere);
211                     combined.setRightCondition(objectWhere);
212                     newWhere = combined;
213                 } else {
214                     SearchConditionCombined combinedInner = SQLQueryModelFactory.eINSTANCE
215                             .createSearchConditionCombined();
216                     combinedInner.setLeftCondition(subjecWhere);
217                     combinedInner.setRightCondition(objectWhere);
218                     SearchConditionCombined combined2 = SQLQueryModelFactory.eINSTANCE
219                             .createSearchConditionCombined();
220                     combined2.setLeftCondition(combinedInner);
221                     combined2.setRightCondition(originalWhere);
222                     newWhere = combined2;
223                 }
224 
225             }
226 
227             querySelect.setWhereClause(newWhere);
228             generatedQueries.put(i, querySelect.getSQL());
229         }
230     }
231 }