# Copyright (C) 2005 Meredith L. Patterson
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
import libsqlparse, tempfile, bison
from string import *
from xml.dom import *
def postorder(node): # adapted from the ASPN Python Cookbook, #201423
if node:
for n in node.childNodes:
for elem in postorder(n):
yield elem
yield node
# Ugliest. Function. Ever.
def nodeEquals(node1, node2):
if (node1.nodeType == node2.nodeType == Node.TEXT_NODE):
return (node1.nodeName == node2.nodeName and node1.nodeValue == node2.nodeValue)
else:
return (node1.nodeType == node2.nodeType and node1.nodeName == node2.nodeName and node1.nodeValue == node2.nodeValue and node1.getAttribute('option') == node2.getAttribute('option') and node1.getAttribute('target') == node2.getAttribute('target'))
# Second. Ugliest. Function. Ever.
def isEquivalentTree(exemplar, target):
if exemplar and (exemplar.nodeType == Node.TEXT_NODE):
if not target:
return False
else: # uh, hold on, can TEXT_NODEs *have* children?
for (x, y) in zip(exemplar.childNodes, target.childNodes):
isEquivalentTree(x,y)
return nodeEquals(exemplar, target)
if exemplar and (exemplar.getAttribute('irrelevant') != True):
if not target:
# the exemplar is larger than the target
return False
else:
foo = True
for (x, y) in zip(exemplar.childNodes, target.childNodes):
foo = isEquivalentTree(x, y) # Problem: we need to break the entire recursion the moment anything's
# false, and the iteration is preventing that from happening
if foo == False: break
return (foo and nodeEquals(exemplar, target))
elif target and not exemplar:
# the target is larger than the exemplar
return False
else:
if exemplar and not target:
return False
# otherwise, ignore everything underneath this node
return nodeEquals(exemplar, target)
class Dejector:
def __init__(self, query):
# Right now there's only the one parsing engine;
# in time there will be more, and thus a constructor
# parameter to reflect this.
#
# If you get a segfault when trying to initialise an
# object of this class, check and see whether
# libsqlparse-engine.so is someplace that sqlparse.py can
# find it. The dirty hack I've been using has just been
# to add . to LD_LIBRARY_PATH.
if query.find('[') == -1 and query.find(']') == -1:
self.bracketed = ''
else:
self.bracketed = join(split(query[query.index('[')+1:query.index(']')]), '')
t = tempfile.TemporaryFile()
t.write(self.stripBrackets(query))
t.seek(0)
self.p = libsqlparse.Parser()
self.exemplarTree = self.p.run(file=t).toxmldoc()
self.lowestEnclosingNode = self.markLowestEnclosingNode()
t.close()
def stripBrackets(self, str):
if str.find(']') == -1 or str.find('[') == -1: return str
return join([x for x in str if x != '[' and x != ']'], '')
def findChildString(self, node, ret = None):
if (ret == None): ret = []
if node.hasChildNodes():
for n in node.childNodes:
self.findChildString(n, ret)
if (node.nodeType == Node.TEXT_NODE):
ret.append(node.data)
return join(ret, '')
else:
if (node.nodeType == Node.TEXT_NODE):
ret.append(node.data)
return join(ret, '')
def markLowestEnclosingNode(self):
for x in postorder(self.exemplarTree):
if (self.findChildString(x).find(self.bracketed) != -1 and x.nodeType == Node.ELEMENT_NODE):
x.setAttribute('irrelevant', True)
return x
def validate(self, target):
t = tempfile.TemporaryFile()
t.write(target)
t.seek(0)
try:
targetTree = self.p.run(file=t).toxmldoc()
t.close()
return isEquivalentTree(self.exemplarTree.childNodes[0], targetTree.childNodes[0])
except bison.ParserSyntaxError:
print "Error: target didn't parse."
return False