diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2005-12-23 01:37:10 +0000 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2005-12-23 01:37:10 +0000 |
commit | dbd407d62ac3cbf6e54de7499f1a95b54e3e4204 (patch) | |
tree | aba3a06c75f1c7e477e2429cfe6d97401242da35 /lib/sqlalchemy/ansisql.py | |
parent | d22f5edcae0f29c6542e800660bc4fef9b3f12cb (diff) | |
download | sqlalchemy-dbd407d62ac3cbf6e54de7499f1a95b54e3e4204.tar.gz |
move execute parameter processing from sql.ClauseElement to engine.execute_compiled
testbase gets "assert_sql_count" method, moves execution wrapping to pre_exec to accomodate engine change
move _get_colparams from Insert/Update to ansisql since it applies to compilation
ansisql also insures that select list for columns is unique, helps the mapper with the "distinct" keyword
docstrings/cleanup
Diffstat (limited to 'lib/sqlalchemy/ansisql.py')
-rw-r--r-- | lib/sqlalchemy/ansisql.py | 80 |
1 files changed, 71 insertions, 9 deletions
diff --git a/lib/sqlalchemy/ansisql.py b/lib/sqlalchemy/ansisql.py index d8d2662ba..7a90e746a 100644 --- a/lib/sqlalchemy/ansisql.py +++ b/lib/sqlalchemy/ansisql.py @@ -244,23 +244,32 @@ class ANSICompiler(sql.Compiled): self.strings[alias] = self.get_str(alias.selectable) def visit_select(self, select): - inner_columns = [] - + + # the actual list of columns to print in the SELECT column list. + # its an ordered dictionary to insure that the actual labeled column name + # is unique. + inner_columns = OrderedDict() + def col_key(c): + if select.use_labels: + return c.label + else: + return self.get_str(c) + self.select_stack.append(select) for c in select._raw_columns: if c.is_selectable(): for co in c.columns: co.accept_visitor(self) - inner_columns.append(co) + inner_columns[col_key(co)] = co else: c.accept_visitor(self) - inner_columns.append(c) + inner_columns[col_key(c)] = c self.select_stack.pop(-1) if select.use_labels: - collist = string.join(["%s AS %s" % (self.get_str(c), c.label) for c in inner_columns], ', ') + collist = string.join(["%s AS %s" % (self.get_str(v), k) for k, v in inner_columns.iteritems()], ', ') else: - collist = string.join([self.get_str(c) for c in inner_columns], ', ') + collist = string.join([k for k in inner_columns.keys()], ', ') text = "SELECT " if select.distinct: @@ -275,7 +284,7 @@ class ANSICompiler(sql.Compiled): # matching those keys if self.parameters is not None: revisit = False - for c in inner_columns: + for c in inner_columns.values(): if self.parameters.has_key(c.key) and not self.binds.has_key(c.key): value = self.parameters[c.key] elif self.parameters.has_key(c.label) and not self.binds.has_key(c.label): @@ -377,7 +386,7 @@ class ANSICompiler(sql.Compiled): c.default.accept_visitor(vis) self.isinsert = True - colparams = insert_stmt.get_colparams(self.parameters) + colparams = self._get_colparams(insert_stmt) for c in colparams: b = c[1] self.binds[b.key] = b @@ -389,7 +398,7 @@ class ANSICompiler(sql.Compiled): self.strings[insert_stmt] = text def visit_update(self, update_stmt): - colparams = update_stmt.get_colparams(self.parameters) + colparams = self._get_colparams(update_stmt) def create_param(p): if isinstance(p, sql.BindParamClause): self.binds[p.key] = p @@ -409,6 +418,59 @@ class ANSICompiler(sql.Compiled): self.strings[update_stmt] = text + + def _get_colparams(self, stmt): + """determines the VALUES or SET clause for an INSERT or UPDATE + clause based on the arguments specified to this ANSICompiler object + (i.e., the execute() or compile() method clause object): + + insert(mytable).execute(col1='foo', col2='bar') + mytable.update().execute(col2='foo', col3='bar') + + in the above examples, the insert() and update() methods have no "values" sent to them + at all, so compiling them with no arguments would yield an insert for all table columns, + or an update with no SET clauses. but the parameters sent indicate a set of per-compilation + arguments that result in a differently compiled INSERT or UPDATE object compared to the + original. The "values" parameter to the insert/update is figured as well if present, + but the incoming "parameters" sent here take precedence. + """ + # case one: no parameters in the statement, no parameters in the + # compiled params - just return binds for all the table columns + if self.parameters is None and stmt.parameters is None: + return [(c, bindparam(c.name, type=c.type)) for c in stmt.table.columns] + + # if we have statement parameters - set defaults in the + # compiled params + if self.parameters is None: + parameters = {} + else: + parameters = self.parameters.copy() + + if stmt.parameters is not None: + for k, v in stmt.parameters.iteritems(): + parameters.setdefault(k, v) + + # now go thru compiled params, get the Column object for each key + d = {} + for key, value in parameters.iteritems(): + if isinstance(key, schema.Column): + d[key] = value + else: + try: + d[stmt.table.columns[str(key)]] = value + except KeyError: + pass + + # create a list of column assignment clauses as tuples + values = [] + for c in stmt.table.columns: + if d.has_key(c): + value = d[c] + if sql._is_literal(value): + value = bindparam(c.name, value, type=c.type) + values.append((c, value)) + return values + def visit_delete(self, delete_stmt): text = "DELETE FROM " + delete_stmt.table.fullname |