<commit_before>"""
sqlobject.sqlbuilder
  17 Oct 2002, <NAME> <<EMAIL>>
Builds SQL expressions from normal Python expressions.  Python
2.1 or higher IS REQUIRED.

Disclaimer
----------

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 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 Lesser 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.

Instructions
------------

To begin a SQL expression, you must use some sort of SQL object -- a
field, table, or SQL statement (``SELECT``, ``INSERT``, etc.)  You can
then use normal operators, with the exception of: `and`, `or`, `not`,
and `in`.  You can use the `AND`, `OR`, `NOT`, and `IN` functions
instead, or you can also use `&`, `|`, and `~` for `and`, `or`, and
`not` respectively (however -- the precidence for these operators
doesn't work as you would want, so you must use many parenthesis).

To create a sql field, table, or constant/function, use the namespaces
`table`, `const`, and `func`.  For instance, ``table.address`` refers
to the ``address`` table, and ``table.address.state`` refers to the
``state`` field in the address table.  ``const.NULL`` is the ``NULL``
SQL constant, and ``func.NOW()`` is the ``NOW()`` function call
(`const` and `func` are actually identicle, but the two names are
provided for clarity).  Once you create this object, expressions
formed with it will produce SQL statements.

The ``sqlrepr(obj)`` function gets the SQL representation of these
objects, as well as the proper SQL representation of basic Python
types (None==NULL).

There are a number of DB-specific SQL features that this does not
implement.  There are a bunch of normal ANSI features also not present
-- particularly left joins, among others.  You may wish to only use
this to generate ``WHERE`` clauses.

See the bottom of this module for some examples, and run it (i.e.
``python sql.py``) to see the results of those examples.

"""

########################################
## Constants
########################################

class VersionError(Exception):
    pass
class NoDefault:
    pass

True, False = (1==1), (0==1)

import re, fnmatch
import operator
from converters import sqlrepr, registerConverter, TRUE, FALSE

safeSQLRE = re.compile(r'^[a-zA-Z][a-zA-Z0-9_\.]*$')
def sqlIdentifier(obj):
    return type(obj) is type("") and not not safeSQLRE.search(obj.strip())


def execute(expr, executor):
    if hasattr(expr, 'execute'):
        return expr.execute(executor)
    else:
        return expr

########################################
## Expression generation
########################################

class SQLExpression:
    def __add__(self, other):
        return SQLOp("+", self, other)
    def __radd__(self, other):
        return SQLOp("+", other, self)
    def __sub__(self, other):
        return SQLOp("-", self, other)
    def __rsub__(self, other):
        return SQLOp("-", other, self)
    def __mul__(self, other):
        return SQLOp("*", self, other)
    def __rmul__(self, other):
        return SQLOp("*", other, self)
    def __div__(self, other):
        return SQLOp("/", self, other)
    def __rdiv__(self, other):
        return SQLOp("/", other, self)
    def __pos__(self):
        return SQLPrefix("+", self)
    def __neg__(self):
        return SQLPrefix("-", self)
    def __pow__(self, other):
        return SQLConstant("POW")(self, other)
    def __rpow__(self, other):
        return SQLConstant("POW")(other, self)
    def __abs__(self):
        return SQLConstant("ABS")(self)
    def __mod__(self, other):
        return SQLConstant("MOD")(self, other)
    def __rmod__(self, other):
        return SQLConstant("MOD")(other, self)

    def __lt__(self, other):
        return SQLOp("<", self, other)
    def __le__(self, other):
        return SQLOp("<=", self, other)
    def __gt__(self, other):
        return SQLOp(">", self, other)
    def __ge__(self, other):
        return SQLOp(">=", self, other)
    def __eq__(self, other):
        if other is None:
            return ISNULL(self)
        else:
            return SQLOp("=", self, other)
    def __ne__(self, other):
        if other is None:
            return ISNOTNULL(self)
        else:
            return SQLOp("<>", self, other)

    def __and__(self, other):
        return SQLOp("AND", self, other)
    def __rand__(self, other):
        return SQLOp("AND", other, self)
    def __or__(self, other):
        return SQLOp("OR", self, other)
    def __ror__(self, other):
        return SQLOp("OR", other, self)
    def __invert__(self):
        return SQLPrefix("NOT", self)

    def __call__(self, *args):
        return SQLCall(self, args)

    def __repr__(self):
        try:
            return self.__sqlrepr__(None)
        except AssertionError:
            return '<%s %s>' % (
                self.__class__.__name__, hex(id(self))[2:])
        
    def __str__(self):
        return repr(self)

    def __cmp__(self, other):
        raise VersionError, "Python 2.1+ required"
    def __rcmp__(self, other):
        raise VersionError, "Python 2.1+ required"

    def startswith(self, s):
        return STARTSWITH(self, s)
    def endswith(self, s):
        return ENDSWITH(self, s)
    def contains(self, s):
        return CONTAINSSTRING(self, s)

    def components(self):
        return []

    def tablesUsed(self):
        return self.tablesUsedDict().keys()
    def tablesUsedDict(self):
        tables = {}
        for table in self.tablesUsedImmediate():
            tables[table] = 1
        for component in self.components():
            tables.update(tablesUsedDict(component))
        return tables
    def tablesUsedImmediate(self):
        return []

#######################################
# Converter for SQLExpression instances
#######################################

def SQLExprConverter(value, db):
    return value.__sqlrepr__()

registerConverter(SQLExpression, SQLExprConverter)

def tablesUsedDict(obj):
    if hasattr(obj, "tablesUsedDict"):
        return obj.tablesUsedDict()
    else:
        return {}

operatorMap = {
    "+": operator.add,
    "/": operator.div,
    "-": operator.sub,
    "*": operator.mul,
    "<": operator.lt,
    "<=": operator.le,
    "=": operator.eq,
    "!=": operator.ne,
    ">=": operator.ge,
    ">": operator.gt,
    "IN": operator.contains,
    "IS": operator.eq,
    }

class SQLOp(SQLExpression):
    def __init__(self, op, expr1, expr2):
        self.op = op.upper()
        self.expr1 = expr1
        self.expr2 = expr2
    def __sqlrepr__(self, db):
        return "(%s %s %s)" % (sqlrepr(self.expr1, db), self.op, sqlrepr(self.expr2, db))
    def components(self):
        return [self.expr1, self.expr2]
    def execute(self, executor):
        if self.op == "AND":
            return execute(self.expr1, executor) \
                   and execute(self.expr2, executor)
        elif self.op == "OR":
            return execute(self.expr1, executor) \
                   or execute(self.expr2, executor)
        elif self.op == "LIKE":
            if not hasattr(self, '_regex'):
                # @@: Crude, not entirely accurate
                dest = self.expr2
                dest = dest.replace("%%", "\001")
                dest = dest.replace("*", "\002")
                dest = dest.replace("%", "*")
                dest = dest.replace("\001", "%")
                dest = dest.replace("\002", "[*]")
                self._regex = re.compile(fnmatch.translate(dest), re.I)
            return self._regex.search(execute(self.expr1, executor))
        else:
            return operatorMap[self.op.upper()](execute(self.expr1, executor),
                                                execute(self.expr2, executor))

registerConverter(SQLOp, SQLExprConverter)

class SQLCall(SQLExpression):
    def __init__(self, expr, args):
        self.expr = expr
        self.args = args
    def __sqlrepr__(self, db):
        return "%s%s" % (sqlrepr(self.expr, db), sqlrepr(self.args, db))
    def components(self):
        return [self.expr] + list(self.args)
    def execute(self, executor):
        raise ValueError, "I don't yet know how to locally execute functions"

registerConverter(SQLCall, SQLExprConverter)

class SQLPrefix(SQLExpression):
    def __init__(self, prefix, expr):
        self.prefix = prefix
        self.expr = expr
    def __sqlrepr__(self, db):
        return "%s %s" % (self.prefix, sqlrepr(self.expr, db))
    def components(self):
        return [self.expr]
    def execute(self, executor):
        expr = execute(self.expr, executor)
        if prefix == "+":
            return expr
        elif prefix == "-":
            return -expr
        elif prefix.upper() == "NOT":
            return not expr

registerConverter(SQLPrefix, SQLExprConverter)

class SQLConstant(SQLExpression):
    def __init__(self, const):
        self.const = const
    def __sqlrepr__(self, db):
        return self.const
    def execute(self, executor):
        raise ValueError, "I don't yet know how to execute SQL constants"

registerConverter(SQLConstant, SQLExprConverter)

class SQLTrueClauseClass(SQLExpression):
    def __sqlrepr__(self, db):
        return "1 = 1"
    def execute(self, executor):
        return 1

SQLTrueClause = SQLTrueClauseClass()

registerConverter(SQLTrueClauseClass, SQLExprConverter)

########################################
## Namespaces
########################################

class TableSpace:
    def __getattr__(self, attr):
        if attr.startswith('__'):
            raise AttributeError
        return Table(attr)

class Table(SQLExpression):
    def __init__(self, tableName):
        self.tableName = tableName
    def __getattr__(self, attr):
        if attr.startswith('__'):
            raise AttributeError
        return Field(self.tableName, attr)
    def __sqlrepr__(self, db):
        return str(self.tableName)
    def execute(self, executor):
        raise ValueError, "Tables don't have values"

class SQLObjectTable(Table):

    def __init__(self, soClass):
        self.soClass = soClass
        Table.__init__(self, soClass._table)

    def __getattr__(self, attr):
        if attr.startswith('__'):
            raise AttributeError
        if attr == 'id':
            return SQLObjectField(self.tableName, self.soClass._idName, attr)
        else:
            return SQLObjectField(self.tableName,
                                  self.soClass._SO_columnDict[attr].dbName,
                                  attr)
<commit_msg>Avoid tables with empty names<commit_after>"""
sqlobject.sqlbuilder
  17 Oct 2002, <NAME> <<EMAIL>>
Builds SQL expressions from normal Python expressions.  Python
2.1 or higher IS REQUIRED.

Disclaimer
----------

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 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 Lesser 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.

Instructions
------------

To begin a SQL expression, you must use some sort of SQL object -- a
field, table, or SQL statement (``SELECT``, ``INSERT``, etc.)  You can
then use normal operators, with the exception of: `and`, `or`, `not`,
and `in`.  You can use the `AND`, `OR`, `NOT`, and `IN` functions
instead, or you can also use `&`, `|`, and `~` for `and`, `or`, and
`not` respectively (however -- the precidence for these operators
doesn't work as you would want, so you must use many parenthesis).

To create a sql field, table, or constant/function, use the namespaces
`table`, `const`, and `func`.  For instance, ``table.address`` refers
to the ``address`` table, and ``table.address.state`` refers to the
``state`` field in the address table.  ``const.NULL`` is the ``NULL``
SQL constant, and ``func.NOW()`` is the ``NOW()`` function call
(`const` and `func` are actually identicle, but the two names are
provided for clarity).  Once you create this object, expressions
formed with it will produce SQL statements.

The ``sqlrepr(obj)`` function gets the SQL representation of these
objects, as well as the proper SQL representation of basic Python
types (None==NULL).

There are a number of DB-specific SQL features that this does not
implement.  There are a bunch of normal ANSI features also not present
-- particularly left joins, among others.  You may wish to only use
this to generate ``WHERE`` clauses.

See the bottom of this module for some examples, and run it (i.e.
``python sql.py``) to see the results of those examples.

"""

########################################
## Constants
########################################

class VersionError(Exception):
    pass
class NoDefault:
    pass

True, False = (1==1), (0==1)

import re, fnmatch
import operator
from converters import sqlrepr, registerConverter, TRUE, FALSE

safeSQLRE = re.compile(r'^[a-zA-Z][a-zA-Z0-9_\.]*$')
def sqlIdentifier(obj):
    return type(obj) is type("") and not not safeSQLRE.search(obj.strip())


def execute(expr, executor):
    if hasattr(expr, 'execute'):
        return expr.execute(executor)
    else:
        return expr

########################################
## Expression generation
########################################

class SQLExpression:
    def __add__(self, other):
        return SQLOp("+", self, other)
    def __radd__(self, other):
        return SQLOp("+", other, self)
    def __sub__(self, other):
        return SQLOp("-", self, other)
    def __rsub__(self, other):
        return SQLOp("-", other, self)
    def __mul__(self, other):
        return SQLOp("*", self, other)
    def __rmul__(self, other):
        return SQLOp("*", other, self)
    def __div__(self, other):
        return SQLOp("/", self, other)
    def __rdiv__(self, other):
        return SQLOp("/", other, self)
    def __pos__(self):
        return SQLPrefix("+", self)
    def __neg__(self):
        return SQLPrefix("-", self)
    def __pow__(self, other):
        return SQLConstant("POW")(self, other)
    def __rpow__(self, other):
        return SQLConstant("POW")(other, self)
    def __abs__(self):
        return SQLConstant("ABS")(self)
    def __mod__(self, other):
        return SQLConstant("MOD")(self, other)
    def __rmod__(self, other):
        return SQLConstant("MOD")(other, self)

    def __lt__(self, other):
        return SQLOp("<", self, other)
    def __le__(self, other):
        return SQLOp("<=", self, other)
    def __gt__(self, other):
        return SQLOp(">", self, other)
    def __ge__(self, other):
        return SQLOp(">=", self, other)
    def __eq__(self, other):
        if other is None:
            return ISNULL(self)
        else:
            return SQLOp("=", self, other)
    def __ne__(self, other):
        if other is None:
            return ISNOTNULL(self)
        else:
            return SQLOp("<>", self, other)

    def __and__(self, other):
        return SQLOp("AND", self, other)
    def __rand__(self, other):
        return SQLOp("AND", other, self)
    def __or__(self, other):
        return SQLOp("OR", self, other)
    def __ror__(self, other):
        return SQLOp("OR", other, self)
    def __invert__(self):
        return SQLPrefix("NOT", self)

    def __call__(self, *args):
        return SQLCall(self, args)

    def __repr__(self):
        try:
            return self.__sqlrepr__(None)
        except AssertionError:
            return '<%s %s>' % (
                self.__class__.__name__, hex(id(self))[2:])
        
    def __str__(self):
        return repr(self)

    def __cmp__(self, other):
        raise VersionError, "Python 2.1+ required"
    def __rcmp__(self, other):
        raise VersionError, "Python 2.1+ required"

    def startswith(self, s):
        return STARTSWITH(self, s)
    def endswith(self, s):
        return ENDSWITH(self, s)
    def contains(self, s):
        return CONTAINSSTRING(self, s)

    def components(self):
        return []

    def tablesUsed(self):
        return self.tablesUsedDict().keys()
    def tablesUsedDict(self):
        tables = {}
        for table in self.tablesUsedImmediate():
            tables[table] = 1
        for component in self.components():
            tables.update(tablesUsedDict(component))
        return tables
    def tablesUsedImmediate(self):
        return []

#######################################
# Converter for SQLExpression instances
#######################################

def SQLExprConverter(value, db):
    return value.__sqlrepr__()

registerConverter(SQLExpression, SQLExprConverter)

def tablesUsedDict(obj):
    if hasattr(obj, "tablesUsedDict"):
        return obj.tablesUsedDict()
    else:
        return {}

operatorMap = {
    "+": operator.add,
    "/": operator.div,
    "-": operator.sub,
    "*": operator.mul,
    "<": operator.lt,
    "<=": operator.le,
    "=": operator.eq,
    "!=": operator.ne,
    ">=": operator.ge,
    ">": operator.gt,
    "IN": operator.contains,
    "IS": operator.eq,
    }

class SQLOp(SQLExpression):
    def __init__(self, op, expr1, expr2):
        self.op = op.upper()
        self.expr1 = expr1
        self.expr2 = expr2
    def __sqlrepr__(self, db):
        return "(%s %s %s)" % (sqlrepr(self.expr1, db), self.op, sqlrepr(self.expr2, db))
    def components(self):
        return [self.expr1, self.expr2]
    def execute(self, executor):
        if self.op == "AND":
            return execute(self.expr1, executor) \
                   and execute(self.expr2, executor)
        elif self.op == "OR":
            return execute(self.expr1, executor) \
                   or execute(self.expr2, executor)
        elif self.op == "LIKE":
            if not hasattr(self, '_regex'):
                # @@: Crude, not entirely accurate
                dest = self.expr2
                dest = dest.replace("%%", "\001")
                dest = dest.replace("*", "\002")
                dest = dest.replace("%", "*")
                dest = dest.replace("\001", "%")
                dest = dest.replace("\002", "[*]")
                self._regex = re.compile(fnmatch.translate(dest), re.I)
            return self._regex.search(execute(self.expr1, executor))
        else:
            return operatorMap[self.op.upper()](execute(self.expr1, executor),
                                                execute(self.expr2, executor))

registerConverter(SQLOp, SQLExprConverter)

class SQLCall(SQLExpression):
    def __init__(self, expr, args):
        self.expr = expr
        self.args = args
    def __sqlrepr__(self, db):
        return "%s%s" % (sqlrepr(self.expr, db), sqlrepr(self.args, db))
    def components(self):
        return [self.expr] + list(self.args)
    def execute(self, executor):
        raise ValueError, "I don't yet know how to locally execute functions"

registerConverter(SQLCall, SQLExprConverter)

class SQLPrefix(SQLExpression):
    def __init__(self, prefix, expr):
        self.prefix = prefix
        self.expr = expr
    def __sqlrepr__(self, db):
        return "%s %s" % (self.prefix, sqlrepr(self.expr, db))
    def components(self):
        return [self.expr]
    def execute(self, executor):
        expr = execute(self.expr, executor)
        if prefix == "+":
            return expr
        elif prefix == "-":
            return -expr
        elif prefix.upper() == "NOT":
            return not expr

registerConverter(SQLPrefix, SQLExprConverter)

class SQLConstant(SQLExpression):
    def __init__(self, const):
        self.const = const
    def __sqlrepr__(self, db):
        return self.const
    def execute(self, executor):
        raise ValueError, "I don't yet know how to execute SQL constants"

registerConverter(SQLConstant, SQLExprConverter)

class SQLTrueClauseClass(SQLExpression):
    def __sqlrepr__(self, db):
        return "1 = 1"
    def execute(self, executor):
        return 1

SQLTrueClause = SQLTrueClauseClass()

registerConverter(SQLTrueClauseClass, SQLExprConverter)

########################################
## Namespaces
########################################

class TableSpace:
    def __getattr__(self, attr):
        if attr.startswith('__'):
            raise AttributeError
        return Table(attr)

class Table(SQLExpression):
    def __init__(self, tableName):
        self.tableName = tableName
    def __getattr__(self, attr):
        if attr.startswith('__'):
            raise AttributeError
        return Field(self.tableName, attr)
    def __sqlrepr__(self, db):
        return str(self.tableName)
    def execute(self, executor):
        raise ValueError, "Tables don't have values"

class SQLObjectTable(Table):

    def __init__(self, soClass):
        self.soClass = soClass
        assert soClass._table, (
            "Bad table name in class %r: %r"
            % (soClass, soClass._table))
        Table.__init__(self, soClass._table)

    def __getattr__(self, attr):
        if attr.startswith('__'):
            raise AttributeError
        if attr == 'id':
            return SQLObjectField(self.tableName, self.soClass._idName, attr)
        else:
            return SQLObjectField(self.tableName,
                                  self.soClass._SO_columnDict[attr].dbName,
                                  attr)

{'fraction_non_alphanumeric': 0.14514745066160864, 'fraction_numerical': 0.006232217856658989, 'mean_word_length': 2.7532203389830507, 'pattern_counts': {'":': 36, '<': 21, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2608005', 'n_tokens_mistral': 6495, 'n_tokens_neox': 6274, 'n_words': 2043}