package gov.nist.registry.ws;
import gov.nist.registry.common2.exception.XdsInternalException;
import gov.nist.registry.common2.registry.MetadataSupport;
import java.util.Iterator;
import java.util.List;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.xpath.AXIOMXPath;
import org.jaxen.JaxenException;
public class SqlRepair {
int start_at_word = 0;
public String returnType(OMElement query) {
OMElement response_option_ele = MetadataSupport.firstChildWithLocalName(query, "ResponseOption");
if (response_option_ele == null)
return null;
String return_type = response_option_ele.getAttributeValue(MetadataSupport.return_type_qname);
return return_type;
}
public void repair(OMElement query) throws XdsInternalException, SqlRepairException {
OMElement query_element = find_sql_query_element(query);
String sql_text = query_element.getText().trim();
OMElement response_option_ele = MetadataSupport.firstChildWithLocalName(query, "ResponseOption");
if (response_option_ele == null)
throw new SqlRepairException("Cannot find ResponseOption element");
String return_type = response_option_ele.getAttributeValue(MetadataSupport.return_type_qname);
if (return_type == null)
throw new SqlRepairException("Cannot find returnType option of ResponseOption");
if (!return_type.equals("ObjectRef") && !return_type.equals("LeafClass") )
throw new SqlRepairException("Invalid returnType: only ObjectRef or LeafClass are acceptable");
String x = sql_text.replaceAll("\\(", " ( ");
x = x.replaceAll("\\)", " ) ");
String[] words = x.split("[ \t\n]");
boolean repaired = true;
int i = 0;
start_at_word = 0;
for ( ; i<20 && repaired; i++) {
// System.out.println("fix?");
repaired = repair_once(words, return_type);
// if (repaired) {
// System.out.print("Fixed: ");
// for (int j=0; j<words.length; j++) System.out.print(" " + words[j]);
// System.out.println("");
// }
}
if (i >= 20)
throw new SqlRepairException("SQL repair failed - cannot forward to backend registry");
StringBuffer buf = new StringBuffer();
for (int j=0; j<words.length; j++ ) {
buf.append(" " + words[j]);
}
query_element.setText(buf.toString());
}
private boolean repair_once(String[] words, String return_type)
throws SqlRepairException {
int select_i = -1;
int from_i = -1;
// System.out.println("starting at " + start_at_word);
for (int i=start_at_word; i<words.length && (select_i == -1 || from_i == -1); i++) {
if ( select_i == -1 && words[i].equalsIgnoreCase("select")) {
select_i = i;
}
if ( from_i == -1 && words[i].equalsIgnoreCase("from")) {
from_i = i;
}
}
if (start_at_word > 0 && select_i == -1)
return false; // done
// for next time through loop
start_at_word = from_i + 1;
if (select_i == -1)
throw new SqlRepairException("SqlRepair: SQL keyword SELECT not found");
if (from_i == -1)
throw new SqlRepairException("SqlRepair: SQL keyword FROM not found");
if (from_i < select_i) {
throw new SqlRepairException("SqlRepair: SQL keyword FROM found before keyword SELECT");
}
int range_from = select_i + 1;
int range_to = from_i - 1;
if (range_to < range_from)
throw new SqlRepairException("SqlRepair: Cannot find SELECT variable");
for (int i=range_from; i<=range_to; i++) {
String word = words[i];
if (word.equals("*"))
throw new SqlRepairException("SqlRepair: XDS does not allow SQL queries using SELECT *, must be SELECT something.id" );
if (word.equalsIgnoreCase("distinct"))
continue;
}
boolean fixed = false;
// System.out.println("select_i = " + select_i + " from_i = " + from_i + " returnType = " + return_type);
for (int i=select_i+1; i< from_i; i++ ) {
String word = words[i];
if (word.endsWith(".id") && return_type.equals("LeafClass")) {
words[i] = "*";
fixed = true;
}
}
return fixed;
// StringBuffer buf = new StringBuffer();
// for (int i=0; i<words.length; i++) {
// buf.append(words[i]);
// buf.append(" ");
// }
// String repaired_sql_text = buf.toString();
// System.out.println(repaired_sql_text.substring(0, 80));
// return repaired_sql_text;
}
public String get_query_text(OMElement query) throws XdsInternalException, SqlRepairException {
OMElement element = find_sql_query_element(query);
return element.getText();
}
public OMElement find_sql_query_element(OMElement query) throws XdsInternalException, SqlRepairException {
try {
AXIOMXPath xpathExpression = new AXIOMXPath ("//*[local-name() = 'SQLQuery']");
List nodeList = xpathExpression.selectNodes(query);
Iterator it = nodeList.iterator();
if (! it.hasNext())
throw new SqlRepairException("Cannot find SQLQuery element in query");
OMElement q = (OMElement) it.next();
return q;
} catch (JaxenException e) {
throw new XdsInternalException("Jaxen Exception inside SQLRepair:find_sql_query_element");
}
}
}