Author: jure
Date: Tue Dec 11 10:28:05 2012
New Revision: 1420075
URL: http://svn.apache.org/viewvc?rev=1420075&view=rev
Log:
initial SQL proxy patch as described in ticket #288
Added:
incubator/bloodhound/branches/bep_0003_multiproduct/trac/trac/bloodhound.py
incubator/bloodhound/branches/bep_0003_multiproduct/trac/trac/bloodhoundsql.py
Modified:
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/api.py
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/model.py
incubator/bloodhound/branches/bep_0003_multiproduct/trac/trac/web/standalone.py
Modified:
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/api.py
URL:
http://svn.apache.org/viewvc/incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/api.py?rev=1420075&r1=1420074&r2=1420075&view=diff
==============================================================================
---
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/api.py
(original)
+++
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/api.py
Tue Dec 11 10:28:05 2012
@@ -23,7 +23,7 @@ from genshi.builder import tag
from pkg_resources import resource_filename
from trac.core import Component, TracError, implements
-from trac.db import Table, Column, DatabaseManager
+from trac.db import Table, Column, DatabaseManager, Index
from trac.env import IEnvironmentSetupParticipant
from trac.perm import IPermissionRequestor
from trac.resource import IResourceManager
@@ -33,7 +33,7 @@ from trac.web.chrome import ITemplatePro
from multiproduct.model import Product
-DB_VERSION = 2
+DB_VERSION = 3
DB_SYSTEM_KEY = 'bloodhound_multi_product_version'
PLUGIN_NAME = 'Bloodhound multi product'
@@ -114,7 +114,89 @@ class MultiProductSystem(Component):
WHERE name=%s""", (DB_VERSION, DB_SYSTEM_KEY))
self.log.info("Upgraded multiproduct db schema from version %d"
" to %d" % (db_installed_version, DB_VERSION))
-
+
+ if db_installed_version == 2:
+ from trac import bloodhound
+ migrate_tables = ['enum', 'component', 'milestone', 'version',
'wiki']
+ table_defs = [
+ Table('enum', key=('type', 'name', 'product'))[
+ Column('type'),
+ Column('name'),
+ Column('value'),
+ Column('product')],
+ Table('component', key=('name', 'product'))[
+ Column('name'),
+ Column('owner'),
+ Column('description'),
+ Column('product')],
+ Table('milestone', key=('name', 'product'))[
+ Column('name'),
+ Column('due', type='int64'),
+ Column('completed', type='int64'),
+ Column('description'),
+ Column('product')],
+ Table('version', key=('name', 'product'))[
+ Column('name'),
+ Column('time', type='int64'),
+ Column('description'),
+ Column('product')],
+ Table('wiki', key=('name', 'version', 'product'))[
+ Column('name'),
+ Column('version', type='int'),
+ Column('time', type='int64'),
+ Column('author'),
+ Column('ipnr'),
+ Column('text'),
+ Column('comment'),
+ Column('readonly', type='int'),
+ Column('product'),
+ Index(['time'])],
+ ]
+ table_columns = dict()
+ table_vals = {}
+ for table in table_defs:
+ table_columns[table.name] = filter(lambda column: column
!= 'product', [column.name for column in list(filter(lambda t: t.name ==
table.name, table_defs)[0].columns)])
+ table_columns['bloodhound_product'] = ['prefix', 'name',
'description', 'owner']
+ def fetch_table(table):
+ table_vals[table] = list(db("SELECT %s FROM %s" %
(','.join(table_columns[table]), table)))
+ for table in table_columns.keys():
+ self.log.info("Fetching table '%s'", table)
+ fetch_table(table)
+ for table in migrate_tables:
+ self.log.info("Dropping obsolete table '%s'", table)
+ db("DROP TABLE %s" % table)
+ db_connector, _ = DatabaseManager(self.env).get_connector()
+ for table in table_defs:
+ self.log.info("Creating table '%s'", table.name)
+ for sql in db_connector.to_sql(table):
+ db(sql)
+ self.log.info("Creating default product")
+ db("INSERT INTO bloodhound_product (prefix, name, description,
owner) VALUES ('%s', 'Default', 'Default product', '')" %
bloodhound.DEFAULT_PRODUCT)
+ self.log.info("Migrating tickets w/o product to default
product")
+ db("UPDATE ticket SET product='%s' WHERE product=''" %
bloodhound.DEFAULT_PRODUCT)
+
+ def insert_with_product(table, product):
+ cols = table_columns[table] + ['product']
+ sql = "INSERT INTO %s (%s) VALUES (%s)" % (table,
+ ','.join(cols),
+ ','.join(['%s']
* len(cols)))
+ for r in table_vals[table]:
+ vals = list()
+ for v in list(r):
+ vals.append(v if v else '')
+ db(sql, tuple(vals + [product]))
+ for p in table_vals['bloodhound_product']:
+ for table in migrate_tables:
+ self.log.info("Creating tables '%s' for default
product", table)
+ insert_with_product(table, bloodhound.DEFAULT_PRODUCT)
+ self.log.info("Creating tables '%s' for product '%s'
('%s')", table, p[1], p[0])
+ insert_with_product(table, p[0])
+
+ db("""UPDATE system SET value=%s
+ WHERE name=%s""", (DB_VERSION, DB_SYSTEM_KEY))
+ self.log.info("Upgraded multiproduct db schema from version %d"
+ " to %d" % (db_installed_version, DB_VERSION))
+
# ITemplateProvider methods
def get_templates_dirs(self):
"""provide the plugin templates"""
Modified:
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/model.py
URL:
http://svn.apache.org/viewvc/incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/model.py?rev=1420075&r1=1420074&r2=1420075&view=diff
==============================================================================
---
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/model.py
(original)
+++
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/model.py
Tue Dec 11 10:28:05 2012
@@ -283,6 +283,20 @@ class Product(ModelBase):
q = Query.from_string(env, 'product=%s' % product)
return q.execute()
+ def insert(self):
+ from trac import db_default
+ from trac.bloodhound import TRANSLATE_TABLES
+ with self._env.db_transaction as db:
+ super(Product, self).insert()
+ for table, cols, vals in db_default.get_data(db):
+ if not table in TRANSLATE_TABLES:
+ continue
+ self._env.product_aware = False
+ self._env.product_scope = self.prefix
+ db.executemany("INSERT INTO %s (%s) VALUES (%s)" % (table,
+
','.join(cols),
+
','.join(['%s'] * len(cols))), vals)
+
class ProductResourceMap(ModelBase):
"""Table representing the mapping of resources to their product"""
_meta = {'table_name':'bloodhound_productresourcemap',
Added:
incubator/bloodhound/branches/bep_0003_multiproduct/trac/trac/bloodhound.py
URL:
http://svn.apache.org/viewvc/incubator/bloodhound/branches/bep_0003_multiproduct/trac/trac/bloodhound.py?rev=1420075&view=auto
==============================================================================
--- incubator/bloodhound/branches/bep_0003_multiproduct/trac/trac/bloodhound.py
(added)
+++ incubator/bloodhound/branches/bep_0003_multiproduct/trac/trac/bloodhound.py
Tue Dec 11 10:28:05 2012
@@ -0,0 +1,95 @@
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import trac.env
+from trac.db.util import IterableCursor
+from trac.util import concurrency
+from trac.env import Environment
+from bloodhoundsql import BloodhoundProductSQLTranslate
+
+DEFAULT_PRODUCT = 'default'
+TRANSLATE_TABLES = ['ticket', 'enum', 'component', 'milestone', 'version',
'wiki']
+PRODUCT_COLUMN = 'product'
+
+class BloodhoundIterableCursor(IterableCursor):
+ __slots__ = IterableCursor.__slots__ + ['_translator']
+ _tls = concurrency.ThreadLocal(env=None)
+
+ def __init__(self, cursor, log=None):
+ super(BloodhoundIterableCursor, self).__init__(cursor, log=log)
+ self._translator = None
+
+ @property
+ def translator(self):
+ if not self._translator:
+ product = self.env.product_scope if self.env else DEFAULT_PRODUCT
+ self._translator = BloodhoundProductSQLTranslate(TRANSLATE_TABLES,
+ PRODUCT_COLUMN,
+ product)
+ return self._translator
+
+ def _translate_sql(self, sql):
+ return self.translator.translate(sql) if (self.env and not
self.env.product_aware) else sql
+
+ def execute(self, sql, args=None):
+ return super(BloodhoundIterableCursor,
self).execute(self._translate_sql(sql), args=args)
+
+ def executemany(self, sql, args=None):
+ return super(BloodhoundIterableCursor,
self).executemany(self._translate_sql(sql), args=args)
+
+ @property
+ def env(self):
+ return self._tls.env
+
+ @classmethod
+ def set_env(cls, env):
+ cls._tls.env = env
+
+class BloodhoundEnvironment(Environment):
+ def __init__(self, path, create=False, options=[]):
+ super(BloodhoundEnvironment, self).__init__(path, create=create,
options=options)
+ self._product_scope = DEFAULT_PRODUCT
+ self._product_aware = False
+
+ @property
+ def product_scope(self):
+ return self._product_scope
+ @product_scope.setter
+ def product_scope(self, value):
+ self._product_scope = value
+
+ @property
+ def product_aware(self):
+ return self._product_aware
+ @product_aware.setter
+ def product_aware(self, value):
+ self._product_aware = value
+
+ @property
+ def db_query(self):
+ BloodhoundIterableCursor.set_env(self)
+ return super(BloodhoundEnvironment, self).db_query
+
+ @property
+ def db_transaction(self):
+ BloodhoundIterableCursor.set_env(self)
+ return super(BloodhoundEnvironment, self).db_transaction
+
+def bloodhound_hooks():
+ trac.env.Environment = BloodhoundEnvironment
+ trac.db.util.IterableCursor = BloodhoundIterableCursor
Added:
incubator/bloodhound/branches/bep_0003_multiproduct/trac/trac/bloodhoundsql.py
URL:
http://svn.apache.org/viewvc/incubator/bloodhound/branches/bep_0003_multiproduct/trac/trac/bloodhoundsql.py?rev=1420075&view=auto
==============================================================================
---
incubator/bloodhound/branches/bep_0003_multiproduct/trac/trac/bloodhoundsql.py
(added)
+++
incubator/bloodhound/branches/bep_0003_multiproduct/trac/trac/bloodhoundsql.py
Tue Dec 11 10:28:05 2012
@@ -0,0 +1,397 @@
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import sqlparse
+import sqlparse.tokens as Tokens
+import sqlparse.sql as Types
+
+__all__ = ['BloodhoundProductSQLTranslate']
+
+class BloodhoundProductSQLTranslate(object):
+ _join_statements = ['LEFT JOIN', 'LEFT OUTER JOIN',
+ 'RIGHT JOIN', 'RIGHT OUTER JOIN',
+ 'JOIN', 'INNER JOIN']
+ _from_end_words = ['WHERE', 'GROUP', 'HAVING', 'ORDER', 'UNION']
+
+ def __init__(self, translate_tables, product_column, product_prefix):
+ self._translate_tables = translate_tables
+ self._product_column = product_column
+ self._product_prefix = product_prefix
+
+ def _select_table_name_alias(self, tokens):
+ return filter(lambda t: t.upper() != 'AS', [t.value for t in tokens if
t.value.strip()])
+ def _column_expression_name_alias(self, tokens):
+ return filter(lambda t: t.upper() != 'AS', [t.value for t in tokens if
t.value.strip()])
+
+ def _patch_table_view_sql(self, name, alias=None):
+ sql = '(SELECT * FROM %s WHERE %s="%s")' % (name,
self._product_column, self._product_prefix)
+ if alias:
+ sql += ' AS %s' % alias
+ return sql
+
+ def _token_first(self, parent):
+ return parent.token_first()
+ def _token_next_match(self, parent, start_token, ttype, token):
+ return parent.token_next_match(self._token_idx(parent, start_token),
ttype, token)
+ def _token_next(self, parent, from_token):
+ return parent.token_next(self._token_idx(parent, from_token))
+ def _token_prev(self, parent, from_token):
+ return parent.token_prev(self._token_idx(parent, from_token))
+ def _token_next_by_instance(self, parent, start_token, klass):
+ return parent.token_next_by_instance(self._token_idx(parent,
start_token), klass)
+ def _token_next_by_type(self, parent, start_token, ttype):
+ return parent.token_next_by_type(self._token_idx(parent, start_token),
ttype)
+ def _token_insert_before(self, parent, where, token):
+ return parent.insert_before(where, token)
+ def _token_insert_after(self, parent, where, token):
+ return parent.insert_after(where, token)
+ def _token_idx(self, parent, token):
+ return parent.token_index(token)
+
+ def _eval_expression_value(self, parent, token):
+ if isinstance(token, Types.Parenthesis):
+ t = self._token_first(token)
+ if t.match(Tokens.Punctuation, '('):
+ t = self._token_next(token, t)
+ if t.match(Tokens.DML, 'SELECT'):
+ self._select(token, t)
+
+ def _expression_token_unwind_hack(self, parent, token, start_token):
+ # hack to workaround sqlparse bug that wrongly presents list of tokens
+ # as IdentifierList in certain situations
+ if isinstance(token, Types.IdentifierList):
+ expression_token_idx = self._token_idx(parent, token)
+ del parent.tokens[expression_token_idx]
+ last_token = start_token
+ for t in token.tokens:
+ self._token_insert_after(parent, last_token, t)
+ last_token = t
+ token = self._token_next(parent, start_token)
+ return token
+
+ def _where(self, parent, where_token):
+ if isinstance(where_token, Types.Where):
+ token = self._token_first(where_token)
+ if not token.match(Tokens.Keyword, 'WHERE'):
+ raise Exception("Invalid WHERE statement")
+ while token:
+ self._eval_expression_value(where_token, token)
+ token = self._token_next(where_token, token)
+ return
+
+ def _select_expression_tokens(self, parent, first_token, end_words):
+ if isinstance(first_token, Types.IdentifierList):
+ return first_token, [first_token]
+ tokens = list()
+ current_list = list()
+ current_token = first_token
+ while current_token and not current_token.match(Tokens.Keyword,
end_words):
+ if current_token.match(Tokens.Punctuation, ','):
+ if current_list:
+ tokens.append(current_list)
+ current_list = list()
+ elif current_token.is_whitespace():
+ pass
+ else:
+ current_list.append(current_token)
+ current_token = self._token_next(parent, current_token)
+ if current_list:
+ tokens.append(current_list)
+ return current_token, tokens
+
+ def _select_join(self, parent, start_token, end_words):
+ current_token = self._select_from(parent, start_token, ['ON'])
+ tokens = list()
+ if current_token:
+ current_token = self._token_next(parent, current_token)
+ while current_token and\
+ not current_token.match(Tokens.Keyword, end_words) and\
+ not isinstance(current_token, Types.Where):
+ tokens.append(current_token)
+ current_token = self._token_next(parent, current_token)
+ return current_token
+
+ def _select_from(self, parent, start_token, end_words,
table_name_callback=None):
+ def inject_table_view(token, name, alias):
+ parent.tokens[self._token_idx(parent, token)] =
sqlparse.parse(self._patch_table_view_sql(name,
+
alias=alias))[0]
+
+ def process_table_name_tokens(token, nametokens):
+ if nametokens:
+ l = self._select_table_name_alias(nametokens)
+ if not l:
+ raise Exception("Invalid FROM table name")
+ name, alias = l[0], None
+ if len(l) > 1:
+ alias = l[1]
+ if name in self._translate_tables:
+ inject_table_view(token, name, alias)
+ if table_name_callback:
+ table_name_callback(tablename)
+ return list()
+
+ current_token = self._token_next(parent, start_token)
+ last_token = current_token
+ table_name_tokens = list()
+ join_tokens = list()
+ while current_token and \
+ not current_token.match(Tokens.Keyword, end_words) and \
+ not isinstance(current_token, Types.Where):
+ last_token = current_token
+ next_token = self._token_next(parent, current_token)
+ if current_token.is_whitespace():
+ pass
+ elif isinstance(current_token, Types.Identifier):
+ parenthesis = filter(lambda t: isinstance(t,
Types.Parenthesis), current_token.tokens)
+ if parenthesis:
+ for p in parenthesis:
+ t = self._token_next(p, p.token_first())
+ if not t.match(Tokens.DML, 'SELECT'):
+ raise Exception("Invalid subselect statement")
+ self._select(p, t)
+ else:
+ tablename = current_token.value.strip()
+ tablealias = current_token.get_name().strip()
+ if tablename in self._translate_tables:
+ inject_table_view(current_token, tablename, tablealias)
+ if table_name_callback:
+ table_name_callback(tablename)
+ elif current_token.ttype == Tokens.Punctuation:
+ if table_name_tokens:
+ next_token = self._token_next(parent, current_token)
+ table_name_tokens =
process_table_name_tokens(current_token,
+
table_name_tokens)
+ elif current_token.match(Tokens.Keyword, ['JOIN', 'LEFT', 'RIGHT',
'INNER', 'OUTER'] + self._join_statements):
+ join_tokens.append(current_token.value.strip().upper())
+ join = ' '.join(join_tokens)
+ if join in self._join_statements:
+ join_tokens = list()
+ next_token = self._select_join(parent,
+ current_token,
+ ['JOIN', 'LEFT', 'RIGHT',
'INNER', 'OUTER']
+ + self._join_statements
+ + self._from_end_words)
+ elif current_token.ttype == Tokens.Keyword or \
+ current_token.ttype == Tokens.Token.Literal.Number.Integer:
+ table_name_tokens.append(current_token)
+ else:
+ raise Exception("Failed to parse FROM table name")
+ current_token = next_token
+
+ if last_token and table_name_tokens:
+ process_table_name_tokens(last_token,
+ table_name_tokens)
+ return current_token
+
+ def _select(self, parent, start_token, insert_table=None):
+ token = self._token_next(parent, start_token)
+ fields_token = self._token_next(parent, token) if
token.match(Tokens.Keyword, ['ALL', 'DISTINCT']) else token
+ current_token, field_lists = self._select_expression_tokens(parent,
fields_token, ['FROM'] + self._from_end_words)
+ def handle_insert_table(table_name):
+ if table_name == insert_table:
+ for keyword in [self._product_column, ',', ' ']:
+ self._token_insert_before(parent, fields_token,
Types.Token(Tokens.Keyword, keyword))
+ return
+ table_name_callback = handle_insert_table if insert_table else None
+ from_token = self._token_next_match(parent, start_token,
Tokens.Keyword, 'FROM')
+ if not from_token:
+ raise Exception("Expected FROM in SELECT")
+ current_token = self._select_from(parent,
+ from_token, self._from_end_words,
+
table_name_callback=table_name_callback)
+ if not current_token:
+ return None
+ while current_token:
+ if isinstance(current_token, Types.Where) or \
+ current_token.match(Tokens.Keyword, ['GROUP', 'HAVING',
'ORDER']):
+ if isinstance(current_token, Types.Where):
+ self._where(parent, current_token)
+ start_token = self._token_next(parent, current_token)
+ next_token = self._token_next_match(parent,
+ start_token,
+ Tokens.Keyword,
+ self._from_end_words) if
start_token else None
+ elif current_token.match(Tokens.Keyword, ['UNION']):
+ token = self._token_next(parent, current_token)
+ if not token.match(Tokens.DML, 'SELECT'):
+ raise Exception("Invalid SELECT UNION statement")
+ token = self._select(parent, current_token,
insert_table=insert_table)
+ next_token = self._token_next(parent, token) if token else None
+ else:
+ raise Exception("Unsupported SQL statement")
+ current_token = next_token
+ return current_token
+
+ def _insert(self, parent, start_token):
+ token = self._token_next(parent, start_token)
+ if not token.match(Tokens.Keyword, 'INTO'):
+ raise Exception("Invalid INSERT statement")
+ def insert_extra_column(tablename, columns_token):
+ if tablename in self._translate_tables and\
+ isinstance(columns_token, Types.Parenthesis):
+ ptoken = self._token_first(columns_token)
+ if not ptoken.match(Tokens.Punctuation, '('):
+ raise Exception("Invalid INSERT statement")
+ for keyword in [' ', ',', self._product_column]:
+ self._token_insert_after(columns_token, ptoken,
Types.Token(Tokens.Keyword, keyword))
+ return
+ def insert_extra_column_value(tablename, ptoken, start_token):
+ if tablename in self._translate_tables:
+ for keyword in [',', "'", self._product_prefix, "'"]:
+ self._token_insert_after(ptoken, start_token,
Types.Token(Tokens.Keyword, keyword))
+ return
+ tablename = None
+ table_name_token = self._token_next(parent, token)
+ if isinstance(table_name_token, Types.Function):
+ token = self._token_first(table_name_token)
+ if isinstance(token, Types.Identifier):
+ tablename = token.get_name()
+ columns_token = self._token_next(table_name_token, token)
+ insert_extra_column(tablename, columns_token)
+ token = self._token_next(parent, table_name_token)
+ else:
+ tablename = table_name_token.value
+ columns_token = self._token_next(parent, table_name_token)
+ insert_extra_column(tablename, columns_token)
+ token = self._token_next(parent, columns_token)
+ if token.match(Tokens.Keyword, 'VALUES'):
+ token = self._token_next(parent, token)
+ while token:
+ if isinstance(token, Types.Parenthesis):
+ ptoken = self._token_first(token)
+ if not ptoken.match(Tokens.Punctuation, '('):
+ raise Exception("Invalid INSERT statement")
+ insert_extra_column_value(tablename, token, ptoken)
+ while ptoken:
+ if not ptoken.match(Tokens.Punctuation, [',', '(',
')']) and \
+ not ptoken.match(Tokens.Keyword, [',', '(', ')'])
and \
+ not ptoken.is_whitespace():
+ ptoken = self._expression_token_unwind_hack(token,
ptoken, self._token_prev(token, ptoken))
+ self._eval_expression_value(token, ptoken)
+ ptoken = self._token_next(token, ptoken)
+ elif not token.match(Tokens.Punctuation, [',', '(', ')']) and\
+ not token.match(Tokens.Keyword, [',', '(', ')']) and\
+ not token.is_whitespace():
+ raise Exception("Invalid INSERT statement, unable to parse
VALUES section")
+ token = self._token_next(parent, token)
+ elif token.match(Tokens.DML, 'SELECT'):
+ self._select(parent, token, insert_table=tablename)
+ else:
+ raise Exception("Invalid INSERT statement")
+ return
+
+ def _update_delete_where_limit(self, table_name, parent, start_token):
+ if not start_token:
+ return
+ where_token = start_token if isinstance(start_token, Types.Where) \
+ else self._token_next_by_instance(parent,
start_token, Types.Where)
+ if where_token:
+ self._where(parent, where_token)
+ if not table_name in self._translate_tables:
+ return
+ if where_token:
+ keywords = [self._product_column, '=', "'", self._product_prefix,
"'", ' ', 'AND', ' ']
+ keywords.reverse()
+ token = self._token_first(where_token)
+ if not token.match(Tokens.Keyword, 'WHERE'):
+ token = self._token_next_match(where_token, token,
Tokens.Keyword, 'WHERE')
+ if not token:
+ raise Exception("Invalid UPDATE statement, failed to parse
WHERE")
+ for keyword in keywords:
+ self._token_insert_after(where_token, token,
Types.Token(Tokens.Keyword, keyword))
+ else:
+ keywords = ['WHERE', ' ', self._product_column, '=', "'",
self._product_prefix, "'"]
+ limit_token = self._token_next_match(parent, start_token,
Tokens.Keyword, 'LIMIT')
+ if limit_token:
+ for keyword in keywords:
+ self._token_insert_before(parent, limit_token,
Types.Token(Tokens.Keyword, keyword))
+ self._token_insert_before(parent, limit_token,
Types.Token(Tokens.Keyword, ' '))
+ else:
+ last_token = token = start_token
+ while token:
+ last_token = token
+ token = self._token_next(parent, token)
+ keywords.reverse()
+ for keyword in keywords:
+ self._token_insert_after(parent, last_token,
Types.Token(Tokens.Keyword, keyword))
+ return
+
+ def _update(self, parent, start_token):
+ table_name_token = self._token_next(parent, start_token)
+ if isinstance(table_name_token, Types.Identifier):
+ tablename = table_name_token.get_name()
+ elif isinstance(table_name_token, Types.Token):
+ tablename = table_name_token.value
+ else:
+ raise Exception("Invalid UPDATE statement, expected table name")
+ set_token = self._token_next_match(parent, table_name_token,
Tokens.Keyword, 'SET')
+ if set_token:
+ token = set_token
+ while token and \
+ not isinstance(token, Types.Where) and \
+ not token.match(Tokens.Keyword, 'LIMIT'):
+ if not token.match(Tokens.Keyword, 'SET') and \
+ not token.match(Tokens.Punctuation, ','):
+ raise Exception("Invalid UPDATE statement, failed to match
separator")
+ column_token = self._token_next(parent, token)
+ if isinstance(column_token, Types.Comparison):
+ token = self._token_next(parent, column_token)
+ continue
+ equals_token = self._token_next(parent, column_token)
+ if not equals_token.match(Tokens.Token.Operator.Comparison,
'='):
+ raise Exception("Invalid UPDATE statement, SET equals
token mismatch")
+ expression_token = self._token_next(parent, equals_token)
+ expression_token = self._expression_token_unwind_hack(parent,
expression_token, equals_token)
+ self._eval_expression_value(parent, expression_token)
+ token = self._token_next(parent, expression_token)
+ start_token = token
+ self._update_delete_where_limit(tablename, parent, start_token)
+ return
+
+ def _delete(self, parent, start_token):
+ token = self._token_next(parent, start_token)
+ if not token.match(Tokens.Keyword, 'FROM'):
+ raise Exception("Invalid DELETE statement")
+ table_name_token = self._token_next(parent, token)
+ if isinstance(table_name_token, Types.Identifier):
+ tablename = table_name_token.get_name()
+ elif isinstance(table_name_token, Types.Token):
+ tablename = table_name_token.value
+ else:
+ raise Exception("Invalid DELETE statement, expected table name")
+ if not tablename in self._translate_tables:
+ return
+ self._update_delete_where_limit(tablename, parent, start_token)
+ return
+
+ def translate(self, sql):
+ dml_handlers = {'SELECT': self._select,
+ 'INSERT': self._insert,
+ 'UPDATE': self._update,
+ 'DELETE': self._delete,
+ }
+ try:
+ sql_statement = sqlparse.parse(sql)[0]
+ t = sql_statement.token_first()
+ if not t.match(Tokens.DML, dml_handlers.keys()):
+ return sql
+ dml_handlers[t.value](sql_statement, t)
+ translated_sql = sqlparse.format(sql_statement.to_unicode(),
reindent=True)
+ except Exception:
+ raise Exception("Failed to translate SQL '%s'" % sql)
+ return translated_sql
Modified:
incubator/bloodhound/branches/bep_0003_multiproduct/trac/trac/web/standalone.py
URL:
http://svn.apache.org/viewvc/incubator/bloodhound/branches/bep_0003_multiproduct/trac/trac/web/standalone.py?rev=1420075&r1=1420074&r2=1420075&view=diff
==============================================================================
---
incubator/bloodhound/branches/bep_0003_multiproduct/trac/trac/web/standalone.py
(original)
+++
incubator/bloodhound/branches/bep_0003_multiproduct/trac/trac/web/standalone.py
Tue Dec 11 10:28:05 2012
@@ -120,6 +120,8 @@ class TracHTTPRequestHandler(WSGIRequest
class TracHTTP11RequestHandler(TracHTTPRequestHandler):
protocol_version = 'HTTP/1.1'
+from trac.bloodhound import bloodhound_hooks
+bloodhound_hooks()
def main():
from optparse import OptionParser, OptionValueError