From a5555c25c8574184e8bc2afeee93bec2cc3f9272 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Thu, 25 Oct 2012 15:49:44 -0400 Subject: [PATCH] update to new doc system --- CHANGES | 6 + doc/build/builder/autodoc_mods.py | 47 + doc/build/builder/builders.py | 212 - doc/build/builder/changelog.py | 286 ++ doc/build/builder/dialect_info.py | 174 + doc/build/builder/mako.py | 82 + doc/build/builder/sqlformatter.py | 132 + doc/build/changelog/changelog_01.rst | 975 +++++ doc/build/changelog/changelog_02.rst | 1187 ++++++ doc/build/changelog/changelog_03.rst | 2928 ++++++++++++++ doc/build/changelog/changelog_04.rst | 4198 ++++++++++++++++++++ doc/build/changelog/changelog_05.rst | 3775 ++++++++++++++++++ doc/build/changelog/changelog_06.rst | 5406 ++++++++++++++++++++++++++ doc/build/changelog/changelog_07.rst | 4436 +++++++++++++++++++++ doc/build/changelog/index.rst | 34 + doc/build/changelog/migration_04.rst | 868 +++++ doc/build/changelog/migration_05.rst | 746 ++++ doc/build/changelog/migration_06.rst | 1228 ++++++ doc/build/changelog/migration_07.rst | 1360 +++++++ doc/build/conf.py | 26 +- doc/build/index.rst | 5 +- doc/build/intro.rst | 3 +- doc/build/static/docs.css | 40 +- test/orm/test_attributes.py | 10 +- 24 files changed, 27935 insertions(+), 229 deletions(-) create mode 100644 doc/build/builder/autodoc_mods.py delete mode 100644 doc/build/builder/builders.py create mode 100644 doc/build/builder/changelog.py create mode 100644 doc/build/builder/dialect_info.py create mode 100644 doc/build/builder/mako.py create mode 100644 doc/build/builder/sqlformatter.py create mode 100644 doc/build/changelog/changelog_01.rst create mode 100644 doc/build/changelog/changelog_02.rst create mode 100644 doc/build/changelog/changelog_03.rst create mode 100644 doc/build/changelog/changelog_04.rst create mode 100644 doc/build/changelog/changelog_05.rst create mode 100644 doc/build/changelog/changelog_06.rst create mode 100644 doc/build/changelog/changelog_07.rst create mode 100644 doc/build/changelog/index.rst create mode 100644 doc/build/changelog/migration_04.rst create mode 100644 doc/build/changelog/migration_05.rst create mode 100644 doc/build/changelog/migration_06.rst create mode 100644 doc/build/changelog/migration_07.rst diff --git a/CHANGES b/CHANGES index 0c795c2715..e0d4d7c424 100644 --- a/CHANGES +++ b/CHANGES @@ -5,6 +5,12 @@ CHANGES ======= 0.7.10 ====== +- changelog + - The changelog has been moved to the documentation. + This file will be maintained throughout remaining + 0.7 maintenance for backwards compabitility, but + is removed in 0.8. + - orm - [bug] Fixed Session accounting bug whereby replacing a deleted object in the identity map with another diff --git a/doc/build/builder/autodoc_mods.py b/doc/build/builder/autodoc_mods.py new file mode 100644 index 0000000000..8c687fb3ae --- /dev/null +++ b/doc/build/builder/autodoc_mods.py @@ -0,0 +1,47 @@ +import re + +def autodoc_skip_member(app, what, name, obj, skip, options): + if what == 'class' and skip and \ + name in ('__init__', '__eq__', '__ne__', '__lt__', + '__le__', '__call__') and \ + obj.__doc__: + return False + else: + return skip + +# im sure this is in the app somewhere, but I don't really +# know where, so we're doing it here. +_track_autodoced = {} +def autodoc_process_docstring(app, what, name, obj, options, lines): + if what == "class": + _track_autodoced[name] = obj + elif what in ("attribute", "method") and \ + options.get("inherited-members"): + m = re.match(r'(.*?)\.([\w_]+)$', name) + if m: + clsname, attrname = m.group(1, 2) + if clsname in _track_autodoced: + cls = _track_autodoced[clsname] + for supercls in cls.__mro__: + if attrname in supercls.__dict__: + break + if supercls is not cls: + lines[:0] = [ + ".. container:: inherited_member", + "", + " *inherited from the* :%s:`.%s.%s` *%s of* :class:`.%s`" % ( + "attr" if what == "attribute" + else "meth", + supercls.__name__, + attrname, + what, + supercls.__name__ + ), + "" + ] + + +def setup(app): + app.connect('autodoc-skip-member', autodoc_skip_member) + app.connect('autodoc-process-docstring', autodoc_process_docstring) + diff --git a/doc/build/builder/builders.py b/doc/build/builder/builders.py deleted file mode 100644 index 46469e3dfa..0000000000 --- a/doc/build/builder/builders.py +++ /dev/null @@ -1,212 +0,0 @@ -from sphinx.application import TemplateBridge -from sphinx.builders.html import StandaloneHTMLBuilder -from sphinx.highlighting import PygmentsBridge -from sphinx.jinja2glue import BuiltinTemplateLoader -from pygments import highlight -from pygments.lexer import RegexLexer, bygroups, using -from pygments.token import * -from pygments.filter import Filter, apply_filters -from pygments.lexers import PythonLexer, PythonConsoleLexer -from pygments.formatters import HtmlFormatter, LatexFormatter -import re -from mako.lookup import TemplateLookup -from mako.template import Template -from mako import __version__ -import os - -rtd = os.environ.get('READTHEDOCS', None) == 'True' - -class MakoBridge(TemplateBridge): - def init(self, builder, *args, **kw): - self.jinja2_fallback = BuiltinTemplateLoader() - self.jinja2_fallback.init(builder, *args, **kw) - - builder.config.html_context['release_date'] = builder.config['release_date'] - builder.config.html_context['site_base'] = builder.config['site_base'] - - self.lookup = TemplateLookup(directories=builder.config.templates_path, - #format_exceptions=True, - imports=[ - "from builder import util" - ] - ) - - if rtd: - import urllib2 - template_url = builder.config['site_base'] + "/docs_base.mako" - template = urllib2.urlopen(template_url).read() - self.lookup.put_string("/rtd_base.mako", template) - - def render(self, template, context): - template = template.replace(".html", ".mako") - context['prevtopic'] = context.pop('prev', None) - context['nexttopic'] = context.pop('next', None) - version = context['version'] - pathto = context['pathto'] - - # RTD layout - if rtd: - # add variables if not present, such - # as if local test of READTHEDOCS variable - if 'MEDIA_URL' not in context: - context['MEDIA_URL'] = "http://media.readthedocs.org/" - if 'slug' not in context: - context['slug'] = context['project'].lower() - if 'url' not in context: - context['url'] = "/some/test/url" - if 'current_version' not in context: - context['current_version'] = "latest" - - if 'name' not in context: - context['name'] = context['project'].lower() - - context['rtd'] = True - context['toolbar'] = True - context['layout'] = "rtd_layout.mako" - context['base'] = "rtd_base.mako" - context['pdf_url'] = "%spdf/%s/%s/%s.pdf" % ( - context['MEDIA_URL'], - context['slug'], - context['current_version'], - context['slug'] - ) - # local docs layout - else: - context['rtd'] = False - context['toolbar'] = False - context['layout'] = "layout.mako" - context['base'] = "static_base.mako" - - context.setdefault('_', lambda x:x) - return self.lookup.get_template(template).render_unicode(**context) - - def render_string(self, template, context): - # this is used for .js, .css etc. and we don't have - # local copies of that stuff here so use the jinja render. - return self.jinja2_fallback.render_string(template, context) - -class StripDocTestFilter(Filter): - def filter(self, lexer, stream): - for ttype, value in stream: - if ttype is Token.Comment and re.match(r'#\s*doctest:', value): - continue - yield ttype, value - -class PyConWithSQLLexer(RegexLexer): - name = 'PyCon+SQL' - aliases = ['pycon+sql'] - - flags = re.IGNORECASE | re.DOTALL - - tokens = { - 'root': [ - (r'{sql}', Token.Sql.Link, 'sqlpopup'), - (r'{opensql}', Token.Sql.Open, 'opensqlpopup'), - (r'.*?\n', using(PythonConsoleLexer)) - ], - 'sqlpopup':[ - ( - r'(.*?\n)((?:PRAGMA|BEGIN|SELECT|INSERT|DELETE|ROLLBACK|COMMIT|ALTER|UPDATE|CREATE|DROP|PRAGMA|DESCRIBE).*?(?:{stop}\n?|$))', - bygroups(using(PythonConsoleLexer), Token.Sql.Popup), - "#pop" - ) - ], - 'opensqlpopup':[ - ( - r'.*?(?:{stop}\n*|$)', - Token.Sql, - "#pop" - ) - ] - } - - -class PythonWithSQLLexer(RegexLexer): - name = 'Python+SQL' - aliases = ['pycon+sql'] - - flags = re.IGNORECASE | re.DOTALL - - tokens = { - 'root': [ - (r'{sql}', Token.Sql.Link, 'sqlpopup'), - (r'{opensql}', Token.Sql.Open, 'opensqlpopup'), - (r'.*?\n', using(PythonLexer)) - ], - 'sqlpopup':[ - ( - r'(.*?\n)((?:PRAGMA|BEGIN|SELECT|INSERT|DELETE|ROLLBACK|COMMIT|ALTER|UPDATE|CREATE|DROP|PRAGMA|DESCRIBE).*?(?:{stop}\n?|$))', - bygroups(using(PythonLexer), Token.Sql.Popup), - "#pop" - ) - ], - 'opensqlpopup':[ - ( - r'.*?(?:{stop}\n*|$)', - Token.Sql, - "#pop" - ) - ] - } - - -def _strip_trailing_whitespace(iter_): - buf = list(iter_) - if buf: - buf[-1] = (buf[-1][0], buf[-1][1].rstrip()) - for t, v in buf: - yield t, v - -class PopupSQLFormatter(HtmlFormatter): - def _format_lines(self, tokensource): - buf = [] - for ttype, value in apply_filters(tokensource, [StripDocTestFilter()]): - if ttype in Token.Sql: - for t, v in HtmlFormatter._format_lines(self, iter(buf)): - yield t, v - buf = [] - - if ttype is Token.Sql: - yield 1, "
%s
" % re.sub(r'(?:[{stop}|\n]*)$', '', value) - elif ttype is Token.Sql.Link: - yield 1, "sql" - elif ttype is Token.Sql.Popup: - yield 1, "" % re.sub(r'(?:[{stop}|\n]*)$', '', value) - else: - buf.append((ttype, value)) - - for t, v in _strip_trailing_whitespace(HtmlFormatter._format_lines(self, iter(buf))): - yield t, v - -class PopupLatexFormatter(LatexFormatter): - def _filter_tokens(self, tokensource): - for ttype, value in apply_filters(tokensource, [StripDocTestFilter()]): - if ttype in Token.Sql: - if ttype is not Token.Sql.Link and ttype is not Token.Sql.Open: - yield Token.Literal, re.sub(r'{stop}', '', value) - else: - continue - else: - yield ttype, value - - def format(self, tokensource, outfile): - LatexFormatter.format(self, self._filter_tokens(tokensource), outfile) - -def autodoc_skip_member(app, what, name, obj, skip, options): - if what == 'class' and skip and \ - name in ('__init__', '__eq__', '__ne__', '__lt__', '__le__', '__call__') and \ - obj.__doc__: - return False - else: - return skip - -def setup(app): - app.add_lexer('pycon+sql', PyConWithSQLLexer()) - app.add_lexer('python+sql', PythonWithSQLLexer()) - app.add_config_value('release_date', "", True) - app.add_config_value('site_base', "", True) - app.add_config_value('build_number', "", 1) - app.connect('autodoc-skip-member', autodoc_skip_member) - PygmentsBridge.html_formatter = PopupSQLFormatter - PygmentsBridge.latex_formatter = PopupLatexFormatter - diff --git a/doc/build/builder/changelog.py b/doc/build/builder/changelog.py new file mode 100644 index 0000000000..85ae6dba05 --- /dev/null +++ b/doc/build/builder/changelog.py @@ -0,0 +1,286 @@ +import re +from sphinx.util.compat import Directive +from docutils.statemachine import StringList +from docutils import nodes, utils +import textwrap +import itertools +import collections +import md5 + +def _comma_list(text): + return re.split(r"\s*,\s*", text.strip()) + +def _parse_content(content): + d = {} + d['text'] = [] + idx = 0 + for line in content: + idx += 1 + m = re.match(r' *\:(.+?)\:(?: +(.+))?', line) + if m: + attrname, value = m.group(1, 2) + d[attrname] = value or '' + else: + break + d["text"] = content[idx:] + return d + + +class EnvDirective(object): + @property + def env(self): + return self.state.document.settings.env + +class ChangeLogDirective(EnvDirective, Directive): + has_content = True + + type_ = "change" + + default_section = 'misc' + + def _organize_by_section(self, changes): + compound_sections = [(s, s.split(" ")) for s in + self.sections if " " in s] + + bysection = collections.defaultdict(list) + all_sections = set() + for rec in changes: + inner_tag = rec['tags'].intersection(self.inner_tag_sort) + if inner_tag: + inner_tag = inner_tag.pop() + else: + inner_tag = "" + + for compound, comp_words in compound_sections: + if rec['tags'].issuperset(comp_words): + bysection[(compound, inner_tag)].append(rec) + all_sections.add(compound) + break + else: + intersect = rec['tags'].intersection(self.sections) + if intersect: + for sec in rec['sorted_tags']: + if sec in intersect: + bysection[(sec, inner_tag)].append(rec) + all_sections.add(sec) + break + else: + bysection[(self.default_section, inner_tag)].append(rec) + return bysection, all_sections + + @classmethod + def changes(cls, env): + return env.temp_data['ChangeLogDirective_%s_changes' % cls.type_] + + def _setup_run(self): + self.sections = self.env.config.changelog_sections + self.inner_tag_sort = self.env.config.changelog_inner_tag_sort + [""] + self.env.temp_data['ChangeLogDirective_%s_changes' % self.type_] = [] + self._parsed_content = _parse_content(self.content) + + p = nodes.paragraph('', '',) + self.state.nested_parse(self.content[1:], 0, p) + + def run(self): + self._setup_run() + changes = self.changes(self.env) + output = [] + + self.version = version = self._parsed_content.get('version', '') + id_prefix = "%s-%s" % (self.type_, version) + topsection = self._run_top(id_prefix) + output.append(topsection) + + bysection, all_sections = self._organize_by_section(changes) + + counter = itertools.count() + + sections_to_render = [s for s in self.sections if s in all_sections] + if not sections_to_render: + for cat in self.inner_tag_sort: + append_sec = self._append_node() + + for rec in bysection[(self.default_section, cat)]: + rec["id"] = "%s-%s" % (id_prefix, next(counter)) + + self._render_rec(rec, None, cat, append_sec) + + if append_sec.children: + topsection.append(append_sec) + else: + for section in sections_to_render + [self.default_section]: + sec = nodes.section('', + nodes.title(section, section), + ids=["%s-%s" % (id_prefix, section.replace(" ", "-"))] + ) + + append_sec = self._append_node() + sec.append(append_sec) + + for cat in self.inner_tag_sort: + for rec in bysection[(section, cat)]: + rec["id"] = "%s-%s" % (id_prefix, next(counter)) + self._render_rec(rec, section, cat, append_sec) + + if append_sec.children: + topsection.append(sec) + + return output + + def _append_node(self): + return nodes.bullet_list() + + def _run_top(self, id_prefix): + version = self._parsed_content.get('version', '') + topsection = nodes.section('', + nodes.title(version, version), + ids=[id_prefix] + ) + + if self._parsed_content.get("released"): + topsection.append(nodes.Text("Released: %s" % + self._parsed_content['released'])) + else: + topsection.append(nodes.Text("no release date")) + return topsection + + + def _render_rec(self, rec, section, cat, append_sec): + para = rec['node'].deepcopy() + + text = _text_rawsource_from_node(para) + + to_hash = "%s %s" % (self.version, text[0:100]) + targetid = "%s-%s" % (self.type_, + md5.md5(to_hash.encode('ascii', 'ignore') + ).hexdigest()) + targetnode = nodes.target('', '', ids=[targetid]) + para.insert(0, targetnode) + permalink = nodes.reference('', '', + nodes.Text("(link)", "(link)"), + refid=targetid, + classes=['changeset-link'] + ) + para.append(permalink) + + insert_ticket = nodes.paragraph('') + para.append(insert_ticket) + + i = 0 + for collection, render, prefix in ( + (rec['tickets'], self.env.config.changelog_render_ticket, "#%s"), + (rec['pullreq'], self.env.config.changelog_render_pullreq, + "pull request %s"), + (rec['changeset'], self.env.config.changelog_render_changeset, "r%s"), + ): + for refname in collection: + if i > 0: + insert_ticket.append(nodes.Text(", ", ", ")) + else: + insert_ticket.append(nodes.Text(" ", " ")) + i += 1 + if render is not None: + refuri = render % refname + node = nodes.reference('', '', + nodes.Text(prefix % refname, prefix % refname), + refuri=refuri + ) + else: + node = nodes.Text(prefix % refname, prefix % refname) + insert_ticket.append(node) + + if rec['tags']: + tag_node = nodes.strong('', + " ".join("[%s]" % t for t + in + [t1 for t1 in [section, cat] + if t1 in rec['tags']] + + + list(rec['tags'].difference([section, cat])) + ) + " " + ) + para.children[0].insert(0, tag_node) + + append_sec.append( + nodes.list_item('', + nodes.target('', '', ids=[rec['id']]), + para + ) + ) + + +class ChangeDirective(EnvDirective, Directive): + has_content = True + + type_ = "change" + parent_cls = ChangeLogDirective + + def run(self): + content = _parse_content(self.content) + p = nodes.paragraph('', '',) + sorted_tags = _comma_list(content.get('tags', '')) + rec = { + 'tags': set(sorted_tags).difference(['']), + 'tickets': set(_comma_list(content.get('tickets', ''))).difference(['']), + 'pullreq': set(_comma_list(content.get('pullreq', ''))).difference(['']), + 'changeset': set(_comma_list(content.get('changeset', ''))).difference(['']), + 'node': p, + 'type': self.type_, + "title": content.get("title", None), + 'sorted_tags': sorted_tags + } + + if "declarative" in rec['tags']: + rec['tags'].add("orm") + + self.state.nested_parse(content['text'], 0, p) + self.parent_cls.changes(self.env).append(rec) + + return [] + +def _text_rawsource_from_node(node): + src = [] + stack = [node] + while stack: + n = stack.pop(0) + if isinstance(n, nodes.Text): + src.append(n.rawsource) + stack.extend(n.children) + return "".join(src) + +def _rst2sphinx(text): + return StringList( + [line.strip() for line in textwrap.dedent(text).split("\n")] + ) + + +def make_ticket_link(name, rawtext, text, lineno, inliner, + options={}, content=[]): + env = inliner.document.settings.env + render_ticket = env.config.changelog_render_ticket or "%s" + prefix = "#%s" + if render_ticket: + ref = render_ticket % text + node = nodes.reference(rawtext, prefix % text, refuri=ref, **options) + else: + node = nodes.Text(prefix % text, prefix % text) + return [node], [] + +def setup(app): + app.add_directive('changelog', ChangeLogDirective) + app.add_directive('change', ChangeDirective) + app.add_config_value("changelog_sections", [], 'env') + app.add_config_value("changelog_inner_tag_sort", [], 'env') + app.add_config_value("changelog_render_ticket", + None, + 'env' + ) + app.add_config_value("changelog_render_pullreq", + None, + 'env' + ) + app.add_config_value("changelog_render_changeset", + None, + 'env' + ) + app.add_role('ticket', make_ticket_link) diff --git a/doc/build/builder/dialect_info.py b/doc/build/builder/dialect_info.py new file mode 100644 index 0000000000..22e3fb0859 --- /dev/null +++ b/doc/build/builder/dialect_info.py @@ -0,0 +1,174 @@ +import re +from sphinx.util.compat import Directive +from docutils import nodes + +class DialectDirective(Directive): + has_content = True + + _dialects = {} + + def _parse_content(self): + d = {} + d['default'] = self.content[0] + d['text'] = [] + idx = 0 + for line in self.content[1:]: + idx += 1 + m = re.match(r'\:(.+?)\: +(.+)', line) + if m: + attrname, value = m.group(1, 2) + d[attrname] = value + else: + break + d["text"] = self.content[idx + 1:] + return d + + def _dbapi_node(self): + + dialect_name, dbapi_name = self.dialect_name.split("+") + + try: + dialect_directive = self._dialects[dialect_name] + except KeyError: + raise Exception("No .. dialect:: %s directive has been established" + % dialect_name) + + output = [] + + content = self._parse_content() + + parent_section_ref = self.state.parent.children[0]['ids'][0] + self._append_dbapi_bullet(dialect_name, dbapi_name, + content['name'], parent_section_ref) + + p = nodes.paragraph('', '', + nodes.Text( + "Support for the %s database via the %s driver." % ( + dialect_directive.database_name, + content['name'] + ), + "Support for the %s database via the %s driver." % ( + dialect_directive.database_name, + content['name'] + ) + ), + ) + + self.state.nested_parse(content['text'], 0, p) + output.append(p) + + if "url" in content or "driverurl" in content: + sec = nodes.section( + '', + nodes.title("DBAPI", "DBAPI"), + ids=["dialect-%s-%s-url" % (dialect_name, dbapi_name)] + ) + if "url" in content: + text = "Documentation and download information (if applicable) "\ + "for %s is available at:\n" % content["name"] + uri = content['url'] + sec.append( + nodes.paragraph('', '', + nodes.Text(text, text), + nodes.reference('', '', + nodes.Text(uri, uri), + refuri=uri, + ) + ) + ) + if "driverurl" in content: + text = "Drivers for this database are available at:\n" + sec.append( + nodes.paragraph('', '', + nodes.Text(text, text), + nodes.reference('', '', + nodes.Text(content['driverurl'], content['driverurl']), + refuri=content['driverurl'] + ) + ) + ) + output.append(sec) + + + if "connectstring" in content: + sec = nodes.section( + '', + nodes.title("Connecting", "Connecting"), + nodes.paragraph('', '', + nodes.Text("Connect String:", "Connect String:"), + nodes.literal_block(content['connectstring'], + content['connectstring']) + ), + ids=["dialect-%s-%s-connect" % (dialect_name, dbapi_name)] + ) + output.append(sec) + + return output + + def _dialect_node(self): + self._dialects[self.dialect_name] = self + + content = self._parse_content() + self.database_name = content['name'] + + self.bullets = nodes.bullet_list() + text = "The following dialect/DBAPI options are available. "\ + "Please refer to individual DBAPI sections for connect information." + sec = nodes.section('', + nodes.paragraph('', '', + nodes.Text( + "Support for the %s database." % content['name'], + "Support for the %s database." % content['name'] + ), + ), + nodes.title("DBAPI Support", "DBAPI Support"), + nodes.paragraph('', '', + nodes.Text(text, text), + self.bullets + ), + ids=["dialect-%s" % self.dialect_name] + ) + + return [sec] + + def _append_dbapi_bullet(self, dialect_name, dbapi_name, name, idname): + env = self.state.document.settings.env + dialect_directive = self._dialects[dialect_name] + + list_node = nodes.list_item('', + nodes.paragraph('', '', + nodes.reference('', '', + nodes.Text(name, name), + refdocname=self.docname, + refuri=env.app.builder.get_relative_uri( + dialect_directive.docname, self.docname) + + "#" + idname + ), + #nodes.Text(" ", " "), + #nodes.reference('', '', + # nodes.Text("(connectstring)", "(connectstring)"), + # refdocname=self.docname, + # refuri=env.app.builder.get_relative_uri( + # dialect_directive.docname, self.docname) + + ## "#" + ("dialect-%s-%s-connect" % + # (dialect_name, dbapi_name)) + # ) + ) + ) + dialect_directive.bullets.append(list_node) + + def run(self): + env = self.state.document.settings.env + self.docname = env.docname + + self.dialect_name = dialect_name = self.content[0] + + has_dbapi = "+" in dialect_name + if has_dbapi: + return self._dbapi_node() + else: + return self._dialect_node() + +def setup(app): + app.add_directive('dialect', DialectDirective) + diff --git a/doc/build/builder/mako.py b/doc/build/builder/mako.py new file mode 100644 index 0000000000..845686afcc --- /dev/null +++ b/doc/build/builder/mako.py @@ -0,0 +1,82 @@ +from __future__ import absolute_import + +from sphinx.application import TemplateBridge +from sphinx.jinja2glue import BuiltinTemplateLoader +from mako.lookup import TemplateLookup +import os + +rtd = os.environ.get('READTHEDOCS', None) == 'True' + +class MakoBridge(TemplateBridge): + def init(self, builder, *args, **kw): + self.jinja2_fallback = BuiltinTemplateLoader() + self.jinja2_fallback.init(builder, *args, **kw) + + builder.config.html_context['release_date'] = builder.config['release_date'] + builder.config.html_context['site_base'] = builder.config['site_base'] + + self.lookup = TemplateLookup(directories=builder.config.templates_path, + #format_exceptions=True, + imports=[ + "from builder import util" + ] + ) + + if rtd: + import urllib2 + template_url = builder.config['site_base'] + "/docs_base.mako" + template = urllib2.urlopen(template_url).read() + self.lookup.put_string("/rtd_base.mako", template) + + def render(self, template, context): + template = template.replace(".html", ".mako") + context['prevtopic'] = context.pop('prev', None) + context['nexttopic'] = context.pop('next', None) + + # RTD layout + if rtd: + # add variables if not present, such + # as if local test of READTHEDOCS variable + if 'MEDIA_URL' not in context: + context['MEDIA_URL'] = "http://media.readthedocs.org/" + if 'slug' not in context: + context['slug'] = context['project'].lower() + if 'url' not in context: + context['url'] = "/some/test/url" + if 'current_version' not in context: + context['current_version'] = "latest" + + if 'name' not in context: + context['name'] = context['project'].lower() + + context['rtd'] = True + context['toolbar'] = True + context['layout'] = "rtd_layout.mako" + context['base'] = "rtd_base.mako" + context['pdf_url'] = "%spdf/%s/%s/%s.pdf" % ( + context['MEDIA_URL'], + context['slug'], + context['current_version'], + context['slug'] + ) + # local docs layout + else: + context['rtd'] = False + context['toolbar'] = False + context['layout'] = "layout.mako" + context['base'] = "static_base.mako" + + context.setdefault('_', lambda x: x) + return self.lookup.get_template(template).render_unicode(**context) + + def render_string(self, template, context): + # this is used for .js, .css etc. and we don't have + # local copies of that stuff here so use the jinja render. + return self.jinja2_fallback.render_string(template, context) + +def setup(app): + app.config['template_bridge'] = "builder.mako.MakoBridge" + app.add_config_value('release_date', "", 'env') + app.add_config_value('site_base', "", 'env') + app.add_config_value('build_number', "", 'env') + diff --git a/doc/build/builder/sqlformatter.py b/doc/build/builder/sqlformatter.py new file mode 100644 index 0000000000..2d80749000 --- /dev/null +++ b/doc/build/builder/sqlformatter.py @@ -0,0 +1,132 @@ +from pygments.lexer import RegexLexer, bygroups, using +from pygments.token import Token +from pygments.filter import Filter +from pygments.filter import apply_filters +from pygments.lexers import PythonLexer, PythonConsoleLexer +from sphinx.highlighting import PygmentsBridge +from pygments.formatters import HtmlFormatter, LatexFormatter + +import re + + +def _strip_trailing_whitespace(iter_): + buf = list(iter_) + if buf: + buf[-1] = (buf[-1][0], buf[-1][1].rstrip()) + for t, v in buf: + yield t, v + + +class StripDocTestFilter(Filter): + def filter(self, lexer, stream): + for ttype, value in stream: + if ttype is Token.Comment and re.match(r'#\s*doctest:', value): + continue + yield ttype, value + +class PyConWithSQLLexer(RegexLexer): + name = 'PyCon+SQL' + aliases = ['pycon+sql'] + + flags = re.IGNORECASE | re.DOTALL + + tokens = { + 'root': [ + (r'{sql}', Token.Sql.Link, 'sqlpopup'), + (r'{opensql}', Token.Sql.Open, 'opensqlpopup'), + (r'.*?\n', using(PythonConsoleLexer)) + ], + 'sqlpopup': [ + ( + r'(.*?\n)((?:PRAGMA|BEGIN|SELECT|INSERT|DELETE|ROLLBACK|' + 'COMMIT|ALTER|UPDATE|CREATE|DROP|PRAGMA' + '|DESCRIBE).*?(?:{stop}\n?|$))', + bygroups(using(PythonConsoleLexer), Token.Sql.Popup), + "#pop" + ) + ], + 'opensqlpopup': [ + ( + r'.*?(?:{stop}\n*|$)', + Token.Sql, + "#pop" + ) + ] + } + + +class PythonWithSQLLexer(RegexLexer): + name = 'Python+SQL' + aliases = ['pycon+sql'] + + flags = re.IGNORECASE | re.DOTALL + + tokens = { + 'root': [ + (r'{sql}', Token.Sql.Link, 'sqlpopup'), + (r'{opensql}', Token.Sql.Open, 'opensqlpopup'), + (r'.*?\n', using(PythonLexer)) + ], + 'sqlpopup': [ + ( + r'(.*?\n)((?:PRAGMA|BEGIN|SELECT|INSERT|DELETE|ROLLBACK' + '|COMMIT|ALTER|UPDATE|CREATE|DROP' + '|PRAGMA|DESCRIBE).*?(?:{stop}\n?|$))', + bygroups(using(PythonLexer), Token.Sql.Popup), + "#pop" + ) + ], + 'opensqlpopup': [ + ( + r'.*?(?:{stop}\n*|$)', + Token.Sql, + "#pop" + ) + ] + } + +class PopupSQLFormatter(HtmlFormatter): + def _format_lines(self, tokensource): + buf = [] + for ttype, value in apply_filters(tokensource, [StripDocTestFilter()]): + if ttype in Token.Sql: + for t, v in HtmlFormatter._format_lines(self, iter(buf)): + yield t, v + buf = [] + + if ttype is Token.Sql: + yield 1, "
%s
" % \ + re.sub(r'(?:[{stop}|\n]*)$', '', value) + elif ttype is Token.Sql.Link: + yield 1, "sql" + elif ttype is Token.Sql.Popup: + yield 1, "" % \ + re.sub(r'(?:[{stop}|\n]*)$', '', value) + else: + buf.append((ttype, value)) + + for t, v in _strip_trailing_whitespace( + HtmlFormatter._format_lines(self, iter(buf))): + yield t, v + +class PopupLatexFormatter(LatexFormatter): + def _filter_tokens(self, tokensource): + for ttype, value in apply_filters(tokensource, [StripDocTestFilter()]): + if ttype in Token.Sql: + if ttype is not Token.Sql.Link and ttype is not Token.Sql.Open: + yield Token.Literal, re.sub(r'{stop}', '', value) + else: + continue + else: + yield ttype, value + + def format(self, tokensource, outfile): + LatexFormatter.format(self, self._filter_tokens(tokensource), outfile) + +def setup(app): + app.add_lexer('pycon+sql', PyConWithSQLLexer()) + app.add_lexer('python+sql', PythonWithSQLLexer()) + + PygmentsBridge.html_formatter = PopupSQLFormatter + PygmentsBridge.latex_formatter = PopupLatexFormatter + diff --git a/doc/build/changelog/changelog_01.rst b/doc/build/changelog/changelog_01.rst new file mode 100644 index 0000000000..156599a13e --- /dev/null +++ b/doc/build/changelog/changelog_01.rst @@ -0,0 +1,975 @@ + +============== +0.1 Changelog +============== + + +.. changelog:: + :version: 0.1.7 + :released: Fri May 05 2006 + + .. change:: + :tags: + :tickets: + + some fixes to topological sort algorithm + + .. change:: + :tags: + :tickets: + + added DISTINCT ON support to Postgres (just supply distinct=[col1,col2..]) + + .. change:: + :tags: + :tickets: + + added __mod__ (% operator) to sql expressions + + .. change:: + :tags: + :tickets: + + "order_by" mapper property inherited from inheriting mapper + + .. change:: + :tags: + :tickets: + + fix to column type used when mapper UPDATES/DELETEs + + .. change:: + :tags: + :tickets: + + with convert_unicode=True, reflection was failing, has been fixed + + .. change:: + :tags: + :tickets: + + types types types! still werent working....have to use TypeDecorator again :( + + .. change:: + :tags: + :tickets: + + mysql binary type converts array output to buffer, fixes PickleType + + .. change:: + :tags: + :tickets: + + fixed the attributes.py memory leak once and for all + + .. change:: + :tags: + :tickets: + + unittests are qualified based on the databases that support each one + + .. change:: + :tags: + :tickets: + + fixed bug where column defaults would clobber VALUES clause of insert objects + + .. change:: + :tags: + :tickets: + + fixed bug where table def w/ schema name would force engine connection + + .. change:: + :tags: + :tickets: + + fix for parenthesis to work correctly with subqueries in INSERT/UPDATE + + .. change:: + :tags: + :tickets: + + HistoryArraySet gets extend() method + + .. change:: + :tags: + :tickets: + + fixed lazyload support for other comparison operators besides = + + .. change:: + :tags: + :tickets: + + lazyload fix where two comparisons in the join condition point to the + samem column + + .. change:: + :tags: + :tickets: + + added "construct_new" flag to mapper, will use __new__ to create instances + instead of __init__ (standard in 0.2) + + .. change:: + :tags: + :tickets: + + added selectresults.py to SVN, missed it last time + + .. change:: + :tags: + :tickets: + + tweak to allow a many-to-many relationship from a table to itself via + an association table + + .. change:: + :tags: + :tickets: + + small fix to "translate_row" function used by polymorphic example + + .. change:: + :tags: + :tickets: + + create_engine uses cgi.parse_qsl to read query string (out the window in 0.2) + + .. change:: + :tags: + :tickets: + + tweaks to CAST operator + + .. change:: + :tags: + :tickets: + + fixed function names LOCAL_TIME/LOCAL_TIMESTAMP -> LOCALTIME/LOCALTIMESTAMP + + .. change:: + :tags: + :tickets: + + fixed order of ORDER BY/HAVING in compile + +.. changelog:: + :version: 0.1.6 + :released: Wed Apr 12 2006 + + .. change:: + :tags: + :tickets: + + support for MS-SQL added courtesy Rick Morrison, Runar Petursson + + .. change:: + :tags: + :tickets: + + the latest SQLSoup from J. Ellis + + .. change:: + :tags: + :tickets: + + ActiveMapper has preliminary support for inheritance (Jeff Watkins) + + .. change:: + :tags: + :tickets: + + added a "mods" system which allows pluggable modules that modify/augment + core functionality, using the function "install_mods(*modnames)". + + .. change:: + :tags: + :tickets: + + added the first "mod", SelectResults, which modifies mapper selects to + return generators that turn ranges into LIMIT/OFFSET queries + (Jonas Borgstr? + + .. change:: + :tags: + :tickets: + + factored out querying capabilities of Mapper into a separate Query object + which is Session-centric. this improves the performance of mapper.using(session) + and makes other things possible. + + .. change:: + :tags: + :tickets: + + objectstore/Session refactored, the official way to save objects is now + via the flush() method. The begin/commit functionality of Session is factored + into LegacySession which is still established as the default behavior, until + the 0.2 series. + + .. change:: + :tags: + :tickets: + + types system is bound to an engine at query compile time, not schema + construction time. this simplifies the types system as well as the ProxyEngine. + + .. change:: + :tags: + :tickets: + + added 'version_id' keyword argument to mapper. this keyword should reference a + Column object with type Integer, preferably non-nullable, which will be used on + the mapped table to track version numbers. this number is incremented on each + save operation and is specifed in the UPDATE/DELETE conditions so that it + factors into the returned row count, which results in a ConcurrencyError if the + value received is not the expected count. + + .. change:: + :tags: + :tickets: + + added 'entity_name' keyword argument to mapper. a mapper is now associated + with a class via the class object as well as an optional entity_name parameter, + which is a string defaulting to None. any number of primary mappers can be + created for a class, qualified by the entity name. instances of those classes + will issue all of their load and save operations through their + entity_name-qualified mapper, and maintain separate a identity in the identity + map for an otherwise equilvalent object. + + .. change:: + :tags: + :tickets: + + overhaul to the attributes system. code has been clarified, and also fixed to + support proper polymorphic behavior on object attributes. + + .. change:: + :tags: + :tickets: + + added "for_update" flag to Select objects + + .. change:: + :tags: + :tickets: + + some fixes for backrefs + + .. change:: + :tags: + :tickets: + + fix for postgres1 DateTime type + + .. change:: + :tags: + :tickets: + + documentation pages mostly switched over to Markdown syntax + +.. changelog:: + :version: 0.1.5 + :released: Mon Mar 27 2006 + + .. change:: + :tags: + :tickets: + + added SQLSession concept to SQLEngine. this object keeps track of retrieving a + connection from the connection pool as well as an in-progress transaction. + methods push_session() and pop_session() added to SQLEngine which push/pop a new + SQLSession onto the engine, allowing operation upon a second connection "nested" + within the previous one, allowing nested transactions. Other tricks are sure to + come later regarding SQLSession. + + .. change:: + :tags: + :tickets: + + added nest_on argument to objectstore.Session. This is a single SQLEngine or + list of engines for which push_session()/pop_session() will be called each time + this Session becomes the active session (via objectstore.push_session() or + equivalent). This allows a unit of work Session to take advantage of the nested + transaction feature without explicitly calling push_session/pop_session on the + engine. + + .. change:: + :tags: + :tickets: + + factored apart objectstore/unitofwork to separate "Session scoping" from + "uow commit heavy lifting" + + .. change:: + :tags: + :tickets: + + added populate_instance() method to MapperExtension. allows an extension to + modify the population of object attributes. this method can call the + populate_instance() method on another mapper to proxy the attribute population + from one mapper to another; some row translation logic is also built in to help + with this. + + .. change:: + :tags: + :tickets: + + fixed Oracle8-compatibility "use_ansi" flag which converts JOINs to + comparisons with the = and (+) operators, passes basic unittests + + .. change:: + :tags: + :tickets: + + tweaks to Oracle LIMIT/OFFSET support + + .. change:: + :tags: + :tickets: + + Oracle reflection uses ALL_** views instead of USER_** to get larger + list of stuff to reflect from + + .. change:: + :tags: + :tickets: 105 + + fixes to Oracle foreign key reflection + + .. change:: + :tags: + :tickets: + + objectstore.commit(obj1, obj2,...) adds an extra step to seek out private + relations on properties and delete child objects, even though its not a global + commit + + .. change:: + :tags: + :tickets: + + lots and lots of fixes to mappers which use inheritance, strengthened the + concept of relations on a mapper being made towards the "local" table for that + mapper, not the tables it inherits. allows more complex compositional patterns + to work with lazy/eager loading. + + .. change:: + :tags: + :tickets: + + added support for mappers to inherit from others based on the same table, + just specify the same table as that of both parent/child mapper. + + .. change:: + :tags: + :tickets: + + some minor speed improvements to the attributes system with regards to + instantiating and populating new objects. + + .. change:: + :tags: + :tickets: + + fixed MySQL binary unit test + + .. change:: + :tags: + :tickets: + + INSERTs can receive clause elements as VALUES arguments, not just literal + values + + .. change:: + :tags: + :tickets: + + support for calling multi-tokened functions, i.e. schema.mypkg.func() + + .. change:: + :tags: + :tickets: + + added J. Ellis' SQLSoup module to extensions package + + .. change:: + :tags: + :tickets: + + added "polymorphic" examples illustrating methods to load multiple object types + from one mapper, the second of which uses the new populate_instance() method. + small improvements to mapper, UNION construct to help the examples along + + .. change:: + :tags: + :tickets: + + improvements/fixes to session.refresh()/session.expire() (which may have + been called "invalidate" earlier..) + + .. change:: + :tags: + :tickets: + + added session.expunge() which totally removes an object from the current + session + + .. change:: + :tags: + :tickets: + + added *args, **kwargs pass-thru to engine.transaction(func) allowing easier + creation of transactionalizing decorator functions + + .. change:: + :tags: + :tickets: + + added iterator interface to ResultProxy: "for row in result:..." + + .. change:: + :tags: + :tickets: + + added assertion to tx = session.begin(); tx.rollback(); tx.begin(), i.e. cant + use it after a rollback() + + .. change:: + :tags: + :tickets: + + added date conversion on bind parameter fix to SQLite enabling dates to + work with pysqlite1 + + .. change:: + :tags: + :tickets: 116 + + improvements to subqueries to more intelligently construct their FROM + clauses + + .. change:: + :tags: + :tickets: + + added PickleType to types. + + .. change:: + :tags: + :tickets: + + fixed two bugs with column labels with regards to bind parameters: bind param + keynames they are now generated from a column "label" in all relevant cases to + take advantage of excess-name-length rules, and checks for a peculiar collision + against a column named the same as "tablename_colname" added + + .. change:: + :tags: + :tickets: + + major overhaul to unit of work documentation, other documentation sections. + + .. change:: + :tags: + :tickets: + + fixed attributes bug where if an object is committed, its lazy-loaded list got + blown away if it hadnt been loaded + + .. change:: + :tags: + :tickets: + + added unique_connection() method to engine, connection pool to return a + connection that is not part of the thread-local context or any current + transaction + + .. change:: + :tags: + :tickets: + + added invalidate() function to pooled connection. will remove the connection + from the pool. still need work for engines to auto-reconnect to a stale DB + though. + + .. change:: + :tags: + :tickets: + + added distinct() function to column elements so you can do + func.count(mycol.distinct()) + + .. change:: + :tags: + :tickets: + + added "always_refresh" flag to Mapper, creates a mapper that will always + refresh the attributes of objects it gets/selects from the DB, overwriting any + changes made. + +.. changelog:: + :version: 0.1.4 + :released: Mon Mar 13 2006 + + .. change:: + :tags: + :tickets: + + create_engine() now uses genericized parameters; host/hostname, + db/dbname/database, password/passwd, etc. for all engine connections. makes + engine URIs much more "universal" + + .. change:: + :tags: + :tickets: + + added support for SELECT statements embedded into a column clause, using the + flag "scalar=True" + + .. change:: + :tags: + :tickets: + + another overhaul to EagerLoading when used in conjunction with mappers that + inherit; improvements to eager loads figuring out their aliased queries + correctly, also relations set up against a mapper with inherited mappers will + create joins against the table that is specific to the mapper itself (i.e. and + not any tables that are inherited/are further down the inheritance chain), + this can be overridden by using custom primary/secondary joins. + + .. change:: + :tags: + :tickets: + + added J.Ellis patch to mapper.py so that selectone() throws an exception + if query returns more than one object row, selectfirst() to not throw the + exception. also adds selectfirst_by (synonymous with get_by) and selectone_by + + .. change:: + :tags: + :tickets: + + added onupdate parameter to Column, will exec SQL/python upon an update + statement.Also adds "for_update=True" to all DefaultGenerator subclasses + + .. change:: + :tags: + :tickets: + + added support for Oracle table reflection contributed by Andrija Zaric; + still some bugs to work out regarding composite primary keys/dictionary selection + + .. change:: + :tags: + :tickets: + + checked in an initial Firebird module, awaiting testing. + + .. change:: + :tags: + :tickets: + + added sql.ClauseParameters dictionary object as the result for + compiled.get_params(), does late-typeprocessing of bind parameters so + that the original values are easier to access + + .. change:: + :tags: + :tickets: + + more docs for indexes, column defaults, connection pooling, engine construction + + .. change:: + :tags: + :tickets: + + overhaul to the construction of the types system. uses a simpler inheritance + pattern so that any of the generic types can be easily subclassed, with no need + for TypeDecorator. + + .. change:: + :tags: + :tickets: + + added "convert_unicode=False" parameter to SQLEngine, will cause all String + types to perform unicode encoding/decoding (makes Strings act like Unicodes) + + .. change:: + :tags: + :tickets: + + added 'encoding="utf8"' parameter to engine. the given encoding will be + used for all encode/decode calls within Unicode types as well as Strings + when convert_unicode=True. + + .. change:: + :tags: + :tickets: + + improved support for mapping against UNIONs, added polymorph.py example + to illustrate multi-class mapping against a UNION + + .. change:: + :tags: + :tickets: + + fix to SQLite LIMIT/OFFSET syntax + + .. change:: + :tags: + :tickets: + + fix to Oracle LIMIT syntax + + .. change:: + :tags: + :tickets: + + added backref() function, allows backreferences to have keyword arguments + that will be passed to the backref. + + .. change:: + :tags: + :tickets: + + Sequences and ColumnDefault objects can do execute()/scalar() standalone + + .. change:: + :tags: + :tickets: + + SQL functions (i.e. func.foo()) can do execute()/scalar() standalone + + .. change:: + :tags: + :tickets: + + fix to SQL functions so that the ANSI-standard functions, i.e. current_timestamp + etc., do not specify parenthesis. all other functions do. + + .. change:: + :tags: + :tickets: + + added settattr_clean and append_clean to SmartProperty, which set + attributes without triggering a "dirty" event or any history. used as: + myclass.prop1.setattr_clean(myobject, 'hi') + + .. change:: + :tags: + :tickets: + + improved support to column defaults when used by mappers; mappers will pull + pre-executed defaults from statement's executed bind parameters + (pre-conversion) to populate them into a saved object's attributes; if any + PassiveDefaults have fired off, will instead post-fetch the row from the DB to + populate the object. + + .. change:: + :tags: + :tickets: + + added 'get_session().invalidate(*obj)' method to objectstore, instances will + refresh() themselves upon the next attribute access. + + .. change:: + :tags: + :tickets: + + improvements to SQL func calls including an "engine" keyword argument so + they can be execute()d or scalar()ed standalone, also added func accessor to + SQLEngine + + .. change:: + :tags: + :tickets: + + fix to MySQL4 custom table engines, i.e. TYPE instead of ENGINE + + .. change:: + :tags: + :tickets: + + slightly enhanced logging, includes timestamps and a somewhat configurable + formatting system, in lieu of a full-blown logging system + + .. change:: + :tags: + :tickets: + + improvements to the ActiveMapper class from the TG gang, including + many-to-many relationships + + .. change:: + :tags: + :tickets: + + added Double and TinyInt support to mysql + +.. changelog:: + :version: 0.1.3 + :released: Thu Mar 02 2006 + + .. change:: + :tags: + :tickets: + + completed "post_update" feature, will add a second update statement before + inserts and after deletes in order to reconcile a relationship without any + dependencies being created; used when persisting two rows that are dependent + on each other + + .. change:: + :tags: + :tickets: + + completed mapper.using(session) function, localized per-object Session + functionality; objects can be declared and manipulated as local to any + user-defined Session + + .. change:: + :tags: + :tickets: + + fix to Oracle "row_number over" clause with multiple tables + + .. change:: + :tags: + :tickets: + + mapper.get() was not selecting multiple-keyed objects if the mapper's table was a join, + such as in an inheritance relationship, this is fixed. + + .. change:: + :tags: + :tickets: + + overhaul to sql/schema packages so that the sql package can run all on its own, + producing selects, inserts, etc. without any engine dependencies. builds upon + new TableClause/ColumnClause lexical objects. Schema's Table/Column objects + are the "physical" subclasses of them. simplifies schema/sql relationship, + extensions (like proxyengine), and speeds overall performance by a large margin. + removes the entire getattr() behavior that plagued 0.1.1. + + .. change:: + :tags: + :tickets: + + refactoring of how the mapper "synchronizes" data between two objects into a + separate module, works better with properties attached to a mapper that has an + additional inheritance relationship to one of the related tables, also the same + methodology used to synchronize parent/child objects now used by mapper to + synchronize between inherited and inheriting mappers. + + .. change:: + :tags: + :tickets: + + made objectstore "check for out-of-identitymap" more aggressive, will perform the + check when object attributes are modified or the object is deleted + + .. change:: + :tags: + :tickets: + + Index object fully implemented, can be constructed standalone, or via + "index" and "unique" arguments on Columns. + + .. change:: + :tags: + :tickets: + + added "convert_unicode" flag to SQLEngine, will treat all String/CHAR types + as Unicode types, with raw-byte/utf-8 translation on the bind parameter and + result set side. + + .. change:: + :tags: + :tickets: + + postgres maintains a list of ANSI functions that must have no parenthesis so + function calls with no arguments work consistently + + .. change:: + :tags: + :tickets: + + tables can be created with no engine specified. this will default their engine + to a module-scoped "default engine" which is a ProxyEngine. this engine can + be connected via the function "global_connect". + + .. change:: + :tags: + :tickets: + + added "refresh(*obj)" method to objectstore / Session to reload the attributes of + any set of objects from the database unconditionally + +.. changelog:: + :version: 0.1.2 + :released: Fri Feb 24 2006 + + .. change:: + :tags: + :tickets: + + fixed a recursive call in schema that was somehow running 994 times then returning + normally. broke nothing, slowed down everything. thanks to jpellerin for finding this. + +.. changelog:: + :version: 0.1.1 + :released: Thu Feb 23 2006 + + .. change:: + :tags: + :tickets: + + small fix to Function class so that expressions with a func.foo() use the type of the + Function object (i.e. the left side) as the type of the boolean expression, not the + other side which is more of a moving target (changeset 1020). + + .. change:: + :tags: + :tickets: + + creating self-referring mappers with backrefs slightly easier (but still not that easy - + changeset 1019) + + .. change:: + :tags: + :tickets: + + fixes to one-to-one mappings (changeset 1015) + + .. change:: + :tags: + :tickets: + + psycopg1 date/time issue with None fixed (changeset 1005) + + .. change:: + :tags: + :tickets: + + two issues related to postgres, which doesnt want to give you the "lastrowid" + since oids are deprecated: + * postgres database-side defaults that are on primary key cols *do* execute + explicitly beforehand, even though thats not the idea of a PassiveDefault. this is + because sequences on columns get reflected as PassiveDefaults, but need to be explicitly + executed on a primary key col so we know what we just inserted. + * if you did add a row that has a bunch of database-side defaults on it, + and the PassiveDefault thing was working the old way, i.e. they just execute on + the DB side, the "cant get the row back without an OID" exception that occurred + also will not happen unless someone (usually the ORM) explicitly asks for it. + + .. change:: + :tags: + :tickets: + + fixed a glitch with engine.execute_compiled where it was making a second + ResultProxy that just got thrown away. + + .. change:: + :tags: + :tickets: + + began to implement newer logic in object properities. you can now say + myclass.attr.property, which will give you the PropertyLoader corresponding to that + attribute, i.e. myclass.mapper.props['attr'] + + .. change:: + :tags: + :tickets: + + eager loading has been internally overhauled to use aliases at all times. more + complicated chains of eager loads can now be created without any need for explicit + "use aliases"-type instructions. EagerLoader code is also much simpler now. + + .. change:: + :tags: + :tickets: + + a new somewhat experimental flag "use_update" added to relations, indicates that + this relationship should be handled by a second UPDATE statement, either after a + primary INSERT or before a primary DELETE. handles circular row dependencies. + + .. change:: + :tags: + :tickets: + + added exceptions module, all raised exceptions (except for some + KeyError/AttributeError exceptions) descend from these classes. + + .. change:: + :tags: + :tickets: + + fix to date types with MySQL, returned timedelta converted to datetime.time + + .. change:: + :tags: + :tickets: + + two-phase objectstore.commit operations (i.e. begin/commit) now return a + transactional object (SessionTrans), to more clearly indicate transaction boundaries. + + .. change:: + :tags: + :tickets: + + Index object with create/drop support added to schema + + .. change:: + :tags: + :tickets: + + fix to postgres, where it will explicitly pre-execute a PassiveDefault on a table + if it is a primary key column, pursuant to the ongoing "we cant get inserted rows + back from postgres" issue + + .. change:: + :tags: + :tickets: + + change to information_schema query that gets back postgres table defs, now + uses explicit JOIN keyword, since one user had faster performance with 8.1 + + .. change:: + :tags: + :tickets: + + fix to engine.process_defaults so it works correctly with a table that has + different column name/column keys (changset 982) + + .. change:: + :tags: + :tickets: + + a column can only be attached to one table - this is now asserted + + .. change:: + :tags: + :tickets: + + postgres time types descend from Time type + + .. change:: + :tags: + :tickets: + + fix to alltests so that it runs types test (now named testtypes) + + .. change:: + :tags: + :tickets: + + fix to Join object so that it correctly exports its foreign keys (cs 973) + + .. change:: + :tags: + :tickets: + + creating relationships against mappers that use inheritance fixed (cs 973) diff --git a/doc/build/changelog/changelog_02.rst b/doc/build/changelog/changelog_02.rst new file mode 100644 index 0000000000..3053659a85 --- /dev/null +++ b/doc/build/changelog/changelog_02.rst @@ -0,0 +1,1187 @@ + +============== +0.2 Changelog +============== + + +.. changelog:: + :version: 0.2.8 + :released: Tue Sep 05 2006 + + .. change:: + :tags: + :tickets: + + cleanup on connection methods + documentation. custom DBAPI + arguments specified in query string, 'connect_args' argument + to 'create_engine', or custom creation function via 'creator' + function to 'create_engine'. + + .. change:: + :tags: + :tickets: 274 + + added "recycle" argument to Pool, is "pool_recycle" on create_engine, + defaults to 3600 seconds; connections after this age will be closed and + replaced with a new one, to handle db's that automatically close + stale connections + + .. change:: + :tags: + :tickets: 121 + + changed "invalidate" semantics with pooled connection; will + instruct the underlying connection record to reconnect the next + time its called. "invalidate" will also automatically be called + if any error is thrown in the underlying call to connection.cursor(). + this will hopefully allow the connection pool to reconnect to a + database that had been stopped and started without restarting + the connecting application + + .. change:: + :tags: + :tickets: + + eesh ! the tutorial doctest was broken for quite some time. + + .. change:: + :tags: + :tickets: + + add_property() method on mapper does a "compile all mappers" + step in case the given property references a non-compiled mapper + (as it did in the case of the tutorial !) + + .. change:: + :tags: + :tickets: 277 + + check for pg sequence already existing before create + + .. change:: + :tags: + :tickets: + + if a contextual session is established via MapperExtension.get_session + (as it is using the sessioncontext plugin, etc), a lazy load operation + will use that session by default if the parent object is not + persistent with a session already. + + .. change:: + :tags: + :tickets: + + lazy loads will not fire off for an object that does not have a + database identity (why? + see http://www.sqlalchemy.org/trac/wiki/WhyDontForeignKeysLoadData) + + .. change:: + :tags: + :tickets: + + unit-of-work does a better check for "orphaned" objects that are + part of a "delete-orphan" cascade, for certain conditions where the + parent isnt available to cascade from. + + .. change:: + :tags: + :tickets: + + mappers can tell if one of their objects is an "orphan" based + on interactions with the attribute package. this check is based + on a status flag maintained for each relationship + when objects are attached and detached from each other. + + .. change:: + :tags: + :tickets: + + it is now invalid to declare a self-referential relationship with + "delete-orphan" (as the abovementioned check would make them impossible + to save) + + .. change:: + :tags: + :tickets: + + improved the check for objects being part of a session when the + unit of work seeks to flush() them as part of a relationship.. + + .. change:: + :tags: + :tickets: 280 + + statement execution supports using the same BindParam + object more than once in an expression; simplified handling of positional + parameters. nice job by Bill Noon figuring out the basic idea. + + .. change:: + :tags: + :tickets: 60, 71 + + postgres reflection moved to use pg_schema tables, can be overridden + with use_information_schema=True argument to create_engine. + + .. change:: + :tags: + :tickets: 155 + + added case_sensitive argument to MetaData, Table, Column, determines + itself automatically based on if a parent schemaitem has a non-None + setting for the flag, or if not, then whether the identifier name is all lower + case or not. when set to True, quoting is applied to identifiers with mixed or + uppercase identifiers. quoting is also applied automatically in all cases to + identifiers that are known to be reserved words or contain other non-standard + characters. various database dialects can override all of this behavior, but + currently they are all using the default behavior. tested with postgres, mysql, + sqlite, oracle. needs more testing with firebird, ms-sql. part of the ongoing + work with + + .. change:: + :tags: + :tickets: + + unit tests updated to run without any pysqlite installed; pool + test uses a mock DBAPI + + .. change:: + :tags: + :tickets: 281 + + urls support escaped characters in passwords + + .. change:: + :tags: + :tickets: + + added limit/offset to UNION queries (though not yet in oracle) + + .. change:: + :tags: + :tickets: + + added "timezone=True" flag to DateTime and Time types. postgres + so far will convert this to "TIME[STAMP] (WITH|WITHOUT) TIME ZONE", + so that control over timezone presence is more controllable (psycopg2 + returns datetimes with tzinfo's if available, which can create confusion + against datetimes that dont). + + .. change:: + :tags: + :tickets: 287 + + fix to using query.count() with distinct, **kwargs with SelectResults + count() + + .. change:: + :tags: + :tickets: 289 + + deregister Table from MetaData when autoload fails; + + .. change:: + :tags: + :tickets: 293 + + import of py2.5s sqlite3 + + .. change:: + :tags: + :tickets: 296 + + unicode fix for startswith()/endswith() + +.. changelog:: + :version: 0.2.7 + :released: Sat Aug 12 2006 + + .. change:: + :tags: + :tickets: + + quoting facilities set up so that database-specific quoting can be + turned on for individual table, schema, and column identifiers when + used in all queries/creates/drops. Enabled via "quote=True" in + Table or Column, as well as "quote_schema=True" in Table. Thanks to + Aaron Spike for his excellent efforts. + + .. change:: + :tags: + :tickets: + + assignmapper was setting is_primary=True, causing all sorts of mayhem + by not raising an error when redundant mappers were set up, fixed + + .. change:: + :tags: + :tickets: + + added allow_null_pks option to Mapper, allows rows where some + primary key columns are null (i.e. when mapping to outer joins etc) + + .. change:: + :tags: + :tickets: + + modifcation to unitofwork to not maintain ordering within the + "new" list or within the UOWTask "objects" list; instead, new objects + are tagged with an ordering identifier as they are registered as new + with the session, and the INSERT statements are then sorted within the + mapper save_obj. the INSERT ordering has basically been pushed all + the way to the end of the flush cycle. that way the various sorts and + organizations occuring within UOWTask (particularly the circular task + sort) dont have to worry about maintaining order (which they werent anyway) + + .. change:: + :tags: + :tickets: + + fixed reflection of foreign keys to autoload the referenced table + if it was not loaded already + + .. change:: + :tags: + :tickets: 256 + + - pass URL query string arguments to connect() function + + .. change:: + :tags: + :tickets: 257 + + - oracle boolean type + + .. change:: + :tags: + :tickets: + + custom primary/secondary join conditions in a relation *will* be propagated + to backrefs by default. specifying a backref() will override this behavior. + + .. change:: + :tags: + :tickets: + + better check for ambiguous join conditions in sql.Join; propagates to a + better error message in PropertyLoader (i.e. relation()/backref()) for when + the join condition can't be reasonably determined. + + .. change:: + :tags: + :tickets: + + sqlite creates ForeignKeyConstraint objects properly upon table + reflection. + + .. change:: + :tags: + :tickets: 224 + + adjustments to pool stemming from changes made for. + overflow counter should only be decremented if the connection actually + succeeded. added a test script to attempt testing this. + + .. change:: + :tags: + :tickets: + + fixed mysql reflection of default values to be PassiveDefault + + .. change:: + :tags: + :tickets: 263, 264 + + added reflected 'tinyint', 'mediumint' type to MS-SQL. + + .. change:: + :tags: + :tickets: + + SingletonThreadPool has a size and does a cleanup pass, so that + only a given number of thread-local connections stay around (needed + for sqlite applications that dispose of threads en masse) + + .. change:: + :tags: + :tickets: 267, 265 + + fixed small pickle bug(s) with lazy loaders + + .. change:: + :tags: + :tickets: + + fixed possible error in mysql reflection where certain versions + return an array instead of string for SHOW CREATE TABLE call + + .. change:: + :tags: + :tickets: 1770 + + fix to lazy loads when mapping to joins + + .. change:: + :tags: + :tickets: + + all create()/drop() calls have a keyword argument of "connectable". + "engine" is deprecated. + + .. change:: + :tags: + :tickets: + + fixed ms-sql connect() to work with adodbapi + + .. change:: + :tags: + :tickets: + + added "nowait" flag to Select() + + .. change:: + :tags: + :tickets: 271 + + inheritance check uses issubclass() instead of direct __mro__ check + to make sure class A inherits from B, allowing mapper inheritance to more + flexibly correspond to class inheritance + + .. change:: + :tags: + :tickets: 252 + + SelectResults will use a subselect, when calling an aggregate (i.e. + max, min, etc.) on a SelectResults that has an ORDER BY clause + + .. change:: + :tags: + :tickets: 269 + + fixes to types so that database-specific types more easily used; + fixes to mysql text types to work with this methodology + + .. change:: + :tags: + :tickets: + + some fixes to sqlite date type organization + + .. change:: + :tags: + :tickets: 263 + + added MSTinyInteger to MS-SQL + +.. changelog:: + :version: 0.2.6 + :released: Thu Jul 20 2006 + + .. change:: + :tags: + :tickets: 76 + + big overhaul to schema to allow truly composite primary and foreign + key constraints, via new ForeignKeyConstraint and PrimaryKeyConstraint + objects. + Existing methods of primary/foreign key creation have not been changed + but use these new objects behind the scenes. table creation + and reflection is now more table oriented rather than column oriented. + + .. change:: + :tags: + :tickets: + + overhaul to MapperExtension calling scheme, wasnt working very well + previously + + .. change:: + :tags: + :tickets: + + tweaks to ActiveMapper, supports self-referential relationships + + .. change:: + :tags: + :tickets: + + slight rearrangement to objectstore (in activemapper/threadlocal) + so that the SessionContext is referenced by '.context' instead + of subclassed directly. + + .. change:: + :tags: + :tickets: + + activemapper will use threadlocal's objectstore if the mod is + activated when activemapper is imported + + .. change:: + :tags: + :tickets: + + small fix to URL regexp to allow filenames with '@' in them + + .. change:: + :tags: + :tickets: + + fixes to Session expunge/update/etc...needs more cleanup. + + .. change:: + :tags: + :tickets: + + select_table mappers *still* werent always compiling + + .. change:: + :tags: + :tickets: + + fixed up Boolean datatype + + .. change:: + :tags: + :tickets: + + added count()/count_by() to list of methods proxied by assignmapper; + this also adds them to activemapper + + .. change:: + :tags: + :tickets: + + connection exceptions wrapped in DBAPIError + + .. change:: + :tags: + :tickets: + + ActiveMapper now supports autoloading column definitions from the + database if you supply a __autoload__ = True attribute in your + mapping inner-class. Currently this does not support reflecting + any relationships. + + .. change:: + :tags: + :tickets: + + deferred column load could screw up the connection status in + a flush() under some circumstances, this was fixed + + .. change:: + :tags: + :tickets: + + expunge() was not working with cascade, fixed. + + .. change:: + :tags: + :tickets: + + potential endless loop in cascading operations fixed. + + .. change:: + :tags: + :tickets: + + added "synonym()" function, applied to properties to have a + propname the same as another, for the purposes of overriding props + and allowing the original propname to be accessible in select_by(). + + .. change:: + :tags: + :tickets: + + fix to typing in clause construction which specifically helps + type issues with polymorphic_union (CAST/ColumnClause propagates + its type to proxy columns) + + .. change:: + :tags: + :tickets: + + mapper compilation work ongoing, someday it'll work....moved + around the initialization of MapperProperty objects to be after + all mappers are created to better handle circular compilations. + do_init() method is called on all properties now which are more + aware of their "inherited" status if so. + + .. change:: + :tags: + :tickets: + + eager loads explicitly disallowed on self-referential relationships, or + relationships to an inheriting mapper (which is also self-referential) + + .. change:: + :tags: + :tickets: 244 + + reduced bind param size in query._get to appease the picky oracle + + .. change:: + :tags: + :tickets: 234 + + added 'checkfirst' argument to table.create()/table.drop(), as + well as table.exists() + + .. change:: + :tags: + :tickets: 245 + + some other ongoing fixes to inheritance + + .. change:: + :tags: + :tickets: + + attribute/backref/orphan/history-tracking tweaks as usual... + +.. changelog:: + :version: 0.2.5 + :released: Sat Jul 08 2006 + + .. change:: + :tags: + :tickets: + + fixed endless loop bug in select_by(), if the traversal hit + two mappers that referenced each other + + .. change:: + :tags: + :tickets: + + upgraded all unittests to insert './lib/' into sys.path, + working around new setuptools PYTHONPATH-killing behavior + + .. change:: + :tags: + :tickets: + + further fixes with attributes/dependencies/etc.... + + .. change:: + :tags: + :tickets: + + improved error handling for when DynamicMetaData is not connected + + .. change:: + :tags: + :tickets: + + MS-SQL support largely working (tested with pymssql) + + .. change:: + :tags: + :tickets: + + ordering of UPDATE and DELETE statements within groups is now + in order of primary key values, for more deterministic ordering + + .. change:: + :tags: + :tickets: + + after_insert/delete/update mapper extensions now called per object, + not per-object-per-table + + .. change:: + :tags: + :tickets: + + further fixes/refactorings to mapper compilation + +.. changelog:: + :version: 0.2.4 + :released: Tue Jun 27 2006 + + .. change:: + :tags: + :tickets: + + try/except when the mapper sets init.__name__ on a mapped class, + supports python 2.3 + + .. change:: + :tags: + :tickets: + + fixed bug where threadlocal engine would still autocommit + despite a transaction in progress + + .. change:: + :tags: + :tickets: + + lazy load and deferred load operations require the parent object + to be in a Session to do the operation; whereas before the operation + would just return a blank list or None, it now raises an exception. + + .. change:: + :tags: + :tickets: + + Session.update() is slightly more lenient if the session to which + the given object was formerly attached to was garbage collected; + otherwise still requires you explicitly remove the instance from + the previous Session. + + .. change:: + :tags: + :tickets: + + fixes to mapper compilation, checking for more error conditions + + .. change:: + :tags: + :tickets: + + small fix to eager loading combined with ordering/limit/offset + + .. change:: + :tags: + :tickets: 206 + + utterly remarkable: added a single space between 'CREATE TABLE' + and '(' since *thats how MySQL indicates a non- + reserved word tablename.....* + + .. change:: + :tags: + :tickets: + + more fixes to inheritance, related to many-to-many relations + properly saving + + .. change:: + :tags: + :tickets: + + fixed bug when specifying explicit module to mysql dialect + + .. change:: + :tags: + :tickets: + + when QueuePool times out it raises a TimeoutError instead of + erroneously making another connection + + .. change:: + :tags: + :tickets: + + Queue.Queue usage in pool has been replaced with a locally + modified version (works in py2.3/2.4!) that uses a threading.RLock + for a mutex. this is to fix a reported case where a ConnectionFairy's + __del__() method got called within the Queue's get() method, which + then returns its connection to the Queue via the the put() method, + causing a reentrant hang unless threading.RLock is used. + + .. change:: + :tags: + :tickets: + + postgres will not place SERIAL keyword on a primary key column + if it has a foreign key constraint + + .. change:: + :tags: + :tickets: 221 + + cursor() method on ConnectionFairy allows db-specific extension + arguments to be propagated + + .. change:: + :tags: + :tickets: 225 + + lazy load bind params properly propagate column type + + .. change:: + :tags: + :tickets: + + new MySQL types: MSEnum, MSTinyText, MSMediumText, MSLongText, etc. + more support for MS-specific length/precision params in numeric types + patch courtesy Mike Bernson + + .. change:: + :tags: + :tickets: 224 + + some fixes to connection pool invalidate() + +.. changelog:: + :version: 0.2.3 + :released: Sat Jun 17 2006 + + .. change:: + :tags: + :tickets: + + overhaul to mapper compilation to be deferred. this allows mappers + to be constructed in any order, and their relationships to each + other are compiled when the mappers are first used. + + .. change:: + :tags: + :tickets: + + fixed a pretty big speed bottleneck in cascading behavior particularly + when backrefs were in use + + .. change:: + :tags: + :tickets: + + the attribute instrumentation module has been completely rewritten; its + now a large degree simpler and clearer, slightly faster. the "history" + of an attribute is no longer micromanaged with each change and is + instead part of a "CommittedState" object created when the + instance is first loaded. HistoryArraySet is gone, the behavior of + list attributes is now more open ended (i.e. theyre not sets anymore). + + .. change:: + :tags: + :tickets: + + py2.4 "set" construct used internally, falls back to sets.Set when + "set" not available/ordering is needed. + + .. change:: + :tags: + :tickets: + + fix to transaction control, so that repeated rollback() calls + dont fail (was failing pretty badly when flush() would raise + an exception in a larger try/except transaction block) + + .. change:: + :tags: + :tickets: 151 + + "foreignkey" argument to relation() can also be a list. fixed + auto-foreignkey detection + + .. change:: + :tags: + :tickets: + + fixed bug where tables with schema names werent getting indexed in + the MetaData object properly + + .. change:: + :tags: + :tickets: 207 + + fixed bug where Column with redefined "key" property wasnt getting + type conversion happening in the ResultProxy + + .. change:: + :tags: + :tickets: + + fixed 'port' attribute of URL to be an integer if present + + .. change:: + :tags: + :tickets: + + fixed old bug where if a many-to-many table mapped as "secondary" + had extra columns, delete operations didnt work + + .. change:: + :tags: + :tickets: + + bugfixes for mapping against UNION queries + + .. change:: + :tags: + :tickets: + + fixed incorrect exception class thrown when no DB driver present + + .. change:: + :tags: + :tickets: 138 + + added NonExistentTable exception thrown when reflecting a table + that doesnt exist + + .. change:: + :tags: + :tickets: + + small fix to ActiveMapper regarding one-to-one backrefs, other + refactorings + + .. change:: + :tags: + :tickets: + + overridden constructor in mapped classes gets __name__ and + __doc__ from the original class + + .. change:: + :tags: + :tickets: 200 + + fixed small bug in selectresult.py regarding mapper extension + + .. change:: + :tags: + :tickets: + + small tweak to cascade_mappers, not very strongly supported + function at the moment + + .. change:: + :tags: + :tickets: 202 + + some fixes to between(), column.between() to propagate typing + information better + + .. change:: + :tags: + :tickets: 203 + + if an object fails to be constructed, is not added to the + session + + .. change:: + :tags: + :tickets: + + CAST function has been made into its own clause object with + its own compilation function in ansicompiler; allows MySQL + to silently ignore most CAST calls since MySQL + seems to only support the standard CAST syntax with Date types. + MySQL-compatible CAST support for strings, ints, etc. a TODO + +.. changelog:: + :version: 0.2.2 + :released: Mon Jun 05 2006 + + .. change:: + :tags: + :tickets: 190 + + big improvements to polymorphic inheritance behavior, enabling it + to work with adjacency list table structures + + .. change:: + :tags: + :tickets: + + major fixes and refactorings to inheritance relationships overall, + more unit tests + + .. change:: + :tags: + :tickets: + + fixed "echo_pool" flag on create_engine() + + .. change:: + :tags: + :tickets: + + fix to docs, removed incorrect info that close() is unsafe to use + with threadlocal strategy (its totally safe !) + + .. change:: + :tags: + :tickets: 188 + + create_engine() can take URLs as string or unicode + + .. change:: + :tags: + :tickets: + + firebird support partially completed; + thanks to James Ralston and Brad Clements for their efforts. + + .. change:: + :tags: + :tickets: + + Oracle url translation was broken, fixed, will feed host/port/sid + into cx_oracle makedsn() if 'database' field is present, else uses + straight TNS name from the 'host' field + + .. change:: + :tags: + :tickets: + + fix to using unicode criterion for query.get()/query.load() + + .. change:: + :tags: + :tickets: + + count() function on selectables now uses table primary key or + first column instead of "1" for criterion, also uses label "rowcount" + instead of "count". + + .. change:: + :tags: + :tickets: + + got rudimental "mapping to multiple tables" functionality cleaned up, + more correctly documented + + .. change:: + :tags: + :tickets: + + restored global_connect() function, attaches to a DynamicMetaData + instance called "default_metadata". leaving MetaData arg to Table + out will use the default metadata. + + .. change:: + :tags: + :tickets: + + fixes to session cascade behavior, entity_name propigation + + .. change:: + :tags: + :tickets: + + reorganized unittests into subdirectories + + .. change:: + :tags: + :tickets: + + more fixes to threadlocal connection nesting patterns + +.. changelog:: + :version: 0.2.1 + :released: Mon May 29 2006 + + .. change:: + :tags: + :tickets: + + "pool" argument to create_engine() properly propagates + + .. change:: + :tags: + :tickets: + + fixes to URL, raises exception if not parsed, does not pass blank + fields along to the DB connect string (a string such as + user:host@/db was breaking on postgres) + + .. change:: + :tags: + :tickets: + + small fixes to Mapper when it inserts and tries to get + new primary key values back + + .. change:: + :tags: + :tickets: + + rewrote half of TLEngine, the ComposedSQLEngine used with + 'strategy="threadlocal"'. it now properly implements engine.begin()/ + engine.commit(), which nest fully with connection.begin()/trans.commit(). + added about six unittests. + + .. change:: + :tags: + :tickets: + + major "duh" in pool.Pool, forgot to put back the WeakValueDictionary. + unittest which was supposed to check for this was also silently missing + it. fixed unittest to ensure that ConnectionFairy properly falls out + of scope. + + .. change:: + :tags: + :tickets: + + placeholder dispose() method added to SingletonThreadPool, doesnt + do anything yet + + .. change:: + :tags: + :tickets: + + rollback() is automatically called when an exception is raised, + but only if theres no transaction in process (i.e. works more like + autocommit). + + .. change:: + :tags: + :tickets: + + fixed exception raise in sqlite if no sqlite module present + + .. change:: + :tags: + :tickets: + + added extra example detail for association object doc + + .. change:: + :tags: + :tickets: + + Connection adds checks for already being closed + +.. changelog:: + :version: 0.2.0 + :released: Sat May 27 2006 + + .. change:: + :tags: + :tickets: + + overhaul to Engine system so that what was formerly the SQLEngine + is now a ComposedSQLEngine which consists of a variety of components, + including a Dialect, ConnectionProvider, etc. This impacted all the + db modules as well as Session and Mapper. + + .. change:: + :tags: + :tickets: + + create_engine now takes only RFC-1738-style strings: + driver://user:password@host:port/database + + .. change:: + :tags: + :tickets: 152 + + total rewrite of connection-scoping methodology, Connection objects + can now execute clause elements directly, added explicit "close" as + well as support throughout Engine/ORM to handle closing properly, + no longer relying upon __del__ internally to return connections + to the pool. + + .. change:: + :tags: + :tickets: + + overhaul to Session interface and scoping. uses hibernate-style + methods, including query(class), save(), save_or_update(), etc. + no threadlocal scope is installed by default. Provides a binding + interface to specific Engines and/or Connections so that underlying + Schema objects do not need to be bound to an Engine. Added a basic + SessionTransaction object that can simplistically aggregate transactions + across multiple engines. + + .. change:: + :tags: + :tickets: + + overhaul to mapper's dependency and "cascade" behavior; dependency logic + factored out of properties.py into a separate module "dependency.py". + "cascade" behavior is now explicitly controllable, proper implementation + of "delete", "delete-orphan", etc. dependency system can now determine at + flush time if a child object has a parent or not so that it makes better + decisions on how that child should be updated in the DB with regards to deletes. + + .. change:: + :tags: + :tickets: + + overhaul to Schema to build upon MetaData object instead of an Engine. + Entire SQL/Schema system can be used with no Engines whatsoever, executed + solely by an explicit Connection object. the "bound" methodlogy exists via the + BoundMetaData for schema objects. ProxyEngine is generally not needed + anymore and is replaced by DynamicMetaData. + + .. change:: + :tags: + :tickets: 167 + + true polymorphic behavior implemented, fixes + + .. change:: + :tags: + :tickets: 147 + + "oid" system has been totally moved into compile-time behavior; + if they are used in an order_by where they are not available, the order_by + doesnt get compiled, fixes + + .. change:: + :tags: + :tickets: + + overhaul to packaging; "mapping" is now "orm", "objectstore" is now + "session", the old "objectstore" namespace gets loaded in via the + "threadlocal" mod if used + + .. change:: + :tags: + :tickets: + + mods now called in via "import ". extensions favored over + mods as mods are globally-monkeypatching + + .. change:: + :tags: + :tickets: 154 + + fix to add_property so that it propagates properties to inheriting + mappers + + .. change:: + :tags: + :tickets: + + backrefs create themselves against primary mapper of its originating + property, priamry/secondary join arguments can be specified to override. + helps their usage with polymorphic mappers + + .. change:: + :tags: + :tickets: 31 + + "table exists" function has been implemented + + .. change:: + :tags: + :tickets: 98 + + "create_all/drop_all" added to MetaData object + + .. change:: + :tags: + :tickets: + + improvements and fixes to topological sort algorithm, as well as more + unit tests + + .. change:: + :tags: + :tickets: + + tutorial page added to docs which also can be run with a custom doctest + runner to ensure its properly working. docs generally overhauled to + deal with new code patterns + + .. change:: + :tags: + :tickets: + + many more fixes, refactorings. + + .. change:: + :tags: + :tickets: + + migration guide is available on the Wiki at + http://www.sqlalchemy.org/trac/wiki/02Migration diff --git a/doc/build/changelog/changelog_03.rst b/doc/build/changelog/changelog_03.rst new file mode 100644 index 0000000000..c1944c705b --- /dev/null +++ b/doc/build/changelog/changelog_03.rst @@ -0,0 +1,2928 @@ + +============== +0.3 Changelog +============== + + +.. changelog:: + :version: 0.3.11 + :released: Sun Oct 14 2007 + + .. change:: + :tags: sql + :tickets: + + tweak DISTINCT precedence for clauses like + `func.count(t.c.col.distinct())` + + .. change:: + :tags: sql + :tickets: 719 + + Fixed detection of internal '$' characters in :bind$params + + .. change:: + :tags: sql + :tickets: 768 + + dont assume join criterion consists only of column objects + + .. change:: + :tags: sql + :tickets: 764 + + adjusted operator precedence of NOT to match '==' and others, so that + ~(x==y) produces NOT (x=y), which is compatible with MySQL < 5.0 + (doesn't like "NOT x=y") + + .. change:: + :tags: orm + :tickets: 687 + + added a check for joining from A->B using join(), along two + different m2m tables. this raises an error in 0.3 but is + possible in 0.4 when aliases are used. + + .. change:: + :tags: orm + :tickets: + + fixed small exception throw bug in Session.merge() + + .. change:: + :tags: orm + :tickets: + + fixed bug where mapper, being linked to a join where one table had + no PK columns, would not detect that the joined table had no PK. + + .. change:: + :tags: orm + :tickets: 769 + + fixed bugs in determining proper sync clauses from custom inherit + conditions + + .. change:: + :tags: orm + :tickets: 813 + + backref remove object operation doesn't fail if the other-side + collection doesn't contain the item, supports noload collections + + .. change:: + :tags: engine + :tickets: + + fixed another occasional race condition which could occur + when using pool with threadlocal setting + + .. change:: + :tags: mysql + :tickets: + + fixed specification of YEAR columns when generating schema + + .. change:: + :tags: mssql + :tickets: 679 + + added support for TIME columns (simulated using DATETIME) + + .. change:: + :tags: mssql + :tickets: 721 + + added support for BIGINT, MONEY, SMALLMONEY, UNIQUEIDENTIFIER and + SQL_VARIANT + + .. change:: + :tags: mssql + :tickets: 684 + + index names are now quoted when dropping from reflected tables + + .. change:: + :tags: mssql + :tickets: + + can now specify a DSN for PyODBC, using a URI like mssql:///?dsn=bob + + .. change:: + :tags: postgres + :tickets: + + when reflecting tables from alternate schemas, the "default" placed upon + the primary key, i.e. usually a sequence name, has the "schema" name + unconditionally quoted, so that schema names which need quoting are fine. + its slightly unnecessary for schema names which don't need quoting + but not harmful. + + .. change:: + :tags: sqlite + :tickets: + + passthrough for stringified dates + + .. change:: + :tags: firebird + :tickets: + + supports_sane_rowcount() set to False due to ticket #370 (right way). + + .. change:: + :tags: firebird + :tickets: + + fixed reflection of Column's nullable property. + + .. change:: + :tags: oracle + :tickets: 622, 751 + + removed LONG_STRING, LONG_BINARY from "binary" types, so type objects + don't try to read their values as LOB. + +.. changelog:: + :version: 0.3.10 + :released: Fri Jul 20 2007 + + .. change:: + :tags: general + :tickets: + + a new mutex that was added in 0.3.9 causes the pool_timeout + feature to fail during a race condition; threads would + raise TimeoutError immediately with no delay if many threads + push the pool into overflow at the same time. this issue has been + fixed. + + .. change:: + :tags: sql + :tickets: + + got connection-bound metadata to work with implicit execution + + .. change:: + :tags: sql + :tickets: 667 + + foreign key specs can have any chararcter in their identifiers + + .. change:: + :tags: sql + :tickets: 664 + + added commutativity-awareness to binary clause comparisons to + each other, improves ORM lazy load optimization + + .. change:: + :tags: orm + :tickets: + + cleanup to connection-bound sessions, SessionTransaction + + .. change:: + :tags: postgres + :tickets: 571 + + fixed max identifier length (63) + +.. changelog:: + :version: 0.3.9 + :released: Sun Jul 15 2007 + + .. change:: + :tags: general + :tickets: 607 + + better error message for NoSuchColumnError + + .. change:: + :tags: general + :tickets: 428 + + finally figured out how to get setuptools version in, available + as sqlalchemy.__version__ + + .. change:: + :tags: general + :tickets: + + the various "engine" arguments, such as "engine", "connectable", + "engine_or_url", "bind_to", etc. are all present, but deprecated. + they all get replaced by the single term "bind". you also + set the "bind" of MetaData using + metadata.bind = + + .. change:: + :tags: ext + :tickets: + + iteration over dict association proxies is now dict-like, not + InstrumentedList-like (e.g. over keys instead of values) + + .. change:: + :tags: ext + :tickets: 597 + + association proxies no longer bind tightly to source collections, and are constructed with a thunk instead + + .. change:: + :tags: ext + :tickets: + + added selectone_by() to assignmapper + + .. change:: + :tags: orm + :tickets: + + forwards-compatibility with 0.4: added one(), first(), and + all() to Query. almost all Query functionality from 0.4 is + present in 0.3.9 for forwards-compat purposes. + + .. change:: + :tags: orm + :tickets: + + reset_joinpoint() really really works this time, promise ! lets + you re-join from the root: + query.join(['a', 'b']).filter().reset_joinpoint().\ + join(['a', 'c']).filter().all() + in 0.4 all join() calls start from the "root" + + .. change:: + :tags: orm + :tickets: 613 + + added synchronization to the mapper() construction step, to avoid + thread collisions when pre-existing mappers are compiling in a + different thread + + .. change:: + :tags: orm + :tickets: + + a warning is issued by Mapper when two primary key columns of the + same name are munged into a single attribute. this happens frequently + when mapping to joins (or inheritance). + + .. change:: + :tags: orm + :tickets: 598 + + synonym() properties are fully supported by all Query joining/ + with_parent operations + + .. change:: + :tags: orm + :tickets: + + fixed very stupid bug when deleting items with many-to-many + uselist=False relations + + .. change:: + :tags: orm + :tickets: + + remember all that stuff about polymorphic_union ? for + joined table inheritance ? Funny thing... + You sort of don't need it for joined table inheritance, you + can just string all the tables together via outerjoin(). + The UNION still applies if concrete tables are involved, + though (since nothing to join them on). + + .. change:: + :tags: orm + :tickets: + + small fix to eager loading to better work with eager loads + to polymorphic mappers that are using a straight "outerjoin" + clause + + .. change:: + :tags: sql + :tickets: + + ForeignKey to a table in a schema thats not the default schema + requires the schema to be explicit; i.e. ForeignKey('alt_schema.users.id') + + .. change:: + :tags: sql + :tickets: + + MetaData can now be constructed with an engine or url as the first + argument, just like BoundMetaData + + .. change:: + :tags: sql + :tickets: + + BoundMetaData is now deprecated, and MetaData is a direct substitute. + + .. change:: + :tags: sql + :tickets: + + DynamicMetaData has been renamed to ThreadLocalMetaData. the + DynamicMetaData name is deprecated and is an alias for ThreadLocalMetaData + or a regular MetaData if threadlocal=False + + .. change:: + :tags: sql + :tickets: + + composite primary key is represented as a non-keyed set to allow for + composite keys consisting of cols with the same name; occurs within a + Join. helps inheritance scenarios formulate correct PK. + + .. change:: + :tags: sql + :tickets: 185 + + improved ability to get the "correct" and most minimal set of primary key + columns from a join, equating foreign keys and otherwise equated columns. + this is also mostly to help inheritance scenarios formulate the best + choice of primary key columns. + + .. change:: + :tags: sql + :tickets: + + added 'bind' argument to Sequence.create()/drop(), ColumnDefault.execute() + + .. change:: + :tags: sql + :tickets: 650 + + columns can be overridden in a reflected table with a "key" + attribute different than the column's name, including for primary key + columns + + .. change:: + :tags: sql + :tickets: 657 + + fixed "ambiguous column" result detection, when dupe col names exist + in a result + + .. change:: + :tags: sql + :tickets: + + some enhancements to "column targeting", the ability to match a column + to a "corresponding" column in another selectable. this affects mostly + ORM ability to map to complex joins + + .. change:: + :tags: sql + :tickets: 619 + + MetaData and all SchemaItems are safe to use with pickle. slow + table reflections can be dumped into a pickled file to be reused later. + Just reconnect the engine to the metadata after unpickling. + + .. change:: + :tags: sql + :tickets: + + added a mutex to QueuePool's "overflow" calculation to prevent a race + condition that can bypass max_overflow + + .. change:: + :tags: sql + :tickets: 623 + + fixed grouping of compound selects to give correct results. will break + on sqlite in some cases, but those cases were producing incorrect + results anyway, sqlite doesn't support grouped compound selects + + .. change:: + :tags: sql + :tickets: 620 + + fixed precedence of operators so that parenthesis are correctly applied + + .. change:: + :tags: sql + :tickets: 545 + + calling .in_() (i.e. with no arguments) will return + "CASE WHEN ( IS NULL) THEN NULL ELSE 0 END = 1)", so that + NULL or False is returned in all cases, rather than throwing an error + + .. change:: + :tags: sql + :tickets: + + fixed "where"/"from" criterion of select() to accept a unicode string + in addition to regular string - both convert to text() + + .. change:: + :tags: sql + :tickets: 558 + + added standalone distinct() function in addition to column.distinct() + + .. change:: + :tags: sql + :tickets: + + result.last_inserted_ids() should return a list that is identically + sized to the primary key constraint of the table. values that were + "passively" created and not available via cursor.lastrowid will be None. + + .. change:: + :tags: sql + :tickets: 589 + + long-identifier detection fixed to use > rather than >= for + max ident length + + .. change:: + :tags: sql + :tickets: 593 + + fixed bug where selectable.corresponding_column(selectable.c.col) + would not return selectable.c.col, if the selectable is a join + of a table and another join involving the same table. messed + up ORM decision making + + .. change:: + :tags: sql + :tickets: 595 + + added Interval type to types.py + + .. change:: + :tags: mysql + :tickets: 625 + + fixed catching of some errors that imply a dropped connection + + .. change:: + :tags: mysql + :tickets: 624 + + fixed escaping of the modulo operator + + .. change:: + :tags: mysql + :tickets: 590 + + added 'fields' to reserved words + + .. change:: + :tags: mysql + :tickets: + + various reflection enhancement/fixes + + .. change:: + :tags: oracle + :tickets: 604 + + datetime fixes: got subsecond TIMESTAMP to work, + added OracleDate which supports types.Date with only year/month/day + + .. change:: + :tags: oracle + :tickets: + + added dialect flag "auto_convert_lobs", defaults to True; will cause any + LOB objects detected in a result set to be forced into OracleBinary + so that the LOB is read() automatically, if no typemap was present + (i.e., if a textual execute() was issued). + + .. change:: + :tags: oracle + :tickets: 624 + + mod operator '%' produces MOD + + .. change:: + :tags: oracle + :tickets: 542 + + converts cx_oracle datetime objects to Python datetime.datetime when + Python 2.3 used + + .. change:: + :tags: oracle + :tickets: + + fixed unicode conversion in Oracle TEXT type + + .. change:: + :tags: postgres + :tickets: 624 + + fixed escaping of the modulo operator + + .. change:: + :tags: postgres + :tickets: 570 + + added support for reflection of domains + + .. change:: + :tags: postgres + :tickets: + + types which are missing during reflection resolve to Null type + instead of raising an error + + .. change:: + :tags: postgres + :tickets: + + the fix in "schema" above fixes reflection of foreign keys from an + alt-schema table to a public schema table + + .. change:: + :tags: sqlite + :tickets: + + rearranged dialect initialization so it has time to warn about pysqlite1 + being too old. + + .. change:: + :tags: sqlite + :tickets: + + sqlite better handles datetime/date/time objects mixed and matched + with various Date/Time/DateTime columns + + .. change:: + :tags: sqlite + :tickets: 603 + + string PK column inserts dont get overwritten with OID + + .. change:: + :tags: mssql + :tickets: 634 + + fix port option handling for pyodbc + + .. change:: + :tags: mssql + :tickets: + + now able to reflect start and increment values for identity columns + + .. change:: + :tags: mssql + :tickets: + + preliminary support for using scope_identity() with pyodbc + +.. changelog:: + :version: 0.3.8 + :released: Sat Jun 02 2007 + + .. change:: + :tags: engines + :tickets: + + added detach() to Connection, allows underlying DBAPI connection + to be detached from its pool, closing on dereference/close() + instead of being reused by the pool. + + .. change:: + :tags: engines + :tickets: + + added invalidate() to Connection, immediately invalidates the + Connection and its underlying DBAPI connection. + + .. change:: + :tags: sql + :tickets: + + _Label class overrides compare_self to return its ultimate + object. meaning, if you say someexpr.label('foo') == 5, it + produces the correct "someexpr == 5". + + .. change:: + :tags: sql + :tickets: + + _Label propagates "_hide_froms()" so that scalar selects + behave more properly with regards to FROM clause #574 + + .. change:: + :tags: sql + :tickets: + + fix to long name generation when using oid_column as an order by + (oids used heavily in mapper queries) + + .. change:: + :tags: sql + :tickets: + + significant speed improvement to ResultProxy, pre-caches + TypeEngine dialect implementations and saves on function calls + per column + + .. change:: + :tags: sql + :tickets: + + parenthesis are applied to clauses via a new _Grouping + construct. uses operator precedence to more intelligently apply + parenthesis to clauses, provides cleaner nesting of clauses + (doesnt mutate clauses placed in other clauses, i.e. no 'parens' + flag) + + .. change:: + :tags: sql + :tickets: + + added 'modifier' keyword, works like func. except does not + add parenthesis. e.g. select([modifier.DISTINCT(...)]) etc. + + .. change:: + :tags: sql + :tickets: 578 + + removed "no group by's in a select thats part of a UNION" + restriction + + .. change:: + :tags: orm + :tickets: + + added reset_joinpoint() method to Query, moves the "join point" + back to the starting mapper. 0.4 will change the behavior of + join() to reset the "join point" in all cases so this is an + interim method. for forwards compatibility, ensure joins across + multiple relations are specified using a single join(), i.e. + join(['a', 'b', 'c']). + + .. change:: + :tags: orm + :tickets: + + fixed bug in query.instances() that wouldnt handle more than + on additional mapper or one additional column. + + .. change:: + :tags: orm + :tickets: + + "delete-orphan" no longer implies "delete". ongoing effort to + separate the behavior of these two operations. + + .. change:: + :tags: orm + :tickets: + + many-to-many relationships properly set the type of bind params + for delete operations on the association table + + .. change:: + :tags: orm + :tickets: + + many-to-many relationships check that the number of rows deleted + from the association table by a delete operation matches the + expected results + + .. change:: + :tags: orm + :tickets: + + session.get() and session.load() propagate **kwargs through to + query + + .. change:: + :tags: orm + :tickets: 577 + + fix to polymorphic query which allows the original + polymorphic_union to be embedded into a correlated subquery + + .. change:: + :tags: orm + :tickets: + + fix to select_by(=) -style joins in + conjunction with many-to-many relationships, bug introduced in + r2556 + + .. change:: + :tags: orm + :tickets: + + the "primary_key" argument to mapper() is propagated to the + "polymorphic" mapper. primary key columns in this list get + normalized to that of the mapper's local table. + + .. change:: + :tags: orm + :tickets: + + restored logging of "lazy loading clause" under + sa.orm.strategies logger, got removed in 0.3.7 + + .. change:: + :tags: orm + :tickets: + + improved support for eagerloading of properties off of mappers + that are mapped to select() statements; i.e. eagerloader is + better at locating the correct selectable with which to attach + its LEFT OUTER JOIN. + + .. change:: + :tags: mysql + :tickets: + + Nearly all MySQL column types are now supported for declaration + and reflection. Added NCHAR, NVARCHAR, VARBINARY, TINYBLOB, + LONGBLOB, YEAR + + .. change:: + :tags: mysql + :tickets: + + The sqltypes.Binary passthrough now always builds a BLOB, + avoiding problems with very old database versions + + .. change:: + :tags: mysql + :tickets: + + support for column-level CHARACTER SET and COLLATE declarations, + as well as ASCII, UNICODE, NATIONAL and BINARY shorthand. + + .. change:: + :tags: firebird + :tickets: + + set max identifier length to 31 + + .. change:: + :tags: firebird + :tickets: + + supports_sane_rowcount() set to False due to ticket #370. + versioned_id_col feature wont work in FB. + + .. change:: + :tags: firebird + :tickets: + + some execution fixes + + .. change:: + :tags: firebird + :tickets: + + new association proxy implementation, implementing complete + proxies to list, dict and set-based relation collections + + .. change:: + :tags: firebird + :tickets: + + added orderinglist, a custom list class that synchronizes an + object attribute with that object's position in the list + + .. change:: + :tags: firebird + :tickets: + + small fix to SelectResultsExt to not bypass itself during + select(). + + .. change:: + :tags: firebird + :tickets: + + added filter(), filter_by() to assignmapper + +.. changelog:: + :version: 0.3.7 + :released: Sun Apr 29 2007 + + .. change:: + :tags: engines + :tickets: + + warnings module used for issuing warnings (instead of logging) + + .. change:: + :tags: engines + :tickets: 480 + + cleanup of DBAPI import strategies across all engines + + .. change:: + :tags: engines + :tickets: + + refactoring of engine internals which reduces complexity, + number of codepaths; places more state inside of ExecutionContext + to allow more dialect control of cursor handling, result sets. + ResultProxy totally refactored and also has two versions of + "buffered" result sets used for different purposes. + + .. change:: + :tags: engines + :tickets: 514 + + server side cursor support fully functional in postgres. + + .. change:: + :tags: engines + :tickets: + + improved framework for auto-invalidation of connections that have + lost their underlying database, via dialect-specific detection + of exceptions corresponding to that database's disconnect + related error messages. Additionally, when a "connection no + longer open" condition is detected, the entire connection pool + is discarded and replaced with a new instance. #516 + + .. change:: + :tags: engines + :tickets: 521 + + the dialects within sqlalchemy.databases become a setuptools + entry points. loading the built-in database dialects works the + same as always, but if none found will fall back to trying + pkg_resources to load an external module + + .. change:: + :tags: engines + :tickets: + + Engine contains a "url" attribute referencing the url.URL object + used by create_engine(). + + .. change:: + :tags: sql + :tickets: + + keys() of result set columns are not lowercased, come back + exactly as they're expressed in cursor.description. note this + causes colnames to be all caps in oracle. + + .. change:: + :tags: sql + :tickets: + + preliminary support for unicode table names, column names and + SQL statements added, for databases which can support them. + Works with sqlite and postgres so far. Mysql *mostly* works + except the has_table() function does not work. Reflection + works too. + + .. change:: + :tags: sql + :tickets: 522 + + the Unicode type is now a direct subclass of String, which now + contains all the "convert_unicode" logic. This helps the variety + of unicode situations that occur in db's such as MS-SQL to be + better handled and allows subclassing of the Unicode datatype. + + .. change:: + :tags: sql + :tickets: + + ClauseElements can be used in in_() clauses now, such as bind + parameters, etc. #476 + + .. change:: + :tags: sql + :tickets: + + reverse operators implemented for `CompareMixin` elements, + allows expressions like "5 + somecolumn" etc. #474 + + .. change:: + :tags: sql + :tickets: + + the "where" criterion of an update() and delete() now correlates + embedded select() statements against the table being updated or + deleted. this works the same as nested select() statement + correlation, and can be disabled via the correlate=False flag on + the embedded select(). + + .. change:: + :tags: sql + :tickets: 512 + + column labels are now generated in the compilation phase, which + means their lengths are dialect-dependent. So on oracle a label + that gets truncated to 30 chars will go out to 63 characters + on postgres. Also, the true labelname is always attached as the + accessor on the parent Selectable so theres no need to be aware + of the "truncated" label names. + + .. change:: + :tags: sql + :tickets: + + column label and bind param "truncation" also generate + deterministic names now, based on their ordering within the + full statement being compiled. this means the same statement + will produce the same string across application restarts and + allowing DB query plan caching to work better. + + .. change:: + :tags: sql + :tickets: 513 + + the "mini" column labels generated when using subqueries, which + are to work around glitchy SQLite behavior that doesnt understand + "foo.id" as equivalent to "id", are now only generated in the case + that those named columns are selected from (part of) + + .. change:: + :tags: sql + :tickets: + + the label() method on ColumnElement will properly propagate the + TypeEngine of the base element out to the label, including a label() + created from a scalar=True select() statement. + + .. change:: + :tags: sql + :tickets: 513 + + MS-SQL better detects when a query is a subquery and knows not to + generate ORDER BY phrases for those + + .. change:: + :tags: sql + :tickets: 505 + + fix for fetchmany() "size" argument being positional in most + dbapis + + .. change:: + :tags: sql + :tickets: + + sending None as an argument to func. will produce + an argument of NULL + + .. change:: + :tags: sql + :tickets: + + query strings in unicode URLs get keys encoded to ascii + for **kwargs compat + + .. change:: + :tags: sql + :tickets: 523 + + slight tweak to raw execute() change to also support tuples + for positional parameters, not just lists + + .. change:: + :tags: sql + :tickets: + + fix to case() construct to propagate the type of the first + WHEN condition as the return type of the case statement + + .. change:: + :tags: orm + :tickets: + + fixed critical issue when, after options(eagerload()) is used, + the mapper would then always apply query "wrapping" behavior + for all subsequent LIMIT/OFFSET/DISTINCT queries, even if no + eager loading was applied on those subsequent queries. + + .. change:: + :tags: orm + :tickets: 541 + + added query.with_parent(someinstance) method. searches for + target instance using lazy join criterion from parent instance. + takes optional string "property" to isolate the desired relation. + also adds static Query.query_from_parent(instance, property) + version. + + .. change:: + :tags: orm + :tickets: 554 + + improved query.XXX_by(someprop=someinstance) querying to use + similar methodology to with_parent, i.e. using the "lazy" clause + which prevents adding the remote instance's table to the SQL, + thereby making more complex conditions possible + + .. change:: + :tags: orm + :tickets: + + added generative versions of aggregates, i.e. sum(), avg(), etc. + to query. used via query.apply_max(), apply_sum(), etc. + #552 + + .. change:: + :tags: orm + :tickets: + + fix to using distinct() or distinct=True in combination with + join() and similar + + .. change:: + :tags: orm + :tickets: + + corresponding to label/bindparam name generation, eager loaders + generate deterministic names for the aliases they create using + md5 hashes. + + .. change:: + :tags: orm + :tickets: + + improved/fixed custom collection classes when giving it "set"/ + "sets.Set" classes or subclasses (was still looking for append() + methods on them during lazy loads) + + .. change:: + :tags: orm + :tickets: + + restored old "column_property()" ORM function (used to be called + "column()") to force any column expression to be added as a property + on a mapper, particularly those that aren't present in the mapped + selectable. this allows "scalar expressions" of any kind to be + added as relations (though they have issues with eager loads). + + .. change:: + :tags: orm + :tickets: 533 + + fix to many-to-many relationships targeting polymorphic mappers + + .. change:: + :tags: orm + :tickets: 543 + + making progress with session.merge() as well as combining its + usage with entity_name + + .. change:: + :tags: orm + :tickets: + + the usual adjustments to relationships between inheriting mappers, + in this case establishing relation()s to subclass mappers where + the join conditions come from the superclass' table + + .. change:: + :tags: informix + :tickets: + + informix support added ! courtesy James Zhang, who put a ton + of effort in. + + .. change:: + :tags: sqlite + :tickets: + + removed silly behavior where sqlite would reflect UNIQUE indexes + as part of the primary key (?!) + + .. change:: + :tags: oracle + :tickets: + + small fix to allow successive compiles of the same SELECT object + which features LIMIT/OFFSET. oracle dialect needs to modify + the object to have ROW_NUMBER OVER and wasn't performing + the full series of steps on successive compiles. + + .. change:: + :tags: mysql + :tickets: + + support for SSL arguments given as inline within URL query string, + prefixed with "ssl_", courtesy terjeros@gmail.com. + + .. change:: + :tags: , mysql + :tickets: + + mysql uses "DESCRIBE.", catching exceptions + if table doesnt exist, in order to determine if a table exists. + this supports unicode table names as well as schema names. tested + with MySQL5 but should work with 4.1 series as well. (#557) + + .. change:: + :tags: extensions + :tickets: + + big fix to AssociationProxy so that multiple AssociationProxy + objects can be associated with a single association collection. + + .. change:: + :tags: extensions + :tickets: + + assign_mapper names methods according to their keys (i.e. __name__) + #551 + + .. change:: + :tags: mssql + :tickets: + + pyodbc is now the preferred DB-API for MSSQL, and if no module is + specifically requested, will be loaded first on a module probe. + + .. change:: + :tags: mssql + :tickets: + + The @@SCOPE_IDENTITY is now used instead of @@IDENTITY. This + behavior may be overridden with the engine_connect + "use_scope_identity" keyword parameter, which may also be specified + in the dburi. + +.. changelog:: + :version: 0.3.6 + :released: Fri Mar 23 2007 + + .. change:: + :tags: sql + :tickets: + + bindparam() names are now repeatable! specify two + distinct bindparam()s with the same name in a single statement, + and the key will be shared. proper positional/named args translate + at compile time. for the old behavior of "aliasing" bind parameters + with conflicting names, specify "unique=True" - this option is + still used internally for all the auto-genererated (value-based) + bind parameters. + + .. change:: + :tags: sql + :tickets: + + slightly better support for bind params as column clauses, either + via bindparam() or via literal(), i.e. select([literal('foo')]) + + .. change:: + :tags: sql + :tickets: + + MetaData can bind to an engine either via "url" or "engine" kwargs + to constructor, or by using connect() method. BoundMetaData is + identical to MetaData except engine_or_url param is required. + DynamicMetaData is the same and provides thread-local connections be + default. + + .. change:: + :tags: sql + :tickets: + + exists() becomes useable as a standalone selectable, not just in a + WHERE clause, i.e. exists([columns], criterion).select() + + .. change:: + :tags: sql + :tickets: + + correlated subqueries work inside of ORDER BY, GROUP BY + + .. change:: + :tags: sql + :tickets: + + fixed function execution with explicit connections, i.e. + conn.execute(func.dosomething()) + + .. change:: + :tags: sql + :tickets: + + use_labels flag on select() wont auto-create labels for literal text + column elements, since we can make no assumptions about the text. to + create labels for literal columns, you can say "somecol AS + somelabel", or use literal_column("somecol").label("somelabel") + + .. change:: + :tags: sql + :tickets: + + quoting wont occur for literal columns when they are "proxied" into + the column collection for their selectable (is_literal flag is + propagated). literal columns are specified via + literal_column("somestring"). + + .. change:: + :tags: sql + :tickets: + + added "fold_equivalents" boolean argument to Join.select(), which + removes 'duplicate' columns from the resulting column clause that + are known to be equivalent based on the join condition. this is of + great usage when constructing subqueries of joins which Postgres + complains about if duplicate column names are present. + + .. change:: + :tags: sql + :tickets: 503 + + fixed use_alter flag on ForeignKeyConstraint + + .. change:: + :tags: sql + :tickets: 506 + + fixed usage of 2.4-only "reversed" in topological.py + + .. change:: + :tags: sql + :tickets: 501 + + for hackers, refactored the "visitor" system of ClauseElement and + SchemaItem so that the traversal of items is controlled by the + ClauseVisitor itself, using the method visitor.traverse(item). + accept_visitor() methods can still be called directly but will not + do any traversal of child items. ClauseElement/SchemaItem now have a + configurable get_children() method to return the collection of child + elements for each parent object. This allows the full traversal of + items to be clear and unambiguous (as well as loggable), with an + easy method of limiting a traversal (just pass flags which are + picked up by appropriate get_children() methods). + + .. change:: + :tags: sql + :tickets: + + the "else_" parameter to the case statement now properly works when + set to zero. + + .. change:: + :tags: orm + :tickets: + + the full featureset of the SelectResults extension has been merged + into a new set of methods available off of Query. These methods + all provide "generative" behavior, whereby the Query is copied + and a new one returned with additional criterion added. + The new methods include: + + filter() - applies select criterion to the query + filter_by() - applies "by"-style criterion to the query + avg() - return the avg() function on the given column + join() - join to a property (or across a list of properties) + outerjoin() - like join() but uses LEFT OUTER JOIN + limit()/offset() - apply LIMIT/OFFSET + range-based access which applies limit/offset: + session.query(Foo)[3:5] + distinct() - apply DISTINCT + list() - evaluate the criterion and return results + + no incompatible changes have been made to Query's API and no methods + have been deprecated. Existing methods like select(), select_by(), + get(), get_by() all execute the query at once and return results + like they always did. join_to()/join_via() are still there although + the generative join()/outerjoin() methods are easier to use. + + .. change:: + :tags: orm + :tickets: + + the return value for multiple mappers used with instances() now + returns a cartesian product of the requested list of mappers, + represented as a list of tuples. this corresponds to the documented + behavior. So that instances match up properly, the "uniquing" is + disabled when this feature is used. + + .. change:: + :tags: orm + :tickets: + + Query has add_entity() and add_column() generative methods. these + will add the given mapper/class or ColumnElement to the query at + compile time, and apply them to the instances() method. the user is + responsible for constructing reasonable join conditions (otherwise + you can get full cartesian products). result set is the list of + tuples, non-uniqued. + + .. change:: + :tags: orm + :tickets: + + strings and columns can also be sent to the *args of instances() + where those exact result columns will be part of the result tuples. + + .. change:: + :tags: orm + :tickets: + + a full select() construct can be passed to query.select() (which + worked anyway), but also query.selectfirst(), query.selectone() + which will be used as is (i.e. no query is compiled). works + similarly to sending the results to instances(). + + .. change:: + :tags: orm + :tickets: 495 + + eager loading will not "aliasize" "order by" clauses that were + placed in the select statement by something other than the eager + loader itself, to fix possibility of dupe columns as illustrated in. however, this means you have to be more careful with + the columns placed in the "order by" of Query.select(), that you + have explicitly named them in your criterion (i.e. you cant rely on + the eager loader adding them in for you) + + .. change:: + :tags: orm + :tickets: + + added a handy multi-use "identity_key()" method to Session, allowing + the generation of identity keys for primary key values, instances, + and rows, courtesy Daniel Miller + + .. change:: + :tags: orm + :tickets: 249 + + many-to-many table will be properly handled even for operations that + occur on the "backref" side of the operation + + .. change:: + :tags: orm + :tickets: 492 + + added "refresh-expire" cascade. allows refresh() and + expire() calls to propagate along relationships. + + .. change:: + :tags: orm + :tickets: 493 + + more fixes to polymorphic relations, involving proper lazy-clause + generation on many-to-one relationships to polymorphic mappers. also fixes to detection of "direction", more specific + targeting of columns that belong to the polymorphic union vs. those + that dont. + + .. change:: + :tags: orm + :tickets: + + some fixes to relationship calcs when using "viewonly=True" to pull + in other tables into the join condition which arent parent of the + relationship's parent/child mappings + + .. change:: + :tags: orm + :tickets: + + flush fixes on cyclical-referential relationships that contain + references to other instances outside of the cyclical chain, when + some of the objects in the cycle are not actually part of the flush + + .. change:: + :tags: orm + :tickets: 500 + + put an aggressive check for "flushing object A with a collection of + B's, but you put a C in the collection" error condition - **even if + C is a subclass of B**, unless B's mapper loads polymorphically. + Otherwise, the collection will later load a "B" which should be a + "C" (since its not polymorphic) which breaks in bi-directional + relationships (i.e. C has its A, but A's backref will lazyload it as + a different instance of type "B") This check is going + to bite some of you who do this without issues, so the error message + will also document a flag "enable_typechecks=False" to disable this + checking. But be aware that bi-directional relationships in + particular become fragile without this check. + + .. change:: + :tags: extensions + :tickets: 472 + + options() method on SelectResults now implemented "generatively" + like the rest of the SelectResults methods. But + you're going to just use Query now anyway. + + .. change:: + :tags: extensions + :tickets: + + query() method is added by assignmapper. this helps with + navigating to all the new generative methods on Query. + + .. change:: + :tags: ms-sql + :tickets: + + removed seconds input on DATE column types (probably + should remove the time altogether) + + .. change:: + :tags: ms-sql + :tickets: + + null values in float fields no longer raise errors + + .. change:: + :tags: ms-sql + :tickets: + + LIMIT with OFFSET now raises an error (MS-SQL has no OFFSET support) + + .. change:: + :tags: ms-sql + :tickets: 509 + + added an facility to use the MSSQL type VARCHAR(max) instead of TEXT + for large unsized string fields. Use the new "text_as_varchar" to + turn it on. + + .. change:: + :tags: ms-sql + :tickets: + + ORDER BY clauses without a LIMIT are now stripped in subqueries, as + MS-SQL forbids this usage + + .. change:: + :tags: ms-sql + :tickets: 480 + + cleanup of module importing code; specifiable DB-API module; more + explicit ordering of module preferences. + + .. change:: + :tags: oracle + :tickets: + + got binary working for any size input ! cx_oracle works fine, + it was my fault as BINARY was being passed and not BLOB for + setinputsizes (also unit tests werent even setting input sizes). + + .. change:: + :tags: oracle + :tickets: + + also fixed CLOB read/write on a separate changeset. + + .. change:: + :tags: oracle + :tickets: + + auto_setinputsizes defaults to True for Oracle, fixed cases where + it improperly propagated bad types. + + .. change:: + :tags: mysql + :tickets: + + added a catchall **kwargs to MSString, to help reflection of + obscure types (like "varchar() binary" in MS 4.0) + + .. change:: + :tags: mysql + :tickets: + + added explicit MSTimeStamp type which takes effect when using + types.TIMESTAMP. + +.. changelog:: + :version: 0.3.5 + :released: Thu Feb 22 2007 + + .. change:: + :tags: sql + :tickets: + + the value of "case_sensitive" defaults to True now, regardless of the + casing of the identifier, unless specifically set to False. this is + because the object might be label'ed as something else which does + contain mixed case, and propigating "case_sensitive=False" breaks that. + Other fixes to quoting when using labels and "fake" column objects + + .. change:: + :tags: sql + :tickets: + + added a "supports_execution()" method to ClauseElement, so that + individual kinds of clauses can express if they are appropriate for + executing...such as, you can execute a "select", but not a "Table" or a + "Join". + + .. change:: + :tags: sql + :tickets: + + fixed argument passing to straight textual execute() on engine, + connection. can handle *args or a list instance for positional, **kwargs + or a dict instance for named args, or a list of list or dicts to invoke + executemany() + + .. change:: + :tags: sql + :tickets: + + small fix to BoundMetaData to accept unicode or string URLs + + .. change:: + :tags: sql + :tickets: 466 + + fixed named PrimaryKeyConstraint generation courtesy + andrija at gmail + + .. change:: + :tags: sql + :tickets: 464 + + fixed generation of CHECK constraints on columns + + .. change:: + :tags: sql + :tickets: + + fixes to tometadata() operation to propagate Constraints at column and + table level + + .. change:: + :tags: oracle + :tickets: 436 + + when returning "rowid" as the ORDER BY column or in use with ROW_NUMBER + OVER, oracle dialect checks the selectable its being applied to and will + switch to table PK if not applicable, i.e. for a UNION. checking for + DISTINCT, GROUP BY (other places that rowid is invalid) still a TODO. + allows polymorphic mappings to function. + + .. change:: + :tags: oracle + :tickets: + + sequences on a non-pk column will properly fire off on INSERT + + .. change:: + :tags: oracle + :tickets: 435 + + added PrefetchingResultProxy support to pre-fetch LOB columns when they + are known to be present, fixes + + .. change:: + :tags: oracle + :tickets: 379 + + implemented reflection of tables based on synonyms, including across + dblinks + + .. change:: + :tags: oracle + :tickets: 363 + + issues a log warning when a related table cant be reflected due to + certain permission errors + + .. change:: + :tags: mysql + :tickets: + + fix to reflection on older DB's that might return array() type for + "show variables like" statements + + .. change:: + :tags: postgres + :tickets: 442 + + better reflection of sequences for alternate-schema Tables + + .. change:: + :tags: postgres + :tickets: + + sequences on a non-pk column will properly fire off on INSERT + + .. change:: + :tags: postgres + :tickets: 460, 444 + + added PGInterval type, PGInet type + + .. change:: + :tags: mssql + :tickets: 419 + + preliminary support for pyodbc (Yay!) + + .. change:: + :tags: mssql + :tickets: 298 + + better support for NVARCHAR types added + + .. change:: + :tags: mssql + :tickets: + + fix for commit logic on pymssql + + .. change:: + :tags: mssql + :tickets: 456 + + fix for query.get() with schema + + .. change:: + :tags: mssql + :tickets: 473 + + fix for non-integer relationships + + .. change:: + :tags: mssql + :tickets: 419 + + DB-API module now selectable at run-time + + .. change:: + :tags: tickets:422, 481, 415, mssql + :tickets: + + now passes many more unit tests + + .. change:: + :tags: mssql + :tickets: 479 + + better unittest compatibility with ANSI functions + + .. change:: + :tags: mssql + :tickets: 415 + + improved support for implicit sequence PK columns with auto-insert + + .. change:: + :tags: mssql + :tickets: 371 + + fix for blank password in adodbapi + + .. change:: + :tags: mssql + :tickets: 481 + + fixes to get unit tests working with pyodbc + + .. change:: + :tags: mssql + :tickets: + + fix to auto_identity_insert on db-url query + + .. change:: + :tags: mssql + :tickets: + + added query_timeout to db-url query parms. currently works only for + pymssql + + .. change:: + :tags: mssql + :tickets: + + tested with pymssql 0.8.0 (which is now LGPL) + + .. change:: + :tags: orm, bugs + :tickets: 441, 448, 439 + + another refactoring to relationship calculation. Allows more accurate + ORM behavior with relationships from/to/between mappers, particularly + polymorphic mappers, also their usage with Query, SelectResults. tickets + include,,. + + .. change:: + :tags: orm, bugs + :tickets: + + removed deprecated method of specifying custom collections on classes; + you must now use the "collection_class" option. the old way was + beginning to produce conflicts when people used assign_mapper(), which + now patches an "options" method, in conjunction with a relationship + named "options". (relationships take precedence over monkeypatched + assign_mapper methods). + + .. change:: + :tags: orm, bugs + :tickets: 454 + + extension() query option propagates to Mapper._instance() method so that + all loading-related methods get called + + .. change:: + :tags: orm, bugs + :tickets: + + eager relation to an inheriting mapper wont fail if no rows returned for + the relationship. + + .. change:: + :tags: orm, bugs + :tickets: 486 + + eager relation loading bug fixed for eager relation on multiple + descendant classes + + .. change:: + :tags: orm, bugs + :tickets: 423 + + fix for very large topological sorts, courtesy ants.aasma at gmail + + .. change:: + :tags: orm, bugs + :tickets: + + eager loading is slightly more strict about detecting "self-referential" + relationships, specifically between polymorphic mappers. this results in + an "eager degrade" to lazy loading. + + .. change:: + :tags: orm, bugs + :tickets: 449 + + improved support for complex queries embedded into "where" criterion for + query.select() + + .. change:: + :tags: orm, bugs + :tickets: 485 + + mapper options like eagerload(), lazyload(), deferred(), will work for + "synonym()" relationships + + .. change:: + :tags: orm, bugs + :tickets: 445 + + fixed bug where cascade operations incorrectly included deleted + collection items in the cascade + + .. change:: + :tags: orm, bugs + :tickets: 478 + + fixed relationship deletion error when one-to-many child item is moved + to a new parent in a single unit of work + + .. change:: + :tags: orm, bugs + :tickets: + + fixed relationship deletion error where parent/child with a single + column as PK/FK on the child would raise a "blank out the primary key" + error, if manually deleted or "delete" cascade without "delete-orphan" + was used + + .. change:: + :tags: orm, bugs + :tickets: + + fix to deferred so that load operation doesnt mistakenly occur when only + PK col attributes are set + + .. change:: + :tags: orm, enhancements + :tickets: 385 + + implemented foreign_keys argument to mapper. use in + conjunction with primaryjoin/secondaryjoin arguments to specify/override + foreign keys defined on the Table instance. + + .. change:: + :tags: orm, enhancements + :tickets: + + contains_eager('foo') automatically implies eagerload('foo') + + .. change:: + :tags: orm, enhancements + :tickets: + + added "alias" argument to contains_eager(). use it to specify the string + name or Alias instance of an alias used in the query for the eagerly + loaded child items. easier to use than "decorator" + + .. change:: + :tags: orm, enhancements + :tickets: + + added "contains_alias()" option for result set mapping to an alias of + the mapped table + + .. change:: + :tags: orm, enhancements + :tickets: 468 + + added support for py2.5 "with" statement with SessionTransaction + + .. change:: + :tags: extensions + :tickets: + + added distinct() method to SelectResults. generally should only make a + difference when using count(). + + .. change:: + :tags: extensions + :tickets: 472 + + added options() method to SelectResults, equivalent to query.options() + + .. change:: + :tags: extensions + :tickets: 462 + + added optional __table_opts__ dictionary to ActiveMapper, will send kw + options to Table objects + + .. change:: + :tags: extensions + :tickets: 467 + + added selectfirst(), selectfirst_by() to assign_mapper + +.. changelog:: + :version: 0.3.4 + :released: Tue Jan 23 2007 + + .. change:: + :tags: general + :tickets: + + global "insure"->"ensure" change. in US english "insure" is actually + largely interchangeable with "ensure" (so says the dictionary), so I'm not + completely illiterate, but its definitely sub-optimal to "ensure" which is + non-ambiguous. + + .. change:: + :tags: sql + :tickets: + + added "fetchmany()" support to ResultProxy + + .. change:: + :tags: sql + :tickets: + + added support for column "key" attribute to be useable in + row[]/row. + + .. change:: + :tags: sql + :tickets: + + changed "BooleanExpression" to subclass from "BinaryExpression", so that + boolean expressions can also follow column-clause behaviors (i.e. label(), + etc). + + .. change:: + :tags: sql + :tickets: + + trailing underscores are trimmed from func. calls, such as func.if_() + + .. change:: + :tags: sql + :tickets: + + fix to correlation of subqueries when the column list of the select + statement is constructed with individual calls to append_column(); this + fixes an ORM bug whereby nested select statements were not getting + correlated with the main select generated by the Query object. + + .. change:: + :tags: sql + :tickets: + + another fix to subquery correlation so that a subquery which has only one + FROM element will *not* correlate that single element, since at least one + FROM element is required in a query. + + .. change:: + :tags: sql + :tickets: 414 + + default "timezone" setting is now False. this corresponds to Python's + datetime behavior as well as Postgres' timestamp/time types (which is the + only timezone-sensitive dialect at the moment) + + .. change:: + :tags: sql + :tickets: + + the "op()" function is now treated as an "operation", rather than a + "comparison". the difference is, an operation produces a BinaryExpression + from which further operations can occur whereas comparison produces the + more restrictive BooleanExpression + + .. change:: + :tags: sql + :tickets: + + trying to redefine a reflected primary key column as non-primary key raises + an error + + .. change:: + :tags: sql + :tickets: + + type system slightly modified to support TypeDecorators that can be + overridden by the dialect (ok, thats not very clear, it allows the mssql + tweak below to be possible) + + .. change:: + :tags: mssql + :tickets: + + added an NVarchar type (produces NVARCHAR), also MSUnicode which provides + Unicode-translation for the NVarchar regardless of dialect convert_unicode + setting. + + .. change:: + :tags: postgres + :tickets: 424 + + fix to the initial checkfirst for tables to take current schema into + account + + .. change:: + :tags: postgres + :tickets: + + postgres has an optional "server_side_cursors=True" flag which will utilize + server side cursors. these are appropriate for fetching only partial + results and are necessary for working with very large unbounded result + sets. While we'd like this to be the default behavior, different + environments seem to have different results and the causes have not been + isolated so we are leaving the feature off by default for now. Uses an + apparently undocumented psycopg2 behavior recently discovered on the + psycopg mailing list. + + .. change:: + :tags: postgres + :tickets: + + added "BIGSERIAL" support for postgres table with + PGBigInteger/autoincrement + + .. change:: + :tags: postgres + :tickets: 402 + + fixes to postgres reflection to better handle when schema names are + present; thanks to jason (at) ncsmags.com + + .. change:: + :tags: mysql + :tickets: 420 + + mysql is inconsistent with what kinds of quotes it uses in foreign keys + during a SHOW CREATE TABLE, reflection updated to accomodate for all three + styles + + .. change:: + :tags: mysql + :tickets: 418 + + mysql table create options work on a generic passthru now, i.e. Table(..., + mysql_engine='InnoDB', mysql_collate="latin1_german2_ci", + mysql_auto_increment="5", mysql_...), helps + + .. change:: + :tags: firebird + :tickets: 408 + + order of constraint creation puts primary key first before all other + constraints; required for firebird, not a bad idea for others + + .. change:: + :tags: firebird + :tickets: 409 + + Firebird fix to autoload multifield foreign keys + + .. change:: + :tags: firebird + :tickets: 409 + + Firebird NUMERIC type properly handles a type without precision + + .. change:: + :tags: oracle + :tickets: + + *slight* support for binary, but still need to figure out how to insert + reasonably large values (over 4K). requires auto_setinputsizes=True sent to + create_engine(), rows must be fully fetched individually, etc. + + .. change:: + :tags: orm + :tickets: + + poked the first hole in the can of worms: saying + query.select_by(somerelationname=someinstance) will create the join of the + primary key columns represented by "somerelationname"'s mapper to the + actual primary key in "someinstance". + + .. change:: + :tags: orm + :tickets: + + reworked how relations interact with "polymorphic" mappers, i.e. mappers + that have a select_table as well as polymorphic flags. better determination + of proper join conditions, interaction with user- defined join conditions, + and support for self-referential polymorphic mappers. + + .. change:: + :tags: orm + :tickets: + + related to polymorphic mapping relations, some deeper error checking when + compiling relations, to detect an ambiguous "primaryjoin" in the case that + both sides of the relationship have foreign key references in the primary + join condition. also tightened down conditions used to locate "relation + direction", associating the "foreignkey" of the relationship with the + "primaryjoin" + + .. change:: + :tags: orm + :tickets: + + a little bit of improvement to the concept of a "concrete" inheritance + mapping, though that concept is not well fleshed out yet (added test case + to support concrete mappers on top of a polymorphic base). + + .. change:: + :tags: orm + :tickets: + + fix to "proxy=True" behavior on synonym() + + .. change:: + :tags: orm + :tickets: 427 + + fixed bug where delete-orphan basically didn't work with many-to-many + relationships, backref presence generally hid the symptom + + .. change:: + :tags: orm + :tickets: + + added a mutex to the mapper compilation step. ive been reluctant to add any + kind of threading anything to SA but this is one spot that its its really + needed since mappers are typically "global", and while their state does not + change during normal operation, the initial compilation step does modify + internal state significantly, and this step usually occurs not at + module-level initialization time (unless you call compile()) but at + first-request time + + .. change:: + :tags: orm + :tickets: + + basic idea of "session.merge()" actually implemented. needs more testing. + + .. change:: + :tags: orm + :tickets: + + added "compile_mappers()" function as a shortcut to compiling all mappers + + .. change:: + :tags: orm + :tickets: + + fix to MapperExtension create_instance so that entity_name properly + associated with new instance + + .. change:: + :tags: orm + :tickets: + + speed enhancements to ORM object instantiation, eager loading of rows + + .. change:: + :tags: orm + :tickets: 406 + + invalid options sent to 'cascade' string will raise an exception + + .. change:: + :tags: orm + :tickets: 407 + + fixed bug in mapper refresh/expire whereby eager loaders didnt properly + re-populate item lists + + .. change:: + :tags: orm + :tickets: 413 + + fix to post_update to ensure rows are updated even for non insert/delete + scenarios + + .. change:: + :tags: orm + :tickets: 412 + + added an error message if you actually try to modify primary key values on + an entity and then flush it + + .. change:: + :tags: extensions + :tickets: 426 + + added "validate=False" argument to assign_mapper, if True will ensure that + only mapped attributes are named + + .. change:: + :tags: extensions + :tickets: + + assign_mapper gets "options", "instances" functions added (i.e. + MyClass.instances()) + +.. changelog:: + :version: 0.3.3 + :released: Fri Dec 15 2006 + + .. change:: + :tags: + :tickets: + + string-based FROM clauses fixed, i.e. select(..., from_obj=["sometext"]) + + .. change:: + :tags: + :tickets: + + fixes to passive_deletes flag, lazy=None (noload) flag + + .. change:: + :tags: + :tickets: + + added example/docs for dealing with large collections + + .. change:: + :tags: + :tickets: + + added object_session() method to sqlalchemy namespace + + .. change:: + :tags: + :tickets: + + fixed QueuePool bug whereby its better able to reconnect to a database + that was not reachable (thanks to Sébastien Lelong), also fixed dispose() + method + + .. change:: + :tags: + :tickets: 396 + + patch that makes MySQL rowcount work correctly! + + .. change:: + :tags: + :tickets: + + fix to MySQL catch of 2006/2014 errors to properly re-raise OperationalError + exception + +.. changelog:: + :version: 0.3.2 + :released: Sun Dec 10 2006 + + .. change:: + :tags: + :tickets: 387 + + major connection pool bug fixed. fixes MySQL out of sync + errors, will also prevent transactions getting rolled back + accidentally in all DBs + + .. change:: + :tags: + :tickets: + + major speed enhancements vs. 0.3.1, to bring speed + back to 0.2.8 levels + + .. change:: + :tags: + :tickets: + + made conditional dozens of debug log calls that were + time-intensive to generate log messages + + .. change:: + :tags: + :tickets: + + fixed bug in cascade rules whereby the entire object graph + could be unnecessarily cascaded on the save/update cascade + + .. change:: + :tags: + :tickets: + + various speedups in attributes module + + .. change:: + :tags: + :tickets: 388 + + identity map in Session is by default *no longer weak referencing*. + to have it be weak referencing, use create_session(weak_identity_map=True) + fixes + + .. change:: + :tags: + :tickets: + + MySQL detects errors 2006 (server has gone away) and 2014 + (commands out of sync) and invalidates the connection on which it occured. + + .. change:: + :tags: + :tickets: 307 + + MySQL bool type fix: + + .. change:: + :tags: + :tickets: 382, 349 + + postgres reflection fixes: + + .. change:: + :tags: + :tickets: 247 + + added keywords for EXCEPT, INTERSECT, EXCEPT ALL, INTERSECT ALL + + .. change:: + :tags: + :tickets: 2110 + + assign_mapper in assignmapper extension returns the created mapper + + .. change:: + :tags: + :tickets: + + added label() function to Select class, when scalar=True is used + to create a scalar subquery + i.e. "select x, y, (select max(foo) from table) AS foomax from table" + + .. change:: + :tags: + :tickets: + + added onupdate and ondelete keyword arguments to ForeignKey; propagate + to underlying ForeignKeyConstraint if present. (dont propagate in the + other direction, however) + + .. change:: + :tags: + :tickets: + + fix to session.update() to preserve "dirty" status of incoming object + + .. change:: + :tags: + :tickets: + + sending a selectable to an IN via the in_() function no longer creates + a "union" out of multiple selects; only one selectable to a the in_() function + is allowed now (make a union yourself if union is needed) + + .. change:: + :tags: + :tickets: + + improved support for disabling save-update cascade via cascade="none" etc. + + .. change:: + :tags: + :tickets: + + added "remote_side" argument to relation(), used only with self-referential + mappers to force the direction of the parent/child relationship. replaces + the usage of the "foreignkey" parameter for "switching" the direction. + "foreignkey" argument is deprecated for all uses and will eventually + be replaced by an argument dedicated to ForeignKey specification on mappers. + +.. changelog:: + :version: 0.3.1 + :released: Mon Nov 13 2006 + + .. change:: + :tags: engine/pool + :tickets: + + some new Pool utility classes, updated docs + + .. change:: + :tags: engine/pool + :tickets: + + "use_threadlocal" on Pool defaults to False (same as create_engine) + + .. change:: + :tags: engine/pool + :tickets: + + fixed direct execution of Compiled objects + + .. change:: + :tags: engine/pool + :tickets: + + create_engine() reworked to be strict about incoming **kwargs. all keyword + arguments must be consumed by one of the dialect, connection pool, and engine + constructors, else a TypeError is thrown which describes the full set of + invalid kwargs in relation to the selected dialect/pool/engine configuration. + + .. change:: + :tags: databases/types + :tickets: + + MySQL catches exception on "describe" and reports as NoSuchTableError + + .. change:: + :tags: databases/types + :tickets: + + further fixes to sqlite booleans, weren't working as defaults + + .. change:: + :tags: databases/types + :tickets: + + fix to postgres sequence quoting when using schemas + + .. change:: + :tags: orm + :tickets: + + the "delete" cascade will load in all child objects, if they were not + loaded already. this can be turned off (i.e. the old behavior) by setting + passive_deletes=True on a relation(). + + .. change:: + :tags: orm + :tickets: + + adjustments to reworked eager query generation to not fail on circular + eager-loaded relationships (like backrefs) + + .. change:: + :tags: orm + :tickets: + + fixed bug where eagerload() (nor lazyload()) option didn't properly + instruct the Query whether or not to use "nesting" when producing a + LIMIT query. + + .. change:: + :tags: orm + :tickets: 360 + + fixed bug in circular dependency sorting at flush time; if object A + contained a cyclical many-to-one relationship to object B, and object B + was just attached to object A, *but* object B itself wasnt changed, + the many-to-one synchronize of B's primary key attribute to A's foreign key + attribute wouldnt occur. + + .. change:: + :tags: orm + :tickets: 325 + + implemented from_obj argument for query.count, improves count function + on selectresults + + .. change:: + :tags: orm + :tickets: + + added an assertion within the "cascade" step of ORM relationships to check + that the class of object attached to a parent object is appropriate + (i.e. if A.items stores B objects, raise an error if a C is appended to A.items) + + .. change:: + :tags: orm + :tickets: + + new extension sqlalchemy.ext.associationproxy, provides transparent + "association object" mappings. new example + examples/association/proxied_association.py illustrates. + + .. change:: + :tags: orm + :tickets: + + improvement to single table inheritance to load full hierarchies beneath + the target class + + .. change:: + :tags: orm + :tickets: 362 + + fix to subtle condition in topological sort where a node could appear twice, + for + + .. change:: + :tags: orm + :tickets: 365 + + additional rework to topological sort, refactoring, for + + .. change:: + :tags: orm + :tickets: + + "delete-orphan" for a certain type can be set on more than one parent class; + the instance is an "orphan" only if its not attached to *any* of those parents + +.. changelog:: + :version: 0.3.0 + :released: Sun Oct 22 2006 + + .. change:: + :tags: general + :tickets: + + logging is now implemented via standard python "logging" module. + "echo" keyword parameters are still functional but set/unset + log levels for their respective classes/instances. all logging + can be controlled directly through the Python API by setting + INFO and DEBUG levels for loggers in the "sqlalchemy" namespace. + class-level logging is under "sqlalchemy..", + instance-level logging under "sqlalchemy...0x..<00-FF>". + Test suite includes "--log-info" and "--log-debug" arguments + which work independently of --verbose/--quiet. Logging added + to orm to allow tracking of mapper configurations, row iteration. + + .. change:: + :tags: general + :tickets: + + the documentation-generation system has been overhauled to be + much simpler in design and more integrated with Markdown + + .. change:: + :tags: sqlite + :tickets: + + sqlite boolean datatype converts False/True to 0/1 by default + + .. change:: + :tags: sqlite + :tickets: 335 + + fixes to Date/Time (SLDate/SLTime) types; works as good as postgres + now + + .. change:: + :tags: ms-sql + :tickets: + + fixes bug 261 (table reflection broken for MS-SQL case-sensitive + databases) + + .. change:: + :tags: ms-sql + :tickets: + + can now specify port for pymssql + + .. change:: + :tags: ms-sql + :tickets: + + introduces new "auto_identity_insert" option for auto-switching + between "SET IDENTITY_INSERT" mode when values specified for IDENTITY columns + + .. change:: + :tags: ms-sql + :tickets: + + now supports multi-column foreign keys + + .. change:: + :tags: ms-sql + :tickets: + + fix to reflecting date/datetime columns + + .. change:: + :tags: ms-sql + :tickets: + + NCHAR and NVARCHAR type support added + + .. change:: + :tags: oracle + :tickets: + + Oracle has experimental support for cx_Oracle.TIMESTAMP, which requires + a setinputsizes() call on the cursor that is now enabled via the + 'auto_setinputsizes' flag to the oracle dialect. + + .. change:: + :tags: firebird + :tickets: + + aliases do not use "AS" + + .. change:: + :tags: firebird + :tickets: + + correctly raises NoSuchTableError when reflecting non-existent table + + .. change:: + :tags: schema + :tickets: + + a fair amount of cleanup to the schema package, removal of ambiguous + methods, methods that are no longer needed. slightly more constrained + useage, greater emphasis on explicitness + + .. change:: + :tags: schema + :tickets: + + the "primary_key" attribute of Table and other selectables becomes + a setlike ColumnCollection object; is ordered but not numerically + indexed. a comparison clause between two pks that are derived from the + same underlying tables (i.e. such as two Alias objects) can be generated + via table1.primary_key==table2.primary_key + + .. change:: + :tags: schema + :tickets: + + ForeignKey(Constraint) supports "use_alter=True", to create/drop a foreign key + via ALTER. this allows circular foreign key relationships to be set up. + + .. change:: + :tags: schema + :tickets: + + append_item() methods removed from Table and Column; preferably + construct Table/Column/related objects inline, but if needed use + append_column(), append_foreign_key(), append_constraint(), etc. + + .. change:: + :tags: schema + :tickets: + + table.create() no longer returns the Table object, instead has no + return value. the usual case is that tables are created via metadata, + which is preferable since it will handle table dependencies. + + .. change:: + :tags: schema + :tickets: + + added UniqueConstraint (goes at Table level), CheckConstraint + (goes at Table or Column level). + + .. change:: + :tags: schema + :tickets: + + index=False/unique=True on Column now creates a UniqueConstraint, + index=True/unique=False creates a plain Index, + index=True/unique=True on Column creates a unique Index. 'index' + and 'unique' keyword arguments to column are now boolean only; for + explcit names and groupings of indexes or unique constraints, use the + UniqueConstraint/Index constructs explicitly. + + .. change:: + :tags: schema + :tickets: + + added autoincrement=True to Column; will disable schema generation + of SERIAL/AUTO_INCREMENT/identity seq for postgres/mysql/mssql if + explicitly set to False + + .. change:: + :tags: schema + :tickets: + + TypeEngine objects now have methods to deal with copying and comparing + values of their specific type. Currently used by the ORM, see below. + + .. change:: + :tags: schema + :tickets: + + fixed condition that occurred during reflection when a primary key + column was explciitly overridden, where the PrimaryKeyConstraint would + get both the reflected and the programmatic column doubled up + + .. change:: + :tags: schema + :tickets: + + the "foreign_key" attribute on Column and ColumnElement in general + is deprecated, in favor of the "foreign_keys" list/set-based attribute, + which takes into account multiple foreign keys on one column. + "foreign_key" will return the first element in the "foreign_keys" list/set + or None if the list is empty. + + .. change:: + :tags: connections/pooling/execution + :tickets: + + connection pool tracks open cursors and automatically closes them + if connection is returned to pool with cursors still opened. Can be + affected by options which cause it to raise an error instead, or to + do nothing. fixes issues with MySQL, others + + .. change:: + :tags: connections/pooling/execution + :tickets: + + fixed bug where Connection wouldnt lose its Transaction + after commit/rollback + + .. change:: + :tags: connections/pooling/execution + :tickets: + + added scalar() method to ComposedSQLEngine, ResultProxy + + .. change:: + :tags: connections/pooling/execution + :tickets: + + ResultProxy will close() the underlying cursor when the ResultProxy + itself is closed. this will auto-close cursors for ResultProxy objects + that have had all their rows fetched (or had scalar() called). + + .. change:: + :tags: connections/pooling/execution + :tickets: + + ResultProxy.fetchall() internally uses DBAPI fetchall() for better efficiency, + added to mapper iteration as well (courtesy Michael Twomey) + + .. change:: + :tags: construction, sql + :tickets: 292 + + changed "for_update" parameter to accept False/True/"nowait" + and "read", the latter two of which are interpreted only by + Oracle and Mysql + + .. change:: + :tags: construction, sql + :tickets: + + added extract() function to sql dialect + (SELECT extract(field FROM expr)) + + .. change:: + :tags: construction, sql + :tickets: + + BooleanExpression includes new "negate" argument to specify + the appropriate negation operator if one is available. + + .. change:: + :tags: construction, sql + :tickets: + + calling a negation on an "IN" or "IS" clause will result in + "NOT IN", "IS NOT" (as opposed to NOT (x IN y)). + + .. change:: + :tags: construction, sql + :tickets: 172 + + Function objects know what to do in a FROM clause now. their + behavior should be the same, except now you can also do things like + select(['*'], from_obj=[func.my_function()]) to get multiple + columns from the result, or even use sql.column() constructs to name the + return columns + + .. change:: + :tags: orm + :tickets: + + attribute tracking modified to be more intelligent about detecting + changes, particularly with mutable types. TypeEngine objects now + take a greater role in defining how to compare two scalar instances, + including the addition of a MutableType mixin which is implemented by + PickleType. unit-of-work now tracks the "dirty" list as an expression + of all persistent objects where the attribute manager detects changes. + The basic issue thats fixed is detecting changes on PickleType + objects, but also generalizes type handling and "modified" object + checking to be more complete and extensible. + + .. change:: + :tags: orm + :tickets: + + a wide refactoring to "attribute loader" and "options" architectures. + ColumnProperty and PropertyLoader define their loading behaivor via switchable + "strategies", and MapperOptions no longer use mapper/property copying + in order to function; they are instead propagated via QueryContext + and SelectionContext objects at query/instances time. + All of the internal copying of mappers and properties that was used to handle + inheritance as well as options() has been removed; the structure + of mappers and properties is much simpler than before and is clearly laid out + in the new 'interfaces' module. + + .. change:: + :tags: orm + :tickets: + + related to the mapper/property overhaul, internal refactoring to + mapper instances() method to use a SelectionContext object to track + state during the operation. + SLIGHT API BREAKAGE: the append_result() and populate_instances() + methods on MapperExtension have a slightly different method signature + now as a result of the change; hoping that these methods are not + in widespread use as of yet. + + .. change:: + :tags: orm + :tickets: + + instances() method moved to Query now, backwards-compatible + version remains on Mapper. + + .. change:: + :tags: orm + :tickets: + + added contains_eager() MapperOption, used in conjunction with + instances() to specify properties that should be eagerly loaded + from the result set, using their plain column names by default, or translated + given an custom row-translation function. + + .. change:: + :tags: orm + :tickets: + + more rearrangements of unit-of-work commit scheme to better allow + dependencies within circular flushes to work properly...updated + task traversal/logging implementation + + .. change:: + :tags: orm + :tickets: 321 + + polymorphic mappers (i.e. using inheritance) now produces INSERT + statements in order of tables across all inherited classes + + .. change:: + :tags: orm + :tickets: + + added an automatic "row switch" feature to mapping, which will + detect a pending instance/deleted instance pair with the same + identity key and convert the INSERT/DELETE to a single UPDATE + + .. change:: + :tags: orm + :tickets: + + "association" mappings simplified to take advantage of + automatic "row switch" feature + + .. change:: + :tags: orm + :tickets: 212 + + "custom list classes" is now implemented via the "collection_class" + keyword argument to relation(). the old way still works but is + deprecated + + .. change:: + :tags: orm + :tickets: + + added "viewonly" flag to relation(), allows construction of + relations that have no effect on the flush() process. + + .. change:: + :tags: orm + :tickets: 292 + + added "lockmode" argument to base Query select/get functions, + including "with_lockmode" function to get a Query copy that has + a default locking mode. Will translate "read"/"update" + arguments into a for_update argument on the select side. + + .. change:: + :tags: orm + :tickets: + + implemented "version check" logic in Query/Mapper, used + when version_id_col is in effect and query.with_lockmode() + is used to get() an instance thats already loaded + + .. change:: + :tags: orm + :tickets: 208 + + post_update behavior improved; does a better job at not + updating too many rows, updates only required columns + + .. change:: + :tags: orm + :tickets: 308 + + adjustments to eager loading so that its "eager chain" is + kept separate from the normal mapper setup, thereby + preventing conflicts with lazy loader operation, fixes + + .. change:: + :tags: orm + :tickets: + + fix to deferred group loading + + .. change:: + :tags: orm + :tickets: 346 + + session.flush() wont close a connection it opened + + .. change:: + :tags: orm + :tickets: + + added "batch=True" flag to mapper; if False, save_obj + will fully save one object at a time including calls + to before_XXXX and after_XXXX + + .. change:: + :tags: orm + :tickets: + + added "column_prefix=None" argument to mapper; prepends the + given string (typically '_') to column-based attributes automatically + set up from the mapper's Table + + .. change:: + :tags: orm + :tickets: 315 + + specifying joins in the from_obj argument of query.select() will + replace the main table of the query, if the table is somewhere within + the given from_obj. this makes it possible to produce custom joins and + outerjoins in queries without the main table getting added twice. + + .. change:: + :tags: orm + :tickets: + + eagerloading is adjusted to more thoughtfully attach its LEFT OUTER JOINs + to the given query, looking for custom "FROM" clauses that may have + already been set up. + + .. change:: + :tags: orm + :tickets: + + added join_to and outerjoin_to transformative methods to SelectResults, + to build up join/outerjoin conditions based on property names. also + added select_from to explicitly set from_obj parameter. + + .. change:: + :tags: orm + :tickets: + + removed "is_primary" flag from mapper. diff --git a/doc/build/changelog/changelog_04.rst b/doc/build/changelog/changelog_04.rst new file mode 100644 index 0000000000..37b424df7b --- /dev/null +++ b/doc/build/changelog/changelog_04.rst @@ -0,0 +1,4198 @@ + +============== +0.4 Changelog +============== + + +.. changelog:: + :version: 0.4.8 + :released: Sun Oct 12 2008 + + .. change:: + :tags: orm + :tickets: 1039 + + Fixed bug regarding inherit_condition passed + with "A=B" versus "B=A" leading to errors + + .. change:: + :tags: orm + :tickets: + + Changes made to new, dirty and deleted + collections in + SessionExtension.before_flush() will take + effect for that flush. + + .. change:: + :tags: orm + :tickets: + + Added label() method to InstrumentedAttribute + to establish forwards compatibility with 0.5. + + .. change:: + :tags: sql + :tickets: 1074 + + column.in_(someselect) can now be used as + a columns-clause expression without the subquery + bleeding into the FROM clause + + .. change:: + :tags: mysql + :tickets: 1146 + + Added MSMediumInteger type. + + .. change:: + :tags: sqlite + :tickets: 968 + + Supplied a custom strftime() function which + handles dates before 1900. + + .. change:: + :tags: sqlite + :tickets: + + String's (and Unicode's, UnicodeText's, etc.) + convert_unicode logic disabled in the sqlite dialect, + to adjust for pysqlite 2.5.0's new requirement that + only Python unicode objects are accepted; + http://itsystementwicklung.de/pipermail/list-pysqlite/2008-March/000018.html + + .. change:: + :tags: oracle + :tickets: 1155 + + has_sequence() now takes schema name into account + + .. change:: + :tags: oracle + :tickets: 1121 + + added BFILE to the list of reflected types + +.. changelog:: + :version: 0.4.7p1 + :released: Thu Jul 31 2008 + + .. change:: + :tags: orm + :tickets: + + Added "add()" and "add_all()" to scoped_session + methods. Workaround for 0.4.7: + + from sqlalchemy.orm.scoping import ScopedSession,\ + instrument + setattr( + ScopedSession, "add", instrument("add")) + setattr( + ScopedSession, "add_all", instrument("add_all")) + + .. change:: + :tags: orm + :tickets: + + Fixed non-2.3 compatible usage of set() and generator + expression within relation(). + +.. changelog:: + :version: 0.4.7 + :released: Sat Jul 26 2008 + + .. change:: + :tags: orm + :tickets: 1058 + + The contains() operator when used with many-to-many + will alias() the secondary (association) table so + that multiple contains() calls will not conflict + with each other + + .. change:: + :tags: orm + :tickets: + + fixed bug preventing merge() from functioning in + conjunction with a comparable_property() + + .. change:: + :tags: orm + :tickets: + + the enable_typechecks=False setting on relation() + now only allows subtypes with inheriting mappers. + Totally unrelated types, or subtypes not set up with + mapper inheritance against the target mapper are + still not allowed. + + .. change:: + :tags: orm + :tickets: 976 + + Added is_active flag to Sessions to detect when + a transaction is in progress. This + flag is always True with a "transactional" + (in 0.5 a non-"autocommit") Session. + + .. change:: + :tags: sql + :tickets: + + Fixed bug when calling select([literal('foo')]) + or select([bindparam('foo')]). + + .. change:: + :tags: schema + :tickets: 571 + + create_all(), drop_all(), create(), drop() all raise + an error if the table name or schema name contains + more characters than that dialect's configured + character limit. Some DB's can handle too-long + table names during usage, and SQLA can handle this + as well. But various reflection/ + checkfirst-during-create scenarios fail since we are + looking for the name within the DB's catalog tables. + + .. change:: + :tags: schema + :tickets: 571, 820 + + The index name generated when you say "index=True" + on a Column is truncated to the length appropriate + for the dialect. Additionally, an Index with a too- + long name cannot be explicitly dropped with + Index.drop(), similar to. + + .. change:: + :tags: postgres + :tickets: + + Repaired server_side_cursors to properly detect + text() clauses. + + .. change:: + :tags: postgres + :tickets: 1092 + + Added PGCidr type. + + .. change:: + :tags: mysql + :tickets: + + Added 'CALL' to the list of SQL keywords which return + result rows. + + .. change:: + :tags: oracle + :tickets: + + Oracle get_default_schema_name() "normalizes" the name + before returning, meaning it returns a lower-case name + when the identifier is detected as case insensitive. + + .. change:: + :tags: oracle + :tickets: 709 + + creating/dropping tables takes schema name into account + when searching for the existing table, so that tables + in other owner namespaces with the same name do not + conflict + + .. change:: + :tags: oracle + :tickets: 1062 + + Cursors now have "arraysize" set to 50 by default on + them, the value of which is configurable using the + "arraysize" argument to create_engine() with the + Oracle dialect. This to account for cx_oracle's default + setting of "1", which has the effect of many round trips + being sent to Oracle. This actually works well in + conjunction with BLOB/CLOB-bound cursors, of which + there are any number available but only for the life of + that row request (so BufferedColumnRow is still needed, + but less so). + + .. change:: + :tags: oracle + :tickets: + + sqlite + - add SLFloat type, which matches the SQLite REAL + type affinity. Previously, only SLNumeric was provided + which fulfills NUMERIC affinity, but that's not the + same as REAL. + +.. changelog:: + :version: 0.4.6 + :released: Sat May 10 2008 + + .. change:: + :tags: orm + :tickets: + + Fix to the recent relation() refactoring which fixes + exotic viewonly relations which join between local and + remote table multiple times, with a common column shared + between the joins. + + .. change:: + :tags: orm + :tickets: + + Also re-established viewonly relation() configurations + that join across multiple tables. + + .. change:: + :tags: orm + :tickets: 610 + + Added experimental relation() flag to help with + primaryjoins across functions, etc., + _local_remote_pairs=[tuples]. This complements a complex + primaryjoin condition allowing you to provide the + individual column pairs which comprise the relation's + local and remote sides. Also improved lazy load SQL + generation to handle placing bind params inside of + functions and other expressions. (partial progress + towards) + + .. change:: + :tags: orm + :tickets: 1036 + + repaired single table inheritance such that you + can single-table inherit from a joined-table inherting + mapper without issue. + + .. change:: + :tags: orm + :tickets: 1027 + + Fixed "concatenate tuple" bug which could occur with + Query.order_by() if clause adaption had taken place. + + .. change:: + :tags: orm + :tickets: + + Removed ancient assertion that mapped selectables require + "alias names" - the mapper creates its own alias now if + none is present. Though in this case you need to use the + class, not the mapped selectable, as the source of column + attributes - so a warning is still issued. + + .. change:: + :tags: orm + :tickets: + + fixes to the "exists" function involving inheritance (any(), + has(), ~contains()); the full target join will be rendered + into the EXISTS clause for relations that link to subclasses. + + .. change:: + :tags: orm + :tickets: + + restored usage of append_result() extension method for primary + query rows, when the extension is present and only a single- + entity result is being returned. + + .. change:: + :tags: orm + :tickets: + + Also re-established viewonly relation() configurations that + join across multiple tables. + + .. change:: + :tags: orm + :tickets: + + removed ancient assertion that mapped selectables require + "alias names" - the mapper creates its own alias now if + none is present. Though in this case you need to use + the class, not the mapped selectable, as the source of + column attributes - so a warning is still issued. + + .. change:: + :tags: orm + :tickets: 1015 + + refined mapper._save_obj() which was unnecessarily calling + __ne__() on scalar values during flush + + .. change:: + :tags: orm + :tickets: 1019 + + added a feature to eager loading whereby subqueries set + as column_property() with explicit label names (which is not + necessary, btw) will have the label anonymized when + the instance is part of the eager join, to prevent + conflicts with a subquery or column of the same name + on the parent object. + + .. change:: + :tags: orm + :tickets: + + set-based collections |=, -=, ^= and &= are stricter about + their operands and only operate on sets, frozensets or + subclasses of the collection type. Previously, they would + accept any duck-typed set. + + .. change:: + :tags: orm + :tickets: + + added an example dynamic_dict/dynamic_dict.py, illustrating + a simple way to place dictionary behavior on top of + a dynamic_loader. + + .. change:: + :tags: declarative, extension + :tickets: + + Joined table inheritance mappers use a slightly relaxed + function to create the "inherit condition" to the parent + table, so that other foreign keys to not-yet-declared + Table objects don't trigger an error. + + .. change:: + :tags: declarative, extension + :tickets: + + fixed reentrant mapper compile hang when + a declared attribute is used within ForeignKey, + ie. ForeignKey(MyOtherClass.someattribute) + + .. change:: + :tags: sql + :tickets: + + Added COLLATE support via the .collate() + expression operator and collate(, ) sql + function. + + .. change:: + :tags: sql + :tickets: + + Fixed bug with union() when applied to non-Table connected + select statements + + .. change:: + :tags: sql + :tickets: 1014 + + improved behavior of text() expressions when used as + FROM clauses, such as select().select_from(text("sometext")) + + .. change:: + :tags: sql + :tickets: 1021 + + Column.copy() respects the value of "autoincrement", + fixes usage with Migrate + + .. change:: + :tags: engines + :tickets: + + Pool listeners can now be provided as a dictionary of + callables or a (possibly partial) duck-type of + PoolListener, your choice. + + .. change:: + :tags: engines + :tickets: + + added "rollback_returned" option to Pool which will + disable the rollback() issued when connections are + returned. This flag is only safe to use with a database + which does not support transactions (i.e. MySQL/MyISAM). + + .. change:: + :tags: ext + :tickets: + + set-based association proxies |=, -=, ^= and &= are + stricter about their operands and only operate on sets, + frozensets or other association proxies. Previously, they + would accept any duck-typed set. + + .. change:: + :tags: mssql + :tickets: 1005 + + Added "odbc_autotranslate" parameter to engine / dburi + parameters. Any given string will be passed through to the + ODBC connection string as: + + "AutoTranslate=%s" % odbc_autotranslate + + .. change:: + :tags: mssql + :tickets: + + Added "odbc_options" parameter to engine / dburi + parameters. The given string is simply appended to the + SQLAlchemy-generated odbc connection string. + + This should obviate the need of adding a myriad of ODBC + options in the future. + + .. change:: + :tags: firebird + :tickets: + + Handle the "SUBSTRING(:string FROM :start FOR :length)" + builtin. + +.. changelog:: + :version: 0.4.5 + :released: Fri Apr 04 2008 + + .. change:: + :tags: orm + :tickets: + + A small change in behavior to session.merge() - existing + objects are checked for based on primary key attributes, not + necessarily _instance_key. So the widely requested + capability, that: + + x = MyObject(id=1) + x = sess.merge(x) + + will in fact load MyObject with id #1 from the database if + present, is now available. merge() still copies the state + of the given object to the persistent one, so an example + like the above would typically have copied "None" from all + attributes of "x" onto the persistent copy. These can be + reverted using session.expire(x). + + .. change:: + :tags: orm + :tickets: + + Also fixed behavior in merge() whereby collection elements + present on the destination but not the merged collection + were not being removed from the destination. + + .. change:: + :tags: orm + :tickets: 995 + + Added a more aggressive check for "uncompiled mappers", + helps particularly with declarative layer + + .. change:: + :tags: orm + :tickets: + + The methodology behind "primaryjoin"/"secondaryjoin" has + been refactored. Behavior should be slightly more + intelligent, primarily in terms of error messages which + have been pared down to be more readable. In a slight + number of scenarios it can better resolve the correct + foreign key than before. + + .. change:: + :tags: orm + :tickets: + + Added comparable_property(), adds query Comparator + behavior to regular, unmanaged Python properties + + .. change:: + :tags: orm, Company.employees.of_type(Engineer), 'machines' + :tickets: + + the functionality of query.with_polymorphic() has + been added to mapper() as a configuration option. + + It's set via several forms: + with_polymorphic='*' + with_polymorphic=[mappers] + with_polymorphic=('*', selectable) + with_polymorphic=([mappers], selectable) + + This controls the default polymorphic loading strategy + for inherited mappers. When a selectable is not given, + outer joins are created for all joined-table inheriting + mappers requested. Note that the auto-create of joins + is not compatible with concrete table inheritance. + + The existing select_table flag on mapper() is now + deprecated and is synonymous with + with_polymorphic('*', select_table). Note that the + underlying "guts" of select_table have been + completely removed and replaced with the newer, + more flexible approach. + + The new approach also automatically allows eager loads + to work for subclasses, if they are present, for + example + sess.query(Company).options( + eagerload_all( + + )) + to load Company objects, their employees, and the + 'machines' collection of employees who happen to be + Engineers. A "with_polymorphic" Query option should be + introduced soon as well which would allow per-Query + control of with_polymorphic() on relations. + + .. change:: + :tags: orm + :tickets: + + added two "experimental" features to Query, + "experimental" in that their specific name/behavior + is not carved in stone just yet: _values() and + _from_self(). We'd like feedback on these. + + - _values(*columns) is given a list of column + expressions, and returns a new Query that only + returns those columns. When evaluated, the return + value is a list of tuples just like when using + add_column() or add_entity(), the only difference is + that "entity zero", i.e. the mapped class, is not + included in the results. This means it finally makes + sense to use group_by() and having() on Query, which + have been sitting around uselessly until now. + + A future change to this method may include that its + ability to join, filter and allow other options not + related to a "resultset" are removed, so the feedback + we're looking for is how people want to use + _values()...i.e. at the very end, or do people prefer + to continue generating after it's called. + + - _from_self() compiles the SELECT statement for the + Query (minus any eager loaders), and returns a new + Query that selects from that SELECT. So basically you + can query from a Query without needing to extract the + SELECT statement manually. This gives meaning to + operations like query[3:5]._from_self().filter(some + criterion). There's not much controversial here + except that you can quickly create highly nested + queries that are less efficient, and we want feedback + on the naming choice. + + .. change:: + :tags: orm + :tickets: + + query.order_by() and query.group_by() will accept + multiple arguments using *args (like select() + already does). + + .. change:: + :tags: orm + :tickets: + + Added some convenience descriptors to Query: + query.statement returns the full SELECT construct, + query.whereclause returns just the WHERE part of the + SELECT construct. + + .. change:: + :tags: orm + :tickets: + + Fixed/covered case when using a False/0 value as a + polymorphic discriminator. + + .. change:: + :tags: orm + :tickets: + + Fixed bug which was preventing synonym() attributes from + being used with inheritance + + .. change:: + :tags: orm + :tickets: 996 + + Fixed SQL function truncation of trailing underscores + + .. change:: + :tags: orm + :tickets: + + When attributes are expired on a pending instance, an + error will not be raised when the "refresh" action is + triggered and no result is found. + + .. change:: + :tags: orm + :tickets: + + Session.execute can now find binds from metadata + + .. change:: + :tags: orm + :tickets: + + Adjusted the definition of "self-referential" to be any + two mappers with a common parent (this affects whether or + not aliased=True is required when joining with Query). + + .. change:: + :tags: orm + :tickets: + + Made some fixes to the "from_joinpoint" argument to + query.join() so that if the previous join was aliased and + this one isn't, the join still happens successfully. + + .. change:: + :tags: orm + :tickets: 895 + + Assorted "cascade deletes" fixes: + - Fixed "cascade delete" operation of dynamic relations, + which had only been implemented for foreign-key + nulling behavior in 0.4.2 and not actual cascading + deletes + + - Delete cascade without delete-orphan cascade on a + many-to-one will not delete orphans which were + disconnected from the parent before session.delete() + is called on the parent (one-to-many already had + this). + + - Delete cascade with delete-orphan will delete orphans + whether or not it remains attached to its also-deleted + parent. + + - delete-orphan casacde is properly detected on relations + that are present on superclasses when using inheritance. + + .. change:: + :tags: orm + :tickets: + + Fixed order_by calculation in Query to properly alias + mapper-config'ed order_by when using select_from() + + .. change:: + :tags: orm + :tickets: + + Refactored the diffing logic that kicks in when replacing + one collection with another into collections.bulk_replace, + useful to anyone building multi-level collections. + + .. change:: + :tags: orm + :tickets: + + Cascade traversal algorithm converted from recursive to + iterative to support deep object graphs. + + .. change:: + :tags: sql + :tickets: 999 + + schema-qualified tables now will place the schemaname + ahead of the tablename in all column expressions as well + as when generating column labels. This prevents cross- + schema name collisions in all cases + + .. change:: + :tags: sql + :tickets: + + can now allow selects which correlate all FROM clauses + and have no FROM themselves. These are typically + used in a scalar context, i.e. SELECT x, (SELECT x WHERE y) + FROM table. Requires explicit correlate() call. + + .. change:: + :tags: sql + :tickets: + + 'name' is no longer a required constructor argument for + Column(). It (and .key) may now be deferred until the + column is added to a Table. + + .. change:: + :tags: sql + :tickets: 791, 993 + + like(), ilike(), contains(), startswith(), endswith() take + an optional keyword argument "escape=", which + is set as the escape character using the syntax "x LIKE y + ESCAPE ''". + + .. change:: + :tags: sql + :tickets: + + random() is now a generic sql function and will compile to + the database's random implementation, if any. + + .. change:: + :tags: sql + :tickets: + + update().values() and insert().values() take keyword + arguments. + + .. change:: + :tags: sql + :tickets: + + Fixed an issue in select() regarding its generation of + FROM clauses, in rare circumstances two clauses could be + produced when one was intended to cancel out the other. + Some ORM queries with lots of eager loads might have seen + this symptom. + + .. change:: + :tags: sql + :tickets: + + The case() function now also takes a dictionary as its + whens parameter. It also interprets the "THEN" + expressions as values by default, meaning case([(x==y, + "foo")]) will interpret "foo" as a bound value, not a SQL + expression. use text(expr) for literal SQL expressions in + this case. For the criterion itself, these may be literal + strings only if the "value" keyword is present, otherwise + SA will force explicit usage of either text() or + literal(). + + .. change:: + :tags: oracle + :tickets: + + The "owner" keyword on Table is now deprecated, and is + exactly synonymous with the "schema" keyword. Tables can + now be reflected with alternate "owner" attributes, + explicitly stated on the Table object or not using + "schema". + + .. change:: + :tags: oracle + :tickets: + + All of the "magic" searching for synonyms, DBLINKs etc. + during table reflection are disabled by default unless you + specify "oracle_resolve_synonyms=True" on the Table + object. Resolving synonyms necessarily leads to some + messy guessing which we'd rather leave off by default. + When the flag is set, tables and related tables will be + resolved against synonyms in all cases, meaning if a + synonym exists for a particular table, reflection will use + it when reflecting related tables. This is stickier + behavior than before which is why it's off by default. + + .. change:: + :tags: declarative, extension + :tickets: + + The "synonym" function is now directly usable with + "declarative". Pass in the decorated property using the + "descriptor" keyword argument, e.g.: somekey = + synonym('_somekey', descriptor=property(g, s)) + + .. change:: + :tags: declarative, extension + :tickets: + + The "deferred" function is usable with "declarative". + Simplest usage is to declare deferred and Column together, + e.g.: data = deferred(Column(Text)) + + .. change:: + :tags: declarative, extension + :tickets: + + Declarative also gained @synonym_for(...) and + @comparable_using(...), front-ends for synonym and + comparable_property. + + .. change:: + :tags: declarative, extension + :tickets: 995 + + Improvements to mapper compilation when using declarative; + already-compiled mappers will still trigger compiles of + other uncompiled mappers when used + + .. change:: + :tags: declarative, extension + :tickets: + + Declarative will complete setup for Columns lacking names, + allows a more DRY syntax. + + class Foo(Base): + __tablename__ = 'foos' + id = Column(Integer, primary_key=True) + + .. change:: + :tags: declarative, extension + :tickets: + + inheritance in declarative can be disabled when sending + "inherits=None" to __mapper_args__. + + .. change:: + :tags: declarative, extension + :tickets: + + declarative_base() takes optional kwarg "mapper", which + is any callable/class/method that produces a mapper, + such as declarative_base(mapper=scopedsession.mapper). + This property can also be set on individual declarative + classes using the "__mapper_cls__" property. + + .. change:: + :tags: postgres + :tickets: 1001 + + Got PG server side cursors back into shape, added fixed + unit tests as part of the default test suite. Added + better uniqueness to the cursor ID + + .. change:: + :tags: oracle + :tickets: + + The "owner" keyword on Table is now deprecated, and is + exactly synonymous with the "schema" keyword. Tables can + now be reflected with alternate "owner" attributes, + explicitly stated on the Table object or not using + "schema". + + .. change:: + :tags: oracle + :tickets: + + All of the "magic" searching for synonyms, DBLINKs etc. + during table reflection are disabled by default unless you + specify "oracle_resolve_synonyms=True" on the Table + object. Resolving synonyms necessarily leads to some + messy guessing which we'd rather leave off by default. + When the flag is set, tables and related tables will be + resolved against synonyms in all cases, meaning if a + synonym exists for a particular table, reflection will use + it when reflecting related tables. This is stickier + behavior than before which is why it's off by default. + + .. change:: + :tags: mssql + :tickets: 979 + + Reflected tables will now automatically load other tables + which are referenced by Foreign keys in the auto-loaded + table,. + + .. change:: + :tags: mssql + :tickets: 916 + + Added executemany check to skip identity fetch,. + + .. change:: + :tags: mssql + :tickets: 884 + + Added stubs for small date type. + + .. change:: + :tags: mssql + :tickets: + + Added a new 'driver' keyword parameter for the pyodbc dialect. + Will substitute into the ODBC connection string if given, + defaults to 'SQL Server'. + + .. change:: + :tags: mssql + :tickets: + + Added a new 'max_identifier_length' keyword parameter for + the pyodbc dialect. + + .. change:: + :tags: mssql + :tickets: + + Improvements to pyodbc + Unix. If you couldn't get that + combination to work before, please try again. + + .. change:: + :tags: mysql + :tickets: + + The connection.info keys the dialect uses to cache server + settings have changed and are now namespaced. + +.. changelog:: + :version: 0.4.4 + :released: Wed Mar 12 2008 + + .. change:: + :tags: sql + :tickets: 975 + + Can again create aliases of selects against textual FROM + clauses. + + .. change:: + :tags: sql + :tickets: + + The value of a bindparam() can be a callable, in which + case it's evaluated at statement execution time to get the + value. + + .. change:: + :tags: sql + :tickets: 978 + + Added exception wrapping/reconnect support to result set + fetching. Reconnect works for those databases that raise + a catchable data error during results (i.e. doesn't work + on MySQL) + + .. change:: + :tags: sql + :tickets: 936 + + Implemented two-phase API for "threadlocal" engine, via + engine.begin_twophase(), engine.prepare() + + .. change:: + :tags: sql + :tickets: 986 + + Fixed bug which was preventing UNIONS from being + cloneable. + + .. change:: + :tags: sql + :tickets: + + Added "bind" keyword argument to insert(), update(), + delete() and DDL(). The .bind property is now assignable + on those statements as well as on select(). + + .. change:: + :tags: sql + :tickets: + + Insert statements can now be compiled with extra "prefix" + words between INSERT and INTO, for vendor extensions like + MySQL's INSERT IGNORE INTO table. + + .. change:: + :tags: orm + :tickets: + + any(), has(), contains(), ~contains(), attribute level == + and != now work properly with self-referential relations - + the clause inside the EXISTS is aliased on the "remote" + side to distinguish it from the parent table. This + applies to single table self-referential as well as + inheritance-based self-referential. + + .. change:: + :tags: orm + :tickets: 985 + + Repaired behavior of == and != operators at the relation() + level when compared against NULL for one-to-one relations + + .. change:: + :tags: orm + :tickets: + + Fixed bug whereby session.expire() attributes were not + loading on an polymorphically-mapped instance mapped by a + select_table mapper. + + .. change:: + :tags: orm + :tickets: + + Added query.with_polymorphic() - specifies a list of + classes which descend from the base class, which will be + added to the FROM clause of the query. Allows subclasses + to be used within filter() criterion as well as eagerly + loads the attributes of those subclasses. + + .. change:: + :tags: orm + :tickets: + + Your cries have been heard: removing a pending item from + an attribute or collection with delete-orphan expunges the + item from the session; no FlushError is raised. Note that + if you session.save()'ed the pending item explicitly, the + attribute/collection removal still knocks it out. + + .. change:: + :tags: orm + :tickets: + + session.refresh() and session.expire() raise an error when + called on instances which are not persistent within the + session + + .. change:: + :tags: orm + :tickets: + + Fixed potential generative bug when the same Query was + used to generate multiple Query objects using join(). + + .. change:: + :tags: orm + :tickets: + + Fixed bug which was introduced in 0.4.3, whereby loading + an already-persistent instance mapped with joined table + inheritance would trigger a useless "secondary" load from + its joined table, when using the default "select" + polymorphic_fetch. This was due to attributes being + marked as expired during its first load and not getting + unmarked from the previous "secondary" load. Attributes + are now unexpired based on presence in __dict__ after any + load or commit operation succeeds. + + .. change:: + :tags: orm + :tickets: + + Deprecated Query methods apply_sum(), apply_max(), + apply_min(), apply_avg(). Better methodologies are + coming.... + + .. change:: + :tags: orm + :tickets: + + relation() can accept a callable for its first argument, + which returns the class to be related. This is in place + to assist declarative packages to define relations without + classes yet being in place. + + .. change:: + :tags: orm + :tickets: + + Added a new "higher level" operator called "of_type()": + used in join() as well as with any() and has(), qualifies + the subclass which will be used in filter criterion, e.g.: + + query.filter(Company.employees.of_type(Engineer). + any(Engineer.name=='foo')) + + or + + query.join(Company.employees.of_type(Engineer)). + filter(Engineer.name=='foo') + + .. change:: + :tags: orm + :tickets: + + Preventive code against a potential lost-reference bug in + flush(). + + .. change:: + :tags: orm + :tickets: + + Expressions used in filter(), filter_by() and others, when + they make usage of a clause generated from a relation + using the identity of a child object (e.g., + filter(Parent.child==)), evaluate the actual + primary key value of at execution time so that + the autoflush step of the Query can complete, thereby + populating the PK value of in the case that + was pending. + + .. change:: + :tags: orm + :tickets: + + setting the relation()-level order by to a column in the + many-to-many "secondary" table will now work with eager + loading, previously the "order by" wasn't aliased against + the secondary table's alias. + + .. change:: + :tags: orm + :tickets: + + Synonyms riding on top of existing descriptors are now + full proxies to those descriptors. + + .. change:: + :tags: dialects + :tickets: + + Invalid SQLite connection URLs now raise an error. + + .. change:: + :tags: dialects + :tickets: 981 + + postgres TIMESTAMP renders correctly + + .. change:: + :tags: dialects + :tickets: + + postgres PGArray is a "mutable" type by default; when used + with the ORM, mutable-style equality/ copy-on-write + techniques are used to test for changes. + + .. change:: + :tags: extensions + :tickets: + + a new super-small "declarative" extension has been added, + which allows Table and mapper() configuration to take + place inline underneath a class declaration. This + extension differs from ActiveMapper and Elixir in that it + does not redefine any SQLAlchemy semantics at all; literal + Column, Table and relation() constructs are used to define + the class behavior and table definition. + +.. changelog:: + :version: 0.4.3 + :released: Thu Feb 14 2008 + + .. change:: + :tags: sql + :tickets: + + Added "schema.DDL", an executable free-form DDL statement. + DDLs can be executed in isolation or attached to Table or + MetaData instances and executed automatically when those + objects are created and/or dropped. + + .. change:: + :tags: sql + :tickets: + + Table columns and constraints can be overridden on a an + existing table (such as a table that was already reflected) + using the 'useexisting=True' flag, which now takes into + account the arguments passed along with it. + + .. change:: + :tags: sql + :tickets: + + Added a callable-based DDL events interface, adds hooks + before and after Tables and MetaData create and drop. + + .. change:: + :tags: sql + :tickets: + + Added generative where() method to delete() and + update() constructs which return a new object with criterion + joined to existing criterion via AND, just like + select().where(). + + .. change:: + :tags: sql + :tickets: 727 + + Added "ilike()" operator to column operations. Compiles to + ILIKE on postgres, lower(x) LIKE lower(y) on all + others. + + .. change:: + :tags: sql + :tickets: 943 + + Added "now()" as a generic function; on SQLite, Oracle + and MSSQL compiles as "CURRENT_TIMESTAMP"; "now()" on + all others. + + .. change:: + :tags: sql + :tickets: 962 + + The startswith(), endswith(), and contains() operators now + concatenate the wildcard operator with the given operand in + SQL, i.e. "'%' || " in all cases, accept + text('something') operands properly + + .. change:: + :tags: sql + :tickets: 962 + + cast() accepts text('something') and other non-literal + operands properly + + .. change:: + :tags: sql + :tickets: + + fixed bug in result proxy where anonymously generated + column labels would not be accessible using their straight + string name + + .. change:: + :tags: sql + :tickets: + + Deferrable constraints can now be defined. + + .. change:: + :tags: sql + :tickets: 915 + + Added "autocommit=True" keyword argument to select() and + text(), as well as generative autocommit() method on + select(); for statements which modify the database through + some user-defined means other than the usual INSERT/UPDATE/ + DELETE etc. This flag will enable "autocommit" behavior + during execution if no transaction is in progress. + + .. change:: + :tags: sql + :tickets: + + The '.c.' attribute on a selectable now gets an entry for + every column expression in its columns clause. Previously, + "unnamed" columns like functions and CASE statements weren't + getting put there. Now they will, using their full string + representation if no 'name' is available. + + .. change:: + :tags: sql + :tickets: + + a CompositeSelect, i.e. any union(), union_all(), + intersect(), etc. now asserts that each selectable contains + the same number of columns. This conforms to the + corresponding SQL requirement. + + .. change:: + :tags: sql + :tickets: + + The anonymous 'label' generated for otherwise unlabeled + functions and expressions now propagates outwards at compile + time for expressions like select([select([func.foo()])]). + + .. change:: + :tags: sql + :tickets: + + Building on the above ideas, CompositeSelects now build up + their ".c." collection based on the names present in the + first selectable only; corresponding_column() now works + fully for all embedded selectables. + + .. change:: + :tags: sql + :tickets: + + Oracle and others properly encode SQL used for defaults like + sequences, etc., even if no unicode idents are used since + identifier preparer may return a cached unicode identifier. + + .. change:: + :tags: sql + :tickets: + + Column and clause comparisons to datetime objects on the + left hand side of the expression now work (d < table.c.col). + (datetimes on the RHS have always worked, the LHS exception + is a quirk of the datetime implementation.) + + .. change:: + :tags: orm + :tickets: + + Every Session.begin() must now be accompanied by a + corresponding commit() or rollback() unless the session is + closed with Session.close(). This also includes the begin() + which is implicit to a session created with + transactional=True. The biggest change introduced here is + that when a Session created with transactional=True raises + an exception during flush(), you must call + Session.rollback() or Session.close() in order for that + Session to continue after an exception. + + .. change:: + :tags: orm + :tickets: 961 + + Fixed merge() collection-doubling bug when merging transient + entities with backref'ed collections. + + .. change:: + :tags: orm + :tickets: + + merge(dont_load=True) does not accept transient entities, + this is in continuation with the fact that + merge(dont_load=True) does not accept any "dirty" objects + either. + + .. change:: + :tags: orm + :tickets: + + Added standalone "query" class attribute generated by a + scoped_session. This provides MyClass.query without using + Session.mapper. Use via: + + MyClass.query = Session.query_property() + + .. change:: + :tags: orm + :tickets: + + The proper error message is raised when trying to access + expired instance attributes with no session present + + .. change:: + :tags: orm + :tickets: + + dynamic_loader() / lazy="dynamic" now accepts and uses + the order_by parameter in the same way in which it works + with relation(). + + .. change:: + :tags: orm + :tickets: + + Added expire_all() method to Session. Calls expire() for + all persistent instances. This is handy in conjunction + with... + + .. change:: + :tags: orm + :tickets: + + Instances which have been partially or fully expired will + have their expired attributes populated during a regular + Query operation which affects those objects, preventing a + needless second SQL statement for each instance. + + .. change:: + :tags: orm + :tickets: 938 + + Dynamic relations, when referenced, create a strong + reference to the parent object so that the query still has a + parent to call against even if the parent is only created + (and otherwise dereferenced) within the scope of a single + expression. + + .. change:: + :tags: orm + :tickets: + + Added a mapper() flag "eager_defaults". When set to True, + defaults that are generated during an INSERT or UPDATE + operation are post-fetched immediately, instead of being + deferred until later. This mimics the old 0.3 behavior. + + .. change:: + :tags: orm + :tickets: + + query.join() can now accept class-mapped attributes as + arguments. These can be used in place or in any combination + with strings. In particular this allows construction of + joins to subclasses on a polymorphic relation, i.e.: + + query(Company).join(['employees', Engineer.name]) + + .. change:: + :tags: orm, ('employees', people.join(engineer)), Engineer.name + :tickets: + + query.join() can also accept tuples of attribute name/some + selectable as arguments. This allows construction of joins + *from* subclasses of a polymorphic relation, i.e.: + + query(Company).\ + join( + + ) + + .. change:: + :tags: orm + :tickets: + + General improvements to the behavior of join() in + conjunction with polymorphic mappers, i.e. joining from/to + polymorphic mappers and properly applying aliases. + + .. change:: + :tags: orm + :tickets: 933 + + Fixed/improved behavior when a mapper determines the natural + "primary key" of a mapped join, it will more effectively + reduce columns which are equivalent via foreign key + relation. This affects how many arguments need to be sent + to query.get(), among other things. + + .. change:: + :tags: orm + :tickets: 946 + + The lazy loader can now handle a join condition where the + "bound" column (i.e. the one that gets the parent id sent as + a bind parameter) appears more than once in the join + condition. Specifically this allows the common task of a + relation() which contains a parent-correlated subquery, such + as "select only the most recent child item". + + .. change:: + :tags: orm + :tickets: + + Fixed bug in polymorphic inheritance where an incorrect + exception is raised when base polymorphic_on column does not + correspond to any columns within the local selectable of an + inheriting mapper more than one level deep + + .. change:: + :tags: orm + :tickets: + + Fixed bug in polymorphic inheritance which made it difficult + to set a working "order_by" on a polymorphic mapper. + + .. change:: + :tags: orm + :tickets: + + Fixed a rather expensive call in Query that was slowing down + polymorphic queries. + + .. change:: + :tags: orm + :tickets: 954 + + "Passive defaults" and other "inline" defaults can now be + loaded during a flush() call if needed; in particular, this + allows constructing relations() where a foreign key column + references a server-side-generated, non-primary-key + column. + + .. change:: + :tags: orm + :tickets: + + Additional Session transaction fixes/changes: + - Fixed bug with session transaction management: parent + transactions weren't started on the connection when + adding a connection to a nested transaction. + + - session.transaction now always refers to the innermost + active transaction, even when commit/rollback are called + directly on the session transaction object. + + - Two-phase transactions can now be prepared. + + - When preparing a two-phase transaction fails on one + connection, all the connections are rolled back. + + - session.close() didn't close all transactions when + nested transactions were used. + + - rollback() previously erroneously set the current + transaction directly to the parent of the transaction + that could be rolled back to. Now it rolls back the next + transaction up that can handle it, but sets the current + transaction to it's parent and inactivates the + transactions in between. Inactive transactions can only + be rolled back or closed, any other call results in an + error. + + - autoflush for commit() wasn't flushing for simple + subtransactions. + + - unitofwork flush didn't close the failed transaction + when the session was not in a transaction and commiting + the transaction failed. + + .. change:: + :tags: orm + :tickets: 964, 940 + + Miscellaneous tickets: + + .. change:: + :tags: general + :tickets: + + Fixed a variety of hidden and some not-so-hidden + compatibility issues for Python 2.3, thanks to new support + for running the full test suite on 2.3. + + .. change:: + :tags: general + :tickets: + + Warnings are now issued as type exceptions.SAWarning. + + .. change:: + :tags: dialects + :tickets: + + Better support for schemas in SQLite (linked in by ATTACH + DATABASE ... AS name). In some cases in the past, schema + names were ommitted from generated SQL for SQLite. This is + no longer the case. + + .. change:: + :tags: dialects + :tickets: + + table_names on SQLite now picks up temporary tables as well. + + .. change:: + :tags: dialects + :tickets: + + Auto-detect an unspecified MySQL ANSI_QUOTES mode during + reflection operations, support for changing the mode + midstream. Manual mode setting is still required if no + reflection is used. + + .. change:: + :tags: dialects + :tickets: + + Fixed reflection of TIME columns on SQLite. + + .. change:: + :tags: dialects + :tickets: 580 + + Finally added PGMacAddr type to postgres + + .. change:: + :tags: dialects + :tickets: + + Reflect the sequence associated to a PK field (typically + with a BEFORE INSERT trigger) under Firebird + + .. change:: + :tags: dialects + :tickets: 941 + + Oracle assembles the correct columns in the result set + column mapping when generating a LIMIT/OFFSET subquery, + allows columns to map properly to result sets even if + long-name truncation kicks in + + .. change:: + :tags: dialects + :tickets: + + MSSQL now includes EXEC in the _is_select regexp, which + should allow row-returning stored procedures to be used. + + .. change:: + :tags: dialects + :tickets: + + MSSQL now includes an experimental implementation of + LIMIT/OFFSET using the ANSI SQL row_number() function, so it + requires MSSQL-2005 or higher. To enable the feature, add + "has_window_funcs" to the keyword arguments for connect, or + add "?has_window_funcs=1" to your dburi query arguments. + + .. change:: + :tags: ext + :tickets: + + Changed ext.activemapper to use a non-transactional session + for the objectstore. + + .. change:: + :tags: ext + :tickets: + + Fixed output order of "['a'] + obj.proxied" binary operation + on association-proxied lists. + +.. changelog:: + :version: 0.4.2p3 + :released: Wed Jan 09 2008 + + .. change:: + :tags: general + :tickets: + + sub version numbering scheme changed to suite + setuptools version number rules; easy_install -u + should now get this version over 0.4.2. + + .. change:: + :tags: sql + :tickets: 912 + + Text type is properly exported now and does not + raise a warning on DDL create; String types with no + length only raise warnings during CREATE TABLE + + .. change:: + :tags: sql + :tickets: + + new UnicodeText type is added, to specify an + encoded, unlengthed Text type + + .. change:: + :tags: sql + :tickets: + + fixed bug in union() so that select() statements + which don't derive from FromClause objects can be + unioned + + .. change:: + :tags: orm + :tickets: + + fixed bug with session.dirty when using "mutable + scalars" (such as PickleTypes) + + .. change:: + :tags: orm + :tickets: + + added a more descriptive error message when flushing + on a relation() that has non-locally-mapped columns + in its primary or secondary join condition + + .. change:: + :tags: dialects + :tickets: + + Fixed reflection of mysql empty string column + defaults. + + .. change:: + :tags: sql + :tickets: 912 + + changed name of TEXT to Text since its a "generic" + type; TEXT name is deprecated until 0.5. The + "upgrading" behavior of String to Text when no + length is present is also deprecated until 0.5; will + issue a warning when used for CREATE TABLE + statements (String with no length for SQL expression + purposes is still fine) + + .. change:: + :tags: sql + :tickets: 924 + + generative select.order_by(None) / group_by(None) + was not managing to reset order by/group by + criterion, fixed + + .. change:: + :tags: orm + :tickets: + + suppressing *all* errors in + InstanceState.__cleanup() now. + + .. change:: + :tags: orm + :tickets: 922 + + fixed an attribute history bug whereby assigning a + new collection to a collection-based attribute which + already had pending changes would generate incorrect + history + + .. change:: + :tags: orm + :tickets: 925 + + fixed delete-orphan cascade bug whereby setting the + same object twice to a scalar attribute could log it + as an orphan + + .. change:: + :tags: orm + :tickets: + + Fixed cascades on a += assignment to a list-based + relation. + + .. change:: + :tags: orm + :tickets: 919 + + synonyms can now be created against props that don't + exist yet, which are later added via add_property(). + This commonly includes backrefs. (i.e. you can make + synonyms for backrefs without worrying about the + order of operations) + + .. change:: + :tags: orm + :tickets: + + fixed bug which could occur with polymorphic "union" + mapper which falls back to "deferred" loading of + inheriting tables + + .. change:: + :tags: orm + :tickets: + + the "columns" collection on a mapper/mapped class + (i.e. 'c') is against the mapped table, not the + select_table in the case of polymorphic "union" + loading (this shouldn't be noticeable). + + .. change:: + :tags: ext + :tickets: + + '+', '*', '+=' and '*=' support for association + proxied lists. + + .. change:: + :tags: dialects + :tickets: 923 + + mssql - narrowed down the test for "date"/"datetime" + in MSDate/ MSDateTime subclasses so that incoming + "datetime" objects don't get mis-interpreted as + "date" objects and vice versa. + + .. change:: + :tags: orm + :tickets: + + fixed fairly critical bug whereby the same instance could be listed + more than once in the unitofwork.new collection; most typically + reproduced when using a combination of inheriting mappers and + ScopedSession.mapper, as the multiple __init__ calls per instance + could save() the object with distinct _state objects + + .. change:: + :tags: orm + :tickets: + + added very rudimentary yielding iterator behavior to Query. Call + query.yield_per() and evaluate the Query in an + iterative context; every collection of N rows will be packaged up + and yielded. Use this method with extreme caution since it does + not attempt to reconcile eagerly loaded collections across + result batch boundaries, nor will it behave nicely if the same + instance occurs in more than one batch. This means that an eagerly + loaded collection will get cleared out if it's referenced in more than + one batch, and in all cases attributes will be overwritten on instances + that occur in more than one batch. + + .. change:: + :tags: orm + :tickets: 920 + + Fixed in-place set mutation operators for set collections and association + proxied sets. + + .. change:: + :tags: dialects + :tickets: 913 + + Fixed the missing call to subtype result processor for the PGArray + type. + +.. changelog:: + :version: 0.4.2 + :released: Wed Jan 02 2008 + + .. change:: + :tags: sql + :tickets: 615 + + generic functions ! we introduce a database of known SQL functions, such + as current_timestamp, coalesce, and create explicit function objects + representing them. These objects have constrained argument lists, are + type aware, and can compile in a dialect-specific fashion. So saying + func.char_length("foo", "bar") raises an error (too many args), + func.coalesce(datetime.date(2007, 10, 5), datetime.date(2005, 10, 15)) + knows that its return type is a Date. We only have a few functions + represented so far but will continue to add to the system + + .. change:: + :tags: sql + :tickets: + + auto-reconnect support improved; a Connection can now automatically + reconnect after its underlying connection is invalidated, without + needing to connect() again from the engine. This allows an ORM session + bound to a single Connection to not need a reconnect. + Open transactions on the Connection must be rolled back after an invalidation + of the underlying connection else an error is raised. Also fixed + bug where disconnect detect was not being called for cursor(), rollback(), + or commit(). + + .. change:: + :tags: sql + :tickets: + + added new flag to String and create_engine(), + assert_unicode=(True|False|'warn'|None). Defaults to `False` or `None` on + create_engine() and String, `'warn'` on the Unicode type. When `True`, + results in all unicode conversion operations raising an exception when a + non-unicode bytestring is passed as a bind parameter. 'warn' results + in a warning. It is strongly advised that all unicode-aware applications + make proper use of Python unicode objects (i.e. u'hello' and not 'hello') + so that data round trips accurately. + + .. change:: + :tags: sql + :tickets: + + generation of "unique" bind parameters has been simplified to use the same + "unique identifier" mechanisms as everything else. This doesn't affect + user code, except any code that might have been hardcoded against the generated + names. Generated bind params now have the form "_", + whereas before only the second bind of the same name would have this form. + + .. change:: + :tags: sql + :tickets: + + select().as_scalar() will raise an exception if the select does not have + exactly one expression in its columns clause. + + .. change:: + :tags: sql + :tickets: + + bindparam() objects themselves can be used as keys for execute(), i.e. + statement.execute({bind1:'foo', bind2:'bar'}) + + .. change:: + :tags: sql + :tickets: + + added new methods to TypeDecorator, process_bind_param() and + process_result_value(), which automatically take advantage of the processing + of the underlying type. Ideal for using with Unicode or Pickletype. + TypeDecorator should now be the primary way to augment the behavior of any + existing type including other TypeDecorator subclasses such as PickleType. + + .. change:: + :tags: sql + :tickets: + + selectables (and others) will issue a warning when two columns in + their exported columns collection conflict based on name. + + .. change:: + :tags: sql + :tickets: 890 + + tables with schemas can still be used in sqlite, firebird, + schema name just gets dropped + + .. change:: + :tags: sql + :tickets: + + changed the various "literal" generation functions to use an anonymous + bind parameter. not much changes here except their labels now look + like ":param_1", ":param_2" instead of ":literal" + + .. change:: + :tags: sql + :tickets: + + column labels in the form "tablename.columname", i.e. with a dot, are now + supported. + + .. change:: + :tags: sql + :tickets: + + from_obj keyword argument to select() can be a scalar or a list. + + .. change:: + :tags: orm + :tickets: 871 + + a major behavioral change to collection-based backrefs: they no + longer trigger lazy loads ! "reverse" adds and removes + are queued up and are merged with the collection when it is + actually read from and loaded; but do not trigger a load beforehand. + For users who have noticed this behavior, this should be much more + convenient than using dynamic relations in some cases; for those who + have not, you might notice your apps using a lot fewer queries than + before in some situations. + + .. change:: + :tags: orm + :tickets: + + mutable primary key support is added. primary key columns can be + changed freely, and the identity of the instance will change upon + flush. In addition, update cascades of foreign key referents (primary + key or not) along relations are supported, either in tandem with the + database's ON UPDATE CASCADE (required for DB's like Postgres) or + issued directly by the ORM in the form of UPDATE statements, by setting + the flag "passive_cascades=False". + + .. change:: + :tags: orm + :tickets: 490 + + inheriting mappers now inherit the MapperExtensions of their parent + mapper directly, so that all methods for a particular MapperExtension + are called for subclasses as well. As always, any MapperExtension + can return either EXT_CONTINUE to continue extension processing + or EXT_STOP to stop processing. The order of mapper resolution is: + . + + Note that if you instantiate the same extension class separately + and then apply it individually for two mappers in the same inheritance + chain, the extension will be applied twice to the inheriting class, + and each method will be called twice. + + To apply a mapper extension explicitly to each inheriting class but + have each method called only once per operation, use the same + instance of the extension for both mappers. + + .. change:: + :tags: orm + :tickets: 907 + + MapperExtension.before_update() and after_update() are now called + symmetrically; previously, an instance that had no modified column + attributes (but had a relation() modification) could be called with + before_update() but not after_update() + + .. change:: + :tags: orm + :tickets: + + columns which are missing from a Query's select statement + now get automatically deferred during load. + + .. change:: + :tags: orm + :tickets: 908 + + mapped classes which extend "object" and do not provide an + __init__() method will now raise TypeError if non-empty *args + or **kwargs are present at instance construction time (and are + not consumed by any extensions such as the scoped_session mapper), + consistent with the behavior of normal Python classes + + .. change:: + :tags: orm + :tickets: 899 + + fixed Query bug when filter_by() compares a relation against None + + .. change:: + :tags: orm + :tickets: + + improved support for pickling of mapped entities. Per-instance + lazy/deferred/expired callables are now serializable so that + they serialize and deserialize with _state. + + .. change:: + :tags: orm + :tickets: 801 + + new synonym() behavior: an attribute will be placed on the mapped + class, if one does not exist already, in all cases. if a property + already exists on the class, the synonym will decorate the property + with the appropriate comparison operators so that it can be used in in + column expressions just like any other mapped attribute (i.e. usable in + filter(), etc.) the "proxy=True" flag is deprecated and no longer means + anything. Additionally, the flag "map_column=True" will automatically + generate a ColumnProperty corresponding to the name of the synonym, + i.e.: 'somename':synonym('_somename', map_column=True) will map the + column named 'somename' to the attribute '_somename'. See the example + in the mapper docs. + + .. change:: + :tags: orm + :tickets: + + Query.select_from() now replaces all existing FROM criterion with + the given argument; the previous behavior of constructing a list + of FROM clauses was generally not useful as is required + filter() calls to create join criterion, and new tables introduced + within filter() already add themselves to the FROM clause. The + new behavior allows not just joins from the main table, but select + statements as well. Filter criterion, order bys, eager load + clauses will be "aliased" against the given statement. + + .. change:: + :tags: orm + :tickets: + + this month's refactoring of attribute instrumentation changes + the "copy-on-load" behavior we've had since midway through 0.3 + with "copy-on-modify" in most cases. This takes a sizable chunk + of latency out of load operations and overall does less work + as only attributes which are actually modified get their + "committed state" copied. Only "mutable scalar" attributes + (i.e. a pickled object or other mutable item), the reason for + the copy-on-load change in the first place, retain the old + behavior. + + .. change:: + :tags: attrname, orm + :tickets: + + a slight behavioral change to attributes is, del'ing an attribute + does *not* cause the lazyloader of that attribute to fire off again; + the "del" makes the effective value of the attribute "None". To + re-trigger the "loader" for an attribute, use + session.expire(instance,). + + .. change:: + :tags: orm + :tickets: + + query.filter(SomeClass.somechild == None), when comparing + a many-to-one property to None, properly generates "id IS NULL" + including that the NULL is on the right side. + + .. change:: + :tags: orm + :tickets: + + query.order_by() takes into account aliased joins, i.e. + query.join('orders', aliased=True).order_by(Order.id) + + .. change:: + :tags: orm + :tickets: + + eagerload(), lazyload(), eagerload_all() take an optional + second class-or-mapper argument, which will select the mapper + to apply the option towards. This can select among other + mappers which were added using add_entity(). + + .. change:: + :tags: orm + :tickets: + + eagerloading will work with mappers added via add_entity(). + + .. change:: + :tags: orm + :tickets: + + added "cascade delete" behavior to "dynamic" relations just like + that of regular relations. if passive_deletes flag (also just added) + is not set, a delete of the parent item will trigger a full load of + the child items so that they can be deleted or updated accordingly. + + .. change:: + :tags: orm + :tickets: + + also with dynamic, implemented correct count() behavior as well + as other helper methods. + + .. change:: + :tags: orm + :tickets: + + fix to cascades on polymorphic relations, such that cascades + from an object to a polymorphic collection continue cascading + along the set of attributes specific to each element in the collection. + + .. change:: + :tags: orm + :tickets: 893 + + query.get() and query.load() do not take existing filter or other + criterion into account; these methods *always* look up the given id + in the database or return the current instance from the identity map, + disregarding any existing filter, join, group_by or other criterion + which has been configured. + + .. change:: + :tags: orm + :tickets: 883 + + added support for version_id_col in conjunction with inheriting mappers. + version_id_col is typically set on the base mapper in an inheritance + relationship where it takes effect for all inheriting mappers. + + .. change:: + :tags: orm + :tickets: + + relaxed rules on column_property() expressions having labels; any + ColumnElement is accepted now, as the compiler auto-labels non-labeled + ColumnElements now. a selectable, like a select() statement, still + requires conversion to ColumnElement via as_scalar() or label(). + + .. change:: + :tags: orm + :tickets: + + fixed backref bug where you could not del instance.attr if attr + was None + + .. change:: + :tags: orm + :tickets: + + several ORM attributes have been removed or made private: + mapper.get_attr_by_column(), mapper.set_attr_by_column(), + mapper.pks_by_table, mapper.cascade_callable(), + MapperProperty.cascade_callable(), mapper.canload(), + mapper.save_obj(), mapper.delete_obj(), mapper._mapper_registry, + attributes.AttributeManager + + .. change:: + :tags: orm + :tickets: + + Assigning an incompatible collection type to a relation attribute now + raises TypeError instead of sqlalchemy's ArgumentError. + + .. change:: + :tags: orm + :tickets: 886 + + Bulk assignment of a MappedCollection now raises an error if a key in the + incoming dictionary does not match the key that the collection's keyfunc + would use for that value. + + .. change:: + :tags: orm, newval1, newval2 + :tickets: + + Custom collections can now specify a @converter method to translate + objects used in "bulk" assignment into a stream of values, as in:: + + obj.col = + # or + obj.dictcol = {'foo': newval1, 'bar': newval2} + + The MappedCollection uses this hook to ensure that incoming key/value + pairs are sane from the collection's perspective. + + .. change:: + :tags: orm + :tickets: 872 + + fixed endless loop issue when using lazy="dynamic" on both + sides of a bi-directional relationship + + .. change:: + :tags: orm + :tickets: 904 + + more fixes to the LIMIT/OFFSET aliasing applied with Query + eagerloads, + in this case when mapped against a select statement + + .. change:: + :tags: orm + :tickets: + + fix to self-referential eager loading such that if the same mapped + instance appears in two or more distinct sets of columns in the same + result set, its eagerly loaded collection will be populated regardless + of whether or not all of the rows contain a set of "eager" columns for + that collection. this would also show up as a KeyError when fetching + results with join_depth turned on. + + .. change:: + :tags: orm + :tickets: + + fixed bug where Query would not apply a subquery to the SQL when LIMIT + was used in conjunction with an inheriting mapper where the eager + loader was only in the parent mapper. + + .. change:: + :tags: orm + :tickets: + + clarified the error message which occurs when you try to update() + an instance with the same identity key as an instance already present + in the session. + + .. change:: + :tags: orm + :tickets: + + some clarifications and fixes to merge(instance, dont_load=True). + fixed bug where lazy loaders were getting disabled on returned instances. + Also, we currently do not support merging an instance which has uncommitted + changes on it, in the case that dont_load=True is used....this will + now raise an error. This is due to complexities in merging the + "committed state" of the given instance to correctly correspond to the + newly copied instance, as well as other modified state. + Since the use case for dont_load=True is caching, the given instances + shouldn't have any uncommitted changes on them anyway. + We also copy the instances over without using any events now, so that + the 'dirty' list on the new session remains unaffected. + + .. change:: + :tags: orm + :tickets: + + fixed bug which could arise when using session.begin_nested() in conjunction + with more than one level deep of enclosing session.begin() statements + + .. change:: + :tags: orm + :tickets: 914 + + fixed session.refresh() with instance that has custom entity_name + + .. change:: + :tags: dialects + :tickets: + + sqlite SLDate type will not erroneously render "microseconds" portion + of a datetime or time object. + + .. change:: + :tags: dialects + :tickets: 902 + + oracle + - added disconnect detection support for Oracle + - some cleanup to binary/raw types so that cx_oracle.LOB is detected + on an ad-hoc basis + + .. change:: + :tags: dialects + :tickets: 824, 839, 842, 901 + + MSSQL + - PyODBC no longer has a global "set nocount on". + - Fix non-identity integer PKs on autload + - Better support for convert_unicode + - Less strict date conversion for pyodbc/adodbapi + - Schema-qualified tables / autoload + + .. change:: + :tags: firebird, backend + :tickets: 410 + + does properly reflect domains (partially fixing) and + PassiveDefaults + + .. change:: + :tags: 3562, firebird, backend + :tickets: + + reverted to use default poolclass (was set to SingletonThreadPool in + 0.4.0 for test purposes) + + .. change:: + :tags: firebird, backend + :tickets: + + map func.length() to 'char_length' (easily overridable with the UDF + 'strlen' on old versions of Firebird) + +.. changelog:: + :version: 0.4.1 + :released: Sun Nov 18 2007 + + .. change:: + :tags: sql + :tickets: + + the "shortname" keyword parameter on bindparam() has been + deprecated. + + .. change:: + :tags: sql + :tickets: + + Added contains operator (generates a "LIKE %%" clause). + + .. change:: + :tags: sql + :tickets: + + anonymous column expressions are automatically labeled. + e.g. select([x* 5]) produces "SELECT x * 5 AS anon_1". + This allows the labelname to be present in the cursor.description + which can then be appropriately matched to result-column processing + rules. (we can't reliably use positional tracking for result-column + matches since text() expressions may represent multiple columns). + + .. change:: + :tags: sql + :tickets: + + operator overloading is now controlled by TypeEngine objects - the + one built-in operator overload so far is String types overloading + '+' to be the string concatenation operator. + User-defined types can also define their own operator overloading + by overriding the adapt_operator(self, op) method. + + .. change:: + :tags: sql + :tickets: 819 + + untyped bind parameters on the right side of a binary expression + will be assigned the type of the left side of the operation, to better + enable the appropriate bind parameter processing to take effect + + .. change:: + :tags: sql + :tickets: 833 + + Removed regular expression step from most statement compilations. + Also fixes + + .. change:: + :tags: sql + :tickets: + + Fixed empty (zero column) sqlite inserts, allowing inserts on + autoincrementing single column tables. + + .. change:: + :tags: sql + :tickets: + + Fixed expression translation of text() clauses; this repairs various + ORM scenarios where literal text is used for SQL expressions + + .. change:: + :tags: sql + :tickets: + + Removed ClauseParameters object; compiled.params returns a regular + dictionary now, as well as result.last_inserted_params() / + last_updated_params(). + + .. change:: + :tags: sql + :tickets: + + Fixed INSERT statements w.r.t. primary key columns that have + SQL-expression based default generators on them; SQL expression + executes inline as normal but will not trigger a "postfetch" condition + for the column, for those DB's who provide it via cursor.lastrowid + + .. change:: + :tags: sql + :tickets: 844 + + func. objects can be pickled/unpickled + + .. change:: + :tags: sql + :tickets: + + rewrote and simplified the system used to "target" columns across + selectable expressions. On the SQL side this is represented by the + "corresponding_column()" method. This method is used heavily by the ORM + to "adapt" elements of an expression to similar, aliased expressions, + as well as to target result set columns originally bound to a + table or selectable to an aliased, "corresponding" expression. The new + rewrite features completely consistent and accurate behavior. + + .. change:: + :tags: sql + :tickets: 573 + + Added a field ("info") for storing arbitrary data on schema items + + .. change:: + :tags: sql + :tickets: + + The "properties" collection on Connections has been renamed "info" to + match schema's writable collections. Access is still available via + the "properties" name until 0.5. + + .. change:: + :tags: sql + :tickets: + + fixed the close() method on Transaction when using strategy='threadlocal' + + .. change:: + :tags: sql + :tickets: 853 + + fix to compiled bind parameters to not mistakenly populate None + + .. change:: + :tags: sql + :tickets: + + ._execute_clauseelement becomes a public method + Connectable.execute_clauseelement + + .. change:: + :tags: orm + :tickets: 843 + + eager loading with LIMIT/OFFSET applied no longer adds the primary + table joined to a limited subquery of itself; the eager loads now + join directly to the subquery which also provides the primary table's + columns to the result set. This eliminates a JOIN from all eager loads + with LIMIT/OFFSET. + + .. change:: + :tags: orm + :tickets: 802 + + session.refresh() and session.expire() now support an additional argument + "attribute_names", a list of individual attribute keynames to be refreshed + or expired, allowing partial reloads of attributes on an already-loaded + instance. + + .. change:: + :tags: orm + :tickets: 767 + + added op() operator to instrumented attributes; i.e. + User.name.op('ilike')('%somename%') + + .. change:: + :tags: orm + :tickets: 676 + + Mapped classes may now define __eq__, __hash__, and __nonzero__ methods + with arbitrary semantics. The orm now handles all mapped instances on + an identity-only basis. (e.g. 'is' vs '==') + + .. change:: + :tags: orm + :tickets: + + the "properties" accessor on Mapper is removed; it now throws an informative + exception explaining the usage of mapper.get_property() and + mapper.iterate_properties + + .. change:: + :tags: orm + :tickets: + + added having() method to Query, applies HAVING to the generated statement + in the same way as filter() appends to the WHERE clause. + + .. change:: + :tags: orm + :tickets: 777 + + The behavior of query.options() is now fully based on paths, i.e. an + option such as eagerload_all('x.y.z.y.x') will apply eagerloading to + only those paths, i.e. and not 'x.y.x'; eagerload('children.children') + applies only to exactly two-levels deep, etc. + + .. change:: + :tags: orm + :tickets: + + PickleType will compare using `==` when set up with mutable=False, + and not the `is` operator. To use `is` or any other comparator, send + in a custom comparison function using PickleType(comparator=my_custom_comparator). + + .. change:: + :tags: orm + :tickets: 848 + + query doesn't throw an error if you use distinct() and an order_by() + containing UnaryExpressions (or other) together + + .. change:: + :tags: orm + :tickets: 786 + + order_by() expressions from joined tables are properly added to columns + clause when using distinct() + + .. change:: + :tags: orm + :tickets: 858 + + fixed error where Query.add_column() would not accept a class-bound + attribute as an argument; Query also raises an error if an invalid + argument was sent to add_column() (at instances() time) + + .. change:: + :tags: orm + :tickets: + + added a little more checking for garbage-collection dereferences in + InstanceState.__cleanup() to reduce "gc ignored" errors on app + shutdown + + .. change:: + :tags: orm + :tickets: + + The session API has been solidified: + + .. change:: + :tags: orm + :tickets: 840 + + It's an error to session.save() an object which is already + persistent + + .. change:: + :tags: orm + :tickets: + + It's an error to session.delete() an object which is *not* + persistent. + + .. change:: + :tags: orm + :tickets: + + session.update() and session.delete() raise an error when updating + or deleting an instance that is already in the session with a + different identity. + + .. change:: + :tags: orm + :tickets: + + The session checks more carefully when determining "object X already + in another session"; e.g. if you pickle a series of objects and + unpickle (i.e. as in a Pylons HTTP session or similar), they can go + into a new session without any conflict + + .. change:: + :tags: orm + :tickets: + + merge() includes a keyword argument "dont_load=True". setting this + flag will cause the merge operation to not load any data from the + database in response to incoming detached objects, and will accept + the incoming detached object as though it were already present in + that session. Use this to merge detached objects from external + caching systems into the session. + + .. change:: + :tags: orm + :tickets: + + Deferred column attributes no longer trigger a load operation when the + attribute is assigned to. In those cases, the newly assigned value + will be present in the flushes' UPDATE statement unconditionally. + + .. change:: + :tags: orm + :tickets: 834 + + Fixed a truncation error when re-assigning a subset of a collection + (obj.relation = obj.relation[1:]) + + .. change:: + :tags: orm + :tickets: 832 + + De-cruftified backref configuration code, backrefs which step on + existing properties now raise an error + + .. change:: + :tags: orm + :tickets: 831 + + Improved behavior of add_property() etc., fixed involving + synonym/deferred. + + .. change:: + :tags: orm + :tickets: + + Fixed clear_mappers() behavior to better clean up after itself. + + .. change:: + :tags: orm + :tickets: 841 + + Fix to "row switch" behavior, i.e. when an INSERT/DELETE is combined + into a single UPDATE; many-to-many relations on the parent object + update properly. + + .. change:: + :tags: orm + :tickets: + + Fixed __hash__ for association proxy- these collections are unhashable, + just like their mutable Python counterparts. + + .. change:: + :tags: orm + :tickets: + + Added proxying of save_or_update, __contains__ and __iter__ methods for + scoped sessions. + + .. change:: + :tags: orm + :tickets: 852 + + fixed very hard-to-reproduce issue where by the FROM clause of Query + could get polluted by certain generative calls + + .. change:: + :tags: dialects + :tickets: + + Added experimental support for MaxDB (versions >= 7.6.03.007 only). + + .. change:: + :tags: dialects + :tickets: + + oracle will now reflect "DATE" as an OracleDateTime column, not + OracleDate + + .. change:: + :tags: dialects + :tickets: 847 + + added awareness of schema name in oracle table_names() function, + fixes metadata.reflect(schema='someschema') + + .. change:: + :tags: dialects + :tickets: + + MSSQL anonymous labels for selection of functions made deterministic + + .. change:: + :tags: dialects + :tickets: + + sqlite will reflect "DECIMAL" as a numeric column. + + .. change:: + :tags: dialects + :tickets: 828 + + Made access dao detection more reliable + + .. change:: + :tags: dialects + :tickets: + + Renamed the Dialect attribute 'preexecute_sequences' to + 'preexecute_pk_sequences'. An attribute porxy is in place for + out-of-tree dialects using the old name. + + .. change:: + :tags: dialects + :tickets: + + Added test coverage for unknown type reflection. Fixed sqlite/mysql + handling of type reflection for unknown types. + + .. change:: + :tags: dialects + :tickets: + + Added REAL for mysql dialect (for folks exploiting the + REAL_AS_FLOAT sql mode). + + .. change:: + :tags: dialects + :tickets: + + mysql Float, MSFloat and MSDouble constructed without arguments + now produce no-argument DDL, e.g.'FLOAT'. + + .. change:: + :tags: misc + :tickets: + + Removed unused util.hash(). + +.. changelog:: + :version: 0.4.0 + :released: Wed Oct 17 2007 + + .. change:: + :tags: + :tickets: + + (see 0.4.0beta1 for the start of major changes against 0.3, + as well as http://www.sqlalchemy.org/trac/wiki/WhatsNewIn04 ) + + .. change:: + :tags: + :tickets: 785 + + Added initial Sybase support (mxODBC so far) + + .. change:: + :tags: + :tickets: + + Added partial index support for PostgreSQL. Use the postgres_where keyword + on the Index. + + .. change:: + :tags: + :tickets: 817 + + string-based query param parsing/config file parser understands + wider range of string values for booleans + + .. change:: + :tags: + :tickets: 813 + + backref remove object operation doesn't fail if the other-side + collection doesn't contain the item, supports noload collections + + .. change:: + :tags: + :tickets: 818 + + removed __len__ from "dynamic" collection as it would require issuing + a SQL "count()" operation, thus forcing all list evaluations to issue + redundant SQL + + .. change:: + :tags: + :tickets: 816 + + inline optimizations added to locate_dirty() which can greatly speed up + repeated calls to flush(), as occurs with autoflush=True + + .. change:: + :tags: + :tickets: + + The IdentifierPreprarer's _requires_quotes test is now regex based. Any + out-of-tree dialects that provide custom sets of legal_characters or + illegal_initial_characters will need to move to regexes or override + _requires_quotes. + + .. change:: + :tags: + :tickets: + + Firebird has supports_sane_rowcount and supports_sane_multi_rowcount set + to False due to ticket #370 (right way). + + .. change:: + :tags: + :tickets: + + Improvements and fixes on Firebird reflection: + . FBDialect now mimics OracleDialect, regarding case-sensitivity of TABLE and + COLUMN names (see 'case_sensitive remotion' topic on this current file). + . FBDialect.table_names() doesn't bring system tables (ticket:796). + . FB now reflects Column's nullable property correctly. + + .. change:: + :tags: + :tickets: + + Fixed SQL compiler's awareness of top-level column labels as used + in result-set processing; nested selects which contain the same column + names don't affect the result or conflict with result-column metadata. + + .. change:: + :tags: + :tickets: + + query.get() and related functions (like many-to-one lazyloading) + use compile-time-aliased bind parameter names, to prevent + name conflicts with bind parameters that already exist in the + mapped selectable. + + .. change:: + :tags: + :tickets: 795 + + Fixed three- and multi-level select and deferred inheritance loading + (i.e. abc inheritance with no select_table). + + .. change:: + :tags: + :tickets: + + Ident passed to id_chooser in shard.py always a list. + + .. change:: + :tags: + :tickets: + + The no-arg ResultProxy._row_processor() is now the class attribute + `_process_row`. + + .. change:: + :tags: + :tickets: 797 + + Added support for returning values from inserts and updates for + PostgreSQL 8.2+. + + .. change:: + :tags: + :tickets: + + PG reflection, upon seeing the default schema name being used explicitly + as the "schema" argument in a Table, will assume that this is the the + user's desired convention, and will explicitly set the "schema" argument + in foreign-key-related reflected tables, thus making them match only + with Table constructors that also use the explicit "schema" argument + (even though its the default schema). + In other words, SA assumes the user is being consistent in this usage. + + .. change:: + :tags: + :tickets: 808 + + fixed sqlite reflection of BOOL/BOOLEAN + + .. change:: + :tags: + :tickets: + + Added support for UPDATE with LIMIT on mysql. + + .. change:: + :tags: + :tickets: 803 + + null foreign key on a m2o doesn't trigger a lazyload + + .. change:: + :tags: + :tickets: 800 + + oracle does not implicitly convert to unicode for non-typed result + sets (i.e. when no TypeEngine/String/Unicode type is even being used; + previously it was detecting DBAPI types and converting regardless). + should fix + + .. change:: + :tags: + :tickets: 806 + + fix to anonymous label generation of long table/column names + + .. change:: + :tags: + :tickets: + + Firebird dialect now uses SingletonThreadPool as poolclass. + + .. change:: + :tags: + :tickets: + + Firebird now uses dialect.preparer to format sequences names + + .. change:: + :tags: + :tickets: 810 + + Fixed breakage with postgres and multiple two-phase transactions. Two-phase + commits and and rollbacks didn't automatically end up with a new transaction + as the usual dbapi commits/rollbacks do. + + .. change:: + :tags: + :tickets: + + Added an option to the _ScopedExt mapper extension to not automatically + save new objects to session on object initialization. + + .. change:: + :tags: + :tickets: + + fixed Oracle non-ansi join syntax + + .. change:: + :tags: + :tickets: + + PickleType and Interval types (on db not supporting it natively) are now + slightly faster. + + .. change:: + :tags: + :tickets: + + Added Float and Time types to Firebird (FBFloat and FBTime). Fixed + BLOB SUB_TYPE for TEXT and Binary types. + + .. change:: + :tags: + :tickets: + + Changed the API for the in_ operator. in_() now accepts a single argument + that is a sequence of values or a selectable. The old API of passing in + values as varargs still works but is deprecated. + +.. changelog:: + :version: 0.4.0beta6 + :released: Thu Sep 27 2007 + + .. change:: + :tags: + :tickets: + + The Session identity map is now *weak referencing* by default, use + weak_identity_map=False to use a regular dict. The weak dict we are using + is customized to detect instances which are "dirty" and maintain a + temporary strong reference to those instances until changes are flushed. + + .. change:: + :tags: + :tickets: 758 + + Mapper compilation has been reorganized such that most compilation occurs + upon mapper construction. This allows us to have fewer calls to + mapper.compile() and also to allow class-based properties to force a + compilation (i.e. User.addresses == 7 will compile all mappers; this is). The only caveat here is that an inheriting mapper now + looks for its inherited mapper upon construction; so mappers within + inheritance relationships need to be constructed in inheritance order + (which should be the normal case anyway). + + .. change:: + :tags: + :tickets: + + added "FETCH" to the keywords detected by Postgres to indicate a + result-row holding statement (i.e. in addition to "SELECT"). + + .. change:: + :tags: + :tickets: + + Added full list of SQLite reserved keywords so that they get escaped + properly. + + .. change:: + :tags: + :tickets: + + Tightened up the relationship between the Query's generation of "eager + load" aliases, and Query.instances() which actually grabs the eagerly + loaded rows. If the aliases were not specifically generated for that + statement by EagerLoader, the EagerLoader will not take effect when the + rows are fetched. This prevents columns from being grabbed accidentally + as being part of an eager load when they were not meant for such, which + can happen with textual SQL as well as some inheritance situations. It's + particularly important since the "anonymous aliasing" of columns uses + simple integer counts now to generate labels. + + .. change:: + :tags: + :tickets: + + Removed "parameters" argument from clauseelement.compile(), replaced with + "column_keys". The parameters sent to execute() only interact with the + insert/update statement compilation process in terms of the column names + present but not the values for those columns. Produces more consistent + execute/executemany behavior, simplifies things a bit internally. + + .. change:: + :tags: + :tickets: 560 + + Added 'comparator' keyword argument to PickleType. By default, "mutable" + PickleType does a "deep compare" of objects using their dumps() + representation. But this doesn't work for dictionaries. Pickled objects + which provide an adequate __eq__() implementation can be set up with + "PickleType(comparator=operator.eq)" + + .. change:: + :tags: + :tickets: + + Added session.is_modified(obj) method; performs the same "history" + comparison operation as occurs within a flush operation; setting + include_collections=False gives the same result as is used when the flush + determines whether or not to issue an UPDATE for the instance's row. + + .. change:: + :tags: + :tickets: 584, 761 + + Added "schema" argument to Sequence; use this with Postgres /Oracle when + the sequence is located in an alternate schema. Implements part of, should fix. + + .. change:: + :tags: + :tickets: + + Fixed reflection of the empty string for mysql enums. + + .. change:: + :tags: + :tickets: 794 + + Changed MySQL dialect to use the older LIMIT , syntax + instead of LIMIT OFFSET for folks using 3.23. + + .. change:: + :tags: + :tickets: + + Added 'passive_deletes="all"' flag to relation(), disables all nulling-out + of foreign key attributes during a flush where the parent object is + deleted. + + .. change:: + :tags: + :tickets: + + Column defaults and onupdates, executing inline, will add parenthesis for + subqueries and other parenthesis-requiring expressions + + .. change:: + :tags: + :tickets: 793 + + The behavior of String/Unicode types regarding that they auto-convert to + TEXT/CLOB when no length is present now occurs *only* for an exact type of + String or Unicode with no arguments. If you use VARCHAR or NCHAR + (subclasses of String/Unicode) with no length, they will be interpreted by + the dialect as VARCHAR/NCHAR; no "magic" conversion happens there. This + is less surprising behavior and in particular this helps Oracle keep + string-based bind parameters as VARCHARs and not CLOBs. + + .. change:: + :tags: + :tickets: 771 + + Fixes to ShardedSession to work with deferred columns. + + .. change:: + :tags: + :tickets: + + User-defined shard_chooser() function must accept "clause=None" argument; + this is the ClauseElement passed to session.execute(statement) and can be + used to determine correct shard id (since execute() doesn't take an + instance.) + + .. change:: + :tags: + :tickets: 764 + + Adjusted operator precedence of NOT to match '==' and others, so that + ~(x y) produces NOT (x y), which is better compatible + with older MySQL versions.. This doesn't apply to "~(x==y)" + as it does in 0.3 since ~(x==y) compiles to "x != y", but still applies + to operators like BETWEEN. + + .. change:: + :tags: + :tickets: 757, 768, 779, 728 + + Other tickets:,,. + +.. changelog:: + :version: 0.4.0beta5 + :released: + + .. change:: + :tags: + :tickets: 754 + + Connection pool fixes; the better performance of beta4 remains but fixes + "connection overflow" and other bugs which were present (like). + + .. change:: + :tags: + :tickets: 769 + + Fixed bugs in determining proper sync clauses from custom inherit + conditions. + + .. change:: + :tags: + :tickets: 763 + + Extended 'engine_from_config' coercion for QueuePool size / overflow. + + .. change:: + :tags: + :tickets: 748 + + mysql views can be reflected again. + + .. change:: + :tags: + :tickets: + + AssociationProxy can now take custom getters and setters. + + .. change:: + :tags: + :tickets: + + Fixed malfunctioning BETWEEN in orm queries. + + .. change:: + :tags: + :tickets: 762 + + Fixed OrderedProperties pickling + + .. change:: + :tags: + :tickets: + + SQL-expression defaults and sequences now execute "inline" for all + non-primary key columns during an INSERT or UPDATE, and for all columns + during an executemany()-style call. inline=True flag on any insert/update + statement also forces the same behavior with a single execute(). + result.postfetch_cols() is a collection of columns for which the previous + single insert or update statement contained a SQL-side default expression. + + .. change:: + :tags: + :tickets: 759 + + Fixed PG executemany() behavior. + + .. change:: + :tags: + :tickets: + + postgres reflects tables with autoincrement=False for primary key columns + which have no defaults. + + .. change:: + :tags: + :tickets: + + postgres no longer wraps executemany() with individual execute() calls, + instead favoring performance. "rowcount"/"concurrency" checks with + deleted items (which use executemany) are disabled with PG since psycopg2 + does not report proper rowcount for executemany(). + + .. change:: + :tags: tickets, fixed + :tickets: 742 + + + + .. change:: + :tags: tickets, fixed + :tickets: 748 + + + + .. change:: + :tags: tickets, fixed + :tickets: 760 + + + + .. change:: + :tags: tickets, fixed + :tickets: 762 + + + + .. change:: + :tags: tickets, fixed + :tickets: 763 + + + +.. changelog:: + :version: 0.4.0beta4 + :released: Wed Aug 22 2007 + + .. change:: + :tags: + :tickets: + + Tidied up what ends up in your namespace when you 'from sqlalchemy import *': + + .. change:: + :tags: + :tickets: + + 'table' and 'column' are no longer imported. They remain available by + direct reference (as in 'sql.table' and 'sql.column') or a glob import + from the sql package. It was too easy to accidentally use a + sql.expressions.table instead of schema.Table when just starting out + with SQLAlchemy, likewise column. + + .. change:: + :tags: + :tickets: + + Internal-ish classes like ClauseElement, FromClause, NullTypeEngine, + etc., are also no longer imported into your namespace + + .. change:: + :tags: + :tickets: + + The 'Smallinteger' compatiblity name (small i!) is no longer imported, + but remains in schema.py for now. SmallInteger (big I!) is still + imported. + + .. change:: + :tags: + :tickets: + + The connection pool uses a "threadlocal" strategy internally to return + the same connection already bound to a thread, for "contextual" connections; + these are the connections used when you do a "connectionless" execution + like insert().execute(). This is like a "partial" version of the + "threadlocal" engine strategy but without the thread-local transaction part + of it. We're hoping it reduces connection pool overhead as well as + database usage. However, if it proves to impact stability in a negative way, + we'll roll it right back. + + .. change:: + :tags: + :tickets: + + Fix to bind param processing such that "False" values (like blank strings) + still get processed/encoded. + + .. change:: + :tags: + :tickets: 752 + + Fix to select() "generative" behavior, such that calling column(), + select_from(), correlate(), and with_prefix() does not modify the + original select object + + .. change:: + :tags: + :tickets: + + Added a "legacy" adapter to types, such that user-defined TypeEngine + and TypeDecorator classes which define convert_bind_param() and/or + convert_result_value() will continue to function. Also supports + calling the super() version of those methods. + + .. change:: + :tags: + :tickets: + + Added session.prune(), trims away instances cached in a session that + are no longer referenced elsewhere. (A utility for strong-ref + identity maps). + + .. change:: + :tags: + :tickets: + + Added close() method to Transaction. Closes out a transaction using + rollback if it's the outermost transaction, otherwise just ends + without affecting the outer transaction. + + .. change:: + :tags: + :tickets: + + Transactional and non-transactional Session integrates better with + bound connection; a close() will ensure that connection + transactional state is the same as that which existed on it before + being bound to the Session. + + .. change:: + :tags: + :tickets: 735 + + Modified SQL operator functions to be module-level operators, + allowing SQL expressions to be pickleable. + + .. change:: + :tags: + :tickets: + + Small adjustment to mapper class.__init__ to allow for Py2.6 + object.__init__() behavior. + + .. change:: + :tags: + :tickets: + + Fixed 'prefix' argument for select() + + .. change:: + :tags: + :tickets: + + Connection.begin() no longer accepts nested=True, this logic is now + all in begin_nested(). + + .. change:: + :tags: + :tickets: + + Fixes to new "dynamic" relation loader involving cascades + + .. change:: + :tags: tickets, fixed + :tickets: 735 + + + + .. change:: + :tags: tickets, fixed + :tickets: 752 + + + +.. changelog:: + :version: 0.4.0beta3 + :released: Thu Aug 16 2007 + + .. change:: + :tags: + :tickets: + + SQL types optimization: + + .. change:: + :tags: + :tickets: + + New performance tests show a combined mass-insert/mass-select test as + having 68% fewer function calls than the same test run against 0.3. + + .. change:: + :tags: + :tickets: + + General performance improvement of result set iteration is around 10-20%. + + .. change:: + :tags: + :tickets: + + In types.AbstractType, convert_bind_param() and convert_result_value() + have migrated to callable-returning bind_processor() and + result_processor() methods. If no callable is returned, no pre/post + processing function is called. + + .. change:: + :tags: + :tickets: + + Hooks added throughout base/sql/defaults to optimize the calling of bind + aram/result processors so that method call overhead is minimized. + + .. change:: + :tags: + :tickets: + + Support added for executemany() scenarios such that unneeded "last row id" + logic doesn't kick in, parameters aren't excessively traversed. + + .. change:: + :tags: + :tickets: + + Added 'inherit_foreign_keys' arg to mapper(). + + .. change:: + :tags: + :tickets: + + Added support for string date passthrough in sqlite. + + .. change:: + :tags: tickets, fixed + :tickets: 738 + + + + .. change:: + :tags: tickets, fixed + :tickets: 739 + + + + .. change:: + :tags: tickets, fixed + :tickets: 743 + + + + .. change:: + :tags: tickets, fixed + :tickets: 744 + + + +.. changelog:: + :version: 0.4.0beta2 + :released: Tue Aug 14 2007 + + .. change:: + :tags: oracle, improvements. + :tickets: + + Auto-commit after LOAD DATA INFILE for mysql. + + .. change:: + :tags: oracle, improvements. + :tickets: + + A rudimental SessionExtension class has been added, allowing user-defined + functionality to take place at flush(), commit(), and rollback() boundaries. + + .. change:: + :tags: oracle, improvements. + :tickets: + + Added engine_from_config() function for helping to create_engine() from an + .ini style config. + + .. change:: + :tags: oracle, improvements. + :tickets: + + base_mapper() becomes a plain attribute. + + .. change:: + :tags: oracle, improvements. + :tickets: + + session.execute() and scalar() can search for a Table with which to bind from + using the given ClauseElement. + + .. change:: + :tags: oracle, improvements. + :tickets: + + Session automatically extrapolates tables from mappers with binds, also uses + base_mapper so that inheritance hierarchies bind automatically. + + .. change:: + :tags: oracle, improvements. + :tickets: + + Moved ClauseVisitor traversal back to inlined non-recursive. + + .. change:: + :tags: tickets, fixed + :tickets: 730 + + + + .. change:: + :tags: tickets, fixed + :tickets: 732 + + + + .. change:: + :tags: tickets, fixed + :tickets: 733 + + + + .. change:: + :tags: tickets, fixed + :tickets: 734 + + + +.. changelog:: + :version: 0.4.0beta1 + :released: Sun Aug 12 2007 + + .. change:: + :tags: orm + :tickets: + + Speed! Along with recent speedups to ResultProxy, total number of function + calls significantly reduced for large loads. + + .. change:: + :tags: orm + :tickets: + + test/perf/masseagerload.py reports 0.4 as having the fewest number of + function calls across all SA versions (0.1, 0.2, and 0.3). + + .. change:: + :tags: orm + :tickets: 213 + + New collection_class api and implementation. Collections are + now instrumented via decorations rather than proxying. You can now have + collections that manage their own membership, and your class instance will + be directly exposed on the relation property. The changes are transparent + for most users. + + .. change:: + :tags: orm + :tickets: + + InstrumentedList (as it was) is removed, and relation properties no + longer have 'clear()', '.data', or any other added methods beyond those + provided by the collection type. You are free, of course, to add them to + a custom class. + + .. change:: + :tags: orm + :tickets: + + __setitem__-like assignments now fire remove events for the existing + value, if any. + + .. change:: + :tags: orm + :tickets: + + dict-likes used as collection classes no longer need to change __iter__ + semantics- itervalues() is used by default instead. This is a backwards + incompatible change. + + .. change:: + :tags: orm + :tickets: + + Subclassing dict for a mapped collection is no longer needed in most + cases. orm.collections provides canned implementations that key objects + by a specified column or a custom function of your choice. + + .. change:: + :tags: orm + :tickets: + + Collection assignment now requires a compatible type- assigning None to + clear a collection or assigning a list to a dict collection will now + raise an argument error. + + .. change:: + :tags: orm + :tickets: + + AttributeExtension moved to interfaces, and .delete is now .remove The + event method signature has also been swapped around. + + .. change:: + :tags: orm + :tickets: + + Major overhaul for Query: + + .. change:: + :tags: orm + :tickets: + + All selectXXX methods are deprecated. Generative methods are now the + standard way to do things, i.e. filter(), filter_by(), all(), one(), + etc. Deprecated methods are docstring'ed with their new replacements. + + .. change:: + :tags: orm + :tickets: 643 + + Class-level properties are now usable as query elements... no more + '.c.'! "Class.c.propname" is now superceded by "Class.propname". All + clause operators are supported, as well as higher level operators such + as Class.prop== for scalar attributes, + Class.prop.contains() and Class.prop.any() for collection-based attributes (all are also + negatable). Table-based column expressions as well as columns mounted + on mapped classes via 'c' are of course still fully available and can be + freely mixed with the new attributes. + + .. change:: + :tags: orm + :tickets: + + Removed ancient query.select_by_attributename() capability. + + .. change:: + :tags: orm + :tickets: + + The aliasing logic used by eager loading has been generalized, so that + it also adds full automatic aliasing support to Query. It's no longer + necessary to create an explicit Alias to join to the same tables + multiple times; *even for self-referential relationships*. + + - join() and outerjoin() take arguments "aliased=True". Yhis causes + their joins to be built on aliased tables; subsequent calls to + filter() and filter_by() will translate all table expressions (yes, + real expressions using the original mapped Table) to be that of the + Alias for the duration of that join() (i.e. until reset_joinpoint() or + another join() is called). + + - join() and outerjoin() take arguments "id=". When used + with "aliased=True", the id can be referenced by add_entity(cls, + id=) so that you can select the joined instances even if + they're from an alias. + + - join() and outerjoin() now work with self-referential relationships! + Using "aliased=True", you can join as many levels deep as desired, + i.e. query.join(['children', 'children'], aliased=True); filter + criterion will be against the rightmost joined table + + .. change:: + :tags: orm + :tickets: 660 + + Added query.populate_existing(), marks the query to reload all + attributes and collections of all instances touched in the query, + including eagerly-loaded entities. + + .. change:: + :tags: orm + :tickets: + + Added eagerload_all(), allows eagerload_all('x.y.z') to specify eager + loading of all properties in the given path. + + .. change:: + :tags: orm + :tickets: + + Major overhaul for Session: + + .. change:: + :tags: orm + :tickets: + + New function which "configures" a session called "sessionmaker()". Send + various keyword arguments to this function once, returns a new class + which creates a Session against that stereotype. + + .. change:: + :tags: orm + :tickets: + + SessionTransaction removed from "public" API. You now can call begin()/ + commit()/rollback() on the Session itself. + + .. change:: + :tags: orm + :tickets: + + Session also supports SAVEPOINT transactions; call begin_nested(). + + .. change:: + :tags: orm + :tickets: + + Session supports two-phase commit behavior when vertically or + horizontally partitioning (i.e., using more than one engine). Use + twophase=True. + + .. change:: + :tags: orm + :tickets: + + Session flag "transactional=True" produces a session which always places + itself into a transaction when first used. Upon commit(), rollback() or + close(), the transaction ends; but begins again on the next usage. + + .. change:: + :tags: orm + :tickets: + + Session supports "autoflush=True". This issues a flush() before each + query. Use in conjunction with transactional, and you can just + save()/update() and then query, the new objects will be there. Use + commit() at the end (or flush() if non-transactional) to flush remaining + changes. + + .. change:: + :tags: orm + :tickets: + + New scoped_session() function replaces SessionContext and assignmapper. + Builds onto "sessionmaker()" concept to produce a class whos Session() + construction returns the thread-local session. Or, call all Session + methods as class methods, i.e. Session.save(foo); Session.commit(). + just like the old "objectstore" days. + + .. change:: + :tags: orm + :tickets: + + Added new "binds" argument to Session to support configuration of + multiple binds with sessionmaker() function. + + .. change:: + :tags: orm + :tickets: + + A rudimental SessionExtension class has been added, allowing + user-defined functionality to take place at flush(), commit(), and + rollback() boundaries. + + .. change:: + :tags: orm + :tickets: + + Query-based relation()s available with dynamic_loader(). This is a + *writable* collection (supporting append() and remove()) which is also a + live Query object when accessed for reads. Ideal for dealing with very + large collections where only partial loading is desired. + + .. change:: + :tags: orm + :tickets: + + flush()-embedded inline INSERT/UPDATE expressions. Assign any SQL + expression, like "sometable.c.column + 1", to an instance's attribute. + Upon flush(), the mapper detects the expression and embeds it directly in + the INSERT or UPDATE statement; the attribute gets deferred on the + instance so it loads the new value the next time you access it. + + .. change:: + :tags: orm + :tickets: 618 + + A rudimental sharding (horizontal scaling) system is introduced. This + system uses a modified Session which can distribute read and write + operations among multiple databases, based on user-defined functions + defining the "sharding strategy". Instances and their dependents can be + distributed and queried among multiple databases based on attribute + values, round-robin approaches or any other user-defined + system. + + .. change:: + :tags: orm + :tickets: 659 + + Eager loading has been enhanced to allow even more joins in more places. + It now functions at any arbitrary depth along self-referential and + cyclical structures. When loading cyclical structures, specify + "join_depth" on relation() indicating how many times you'd like the table + to join to itself; each level gets a distinct table alias. The alias + names themselves are generated at compile time using a simple counting + scheme now and are a lot easier on the eyes, as well as of course + completely deterministic. + + .. change:: + :tags: orm + :tickets: 211 + + Added composite column properties. This allows you to create a type which + is represented by more than one column, when using the ORM. Objects of + the new type are fully functional in query expressions, comparisons, + query.get() clauses, etc. and act as though they are regular single-column + scalars... except they're not! Use the function composite(cls, *columns) + inside of the mapper's "properties" dict, and instances of cls will be + created/mapped to a single attribute, comprised of the values correponding + to *columns. + + .. change:: + :tags: orm + :tickets: + + Improved support for custom column_property() attributes which feature + correlated subqueries, works better with eager loading now. + + .. change:: + :tags: orm + :tickets: 611 + + Primary key "collapse" behavior; the mapper will analyze all columns in + its given selectable for primary key "equivalence", that is, columns which + are equivalent via foreign key relationship or via an explicit + inherit_condition. primarily for joined-table inheritance scenarios where + different named PK columns in inheriting tables should "collapse" into a + single-valued (or fewer-valued) primary key. Fixes things like. + + .. change:: + :tags: orm + :tickets: + + Joined-table inheritance will now generate the primary key columns of all + inherited classes against the root table of the join only. This implies + that each row in the root table is distinct to a single instance. If for + some rare reason this is not desireable, explicit primary_key settings on + individual mappers will override it. + + .. change:: + :tags: orm + :tickets: + + When "polymorphic" flags are used with joined-table or single-table + inheritance, all identity keys are generated against the root class of the + inheritance hierarchy; this allows query.get() to work polymorphically + using the same caching semantics as a non-polymorphic get. Note that this + currently does not work with concrete inheritance. + + .. change:: + :tags: orm + :tickets: + + Secondary inheritance loading: polymorphic mappers can be constructed + *without* a select_table argument. inheriting mappers whose tables were + not represented in the initial load will issue a second SQL query + immediately, once per instance (i.e. not very efficient for large lists), + in order to load the remaining columns. + + .. change:: + :tags: orm + :tickets: + + Secondary inheritance loading can also move its second query into a + column-level "deferred" load, via the "polymorphic_fetch" argument, which + can be set to 'select' or 'deferred' + + .. change:: + :tags: orm + :tickets: 696 + + It's now possible to map only a subset of available selectable columns + onto mapper properties, using include_columns/exclude_columns.. + + .. change:: + :tags: orm + :tickets: + + Added undefer_group() MapperOption, sets a set of "deferred" columns + joined by a "group" to load as "undeferred". + + .. change:: + :tags: orm + :tickets: + + Rewrite of the "deterministic alias name" logic to be part of the SQL + layer, produces much simpler alias and label names more in the style of + Hibernate + + .. change:: + :tags: sql + :tickets: + + Speed! Clause compilation as well as the mechanics of SQL constructs have + been streamlined and simplified to a signficant degree, for a 20-30% + improvement of the statement construction/compilation overhead of 0.3. + + .. change:: + :tags: sql + :tickets: + + All "type" keyword arguments, such as those to bindparam(), column(), + Column(), and func.(), renamed to "type_". Those objects still + name their "type" attribute as "type". + + .. change:: + :tags: sql + :tickets: + + case_sensitive=(True|False) setting removed from schema items, since + checking this state added a lot of method call overhead and there was no + decent reason to ever set it to False. Table and column names which are + all lower case will be treated as case-insenstive (yes we adjust for + Oracle's UPPERCASE style too). + + .. change:: + :tags: transactions + :tickets: + + Added context manager (with statement) support for transactions. + + .. change:: + :tags: transactions + :tickets: + + Added support for two phase commit, works with mysql and postgres so far. + + .. change:: + :tags: transactions + :tickets: + + Added a subtransaction implementation that uses savepoints. + + .. change:: + :tags: transactions + :tickets: + + Added support for savepoints. + + .. change:: + :tags: metadata + :tickets: + + Tables can be reflected from the database en-masse without declaring + them in advance. MetaData(engine, reflect=True) will load all tables + present in the database, or use metadata.reflect() for finer control. + + .. change:: + :tags: metadata + :tickets: + + DynamicMetaData has been renamed to ThreadLocalMetaData + + .. change:: + :tags: metadata + :tickets: + + The ThreadLocalMetaData constructor now takes no arguments. + + .. change:: + :tags: metadata + :tickets: + + BoundMetaData has been removed- regular MetaData is equivalent + + .. change:: + :tags: metadata + :tickets: 646 + + Numeric and Float types now have an "asdecimal" flag; defaults to True for + Numeric, False for Float. When True, values are returned as + decimal.Decimal objects; when False, values are returned as float(). The + defaults of True/False are already the behavior for PG and MySQL's DBAPI + modules. + + .. change:: + :tags: metadata + :tickets: 475 + + New SQL operator implementation which removes all hardcoded operators from + expression structures and moves them into compilation; allows greater + flexibility of operator compilation; for example, "+" compiles to "||" + when used in a string context, or "concat(a,b)" on MySQL; whereas in a + numeric context it compiles to "+". Fixes. + + .. change:: + :tags: metadata + :tickets: + + "Anonymous" alias and label names are now generated at SQL compilation + time in a completely deterministic fashion... no more random hex IDs + + .. change:: + :tags: metadata + :tickets: + + Significant architectural overhaul to SQL elements (ClauseElement). All + elements share a common "mutability" framework which allows a consistent + approach to in-place modifications of elements as well as generative + behavior. Improves stability of the ORM which makes heavy usage of + mutations to SQL expressions. + + .. change:: + :tags: metadata + :tickets: + + select() and union()'s now have "generative" behavior. Methods like + order_by() and group_by() return a *new* instance - the original instance + is left unchanged. Non-generative methods remain as well. + + .. change:: + :tags: metadata + :tickets: 569, 52 + + The internals of select/union vastly simplified- all decision making + regarding "is subquery" and "correlation" pushed to SQL generation phase. + select() elements are now *never* mutated by their enclosing containers or + by any dialect's compilation process + + .. change:: + :tags: metadata + :tickets: + + select(scalar=True) argument is deprecated; use select(..).as_scalar(). + The resulting object obeys the full "column" interface and plays better + within expressions. + + .. change:: + :tags: metadata + :tickets: 504 + + Added select().with_prefix('foo') allowing any set of keywords to be + placed before the columns clause of the SELECT + + .. change:: + :tags: metadata + :tickets: 686 + + Added array slice support to row[] + + .. change:: + :tags: metadata + :tickets: + + Result sets make a better attempt at matching the DBAPI types present in + cursor.description to the TypeEngine objects defined by the dialect, which + are then used for result-processing. Note this only takes effect for + textual SQL; constructed SQL statements always have an explicit type map. + + .. change:: + :tags: metadata + :tickets: + + Result sets from CRUD operations close their underlying cursor immediately + and will also autoclose the connection if defined for the operation; this + allows more efficient usage of connections for successive CRUD operations + with less chance of "dangling connections". + + .. change:: + :tags: metadata + :tickets: 559 + + Column defaults and onupdate Python functions (i.e. passed to + ColumnDefault) may take zero or one arguments; the one argument is the + ExecutionContext, from which you can call "context.parameters[someparam]" + to access the other bind parameter values affixed to the statement. The connection used for the execution is available as well + so that you can pre-execute statements. + + .. change:: + :tags: metadata + :tickets: + + Added "explcit" create/drop/execute support for sequences (i.e. you can + pass a "connectable" to each of those methods on Sequence). + + .. change:: + :tags: metadata + :tickets: + + Better quoting of identifiers when manipulating schemas. + + .. change:: + :tags: metadata + :tickets: + + Standardized the behavior for table reflection where types can't be + located; NullType is substituted instead, warning is raised. + + .. change:: + :tags: metadata + :tickets: 606 + + ColumnCollection (i.e. the 'c' attribute on tables) follows dictionary + semantics for "__contains__" + + .. change:: + :tags: engines + :tickets: + + Speed! The mechanics of result processing and bind parameter processing + have been overhauled, streamlined and optimized to issue as little method + calls as possible. Bench tests for mass INSERT and mass rowset iteration + both show 0.4 to be over twice as fast as 0.3, using 68% fewer function + calls. + + .. change:: + :tags: engines + :tickets: + + You can now hook into the pool lifecycle and run SQL statements or other + logic at new each DBAPI connection, pool check-out and check-in. + + .. change:: + :tags: engines + :tickets: + + Connections gain a .properties collection, with contents scoped to the + lifetime of the underlying DBAPI connection + + .. change:: + :tags: engines + :tickets: + + Removed auto_close_cursors and disallow_open_cursors arguments from Pool; + reduces overhead as cursors are normally closed by ResultProxy and + Connection. + + .. change:: + :tags: extensions + :tickets: + + proxyengine is temporarily removed, pending an actually working + replacement. + + .. change:: + :tags: extensions + :tickets: + + SelectResults has been replaced by Query. SelectResults / + SelectResultsExt still exist but just return a slightly modified Query + object for backwards-compatibility. join_to() method from SelectResults + isn't present anymore, need to use join(). + + .. change:: + :tags: mysql + :tickets: + + Table and column names loaded via reflection are now Unicode. + + .. change:: + :tags: mysql + :tickets: + + All standard column types are now supported, including SET. + + .. change:: + :tags: mysql + :tickets: + + Table reflection can now be performed in as little as one round-trip. + + .. change:: + :tags: mysql + :tickets: + + ANSI and ANSI_QUOTES sql modes are now supported. + + .. change:: + :tags: mysql + :tickets: + + Indexes are now reflected. + + .. change:: + :tags: postgres + :tickets: + + Added PGArray datatype for using postgres array datatypes. + + .. change:: + :tags: oracle + :tickets: 507 + + Very rudimental support for OUT parameters added; use sql.outparam(name, + type) to set up an OUT parameter, just like bindparam(); after execution, + values are avaiable via result.out_parameters dictionary. diff --git a/doc/build/changelog/changelog_05.rst b/doc/build/changelog/changelog_05.rst new file mode 100644 index 0000000000..0bcc1aa3f1 --- /dev/null +++ b/doc/build/changelog/changelog_05.rst @@ -0,0 +1,3775 @@ + +============== +0.5 Changelog +============== + + +.. changelog:: + :version: 0.5.9 + :released: + + .. change:: + :tags: sql + :tickets: 1661 + + Fixed erroneous self_group() call in expression package. + +.. changelog:: + :version: 0.5.8 + :released: Sat Jan 16 2010 + + .. change:: + :tags: sql + :tickets: + + The copy() method on Column now supports uninitialized, + unnamed Column objects. This allows easy creation of + declarative helpers which place common columns on multiple + subclasses. + + .. change:: + :tags: sql + :tickets: + + Default generators like Sequence() translate correctly + across a copy() operation. + + .. change:: + :tags: sql + :tickets: + + Sequence() and other DefaultGenerator objects are accepted + as the value for the "default" and "onupdate" keyword + arguments of Column, in addition to being accepted + positionally. + + .. change:: + :tags: sql + :tickets: 1568, 1617 + + Fixed a column arithmetic bug that affected column + correspondence for cloned selectables which contain + free-standing column expressions. This bug is + generally only noticeable when exercising newer + ORM behavior only availble in 0.6 via, + but is more correct at the SQL expression level + as well. + + .. change:: + :tags: postgresql + :tickets: 1647 + + The extract() function, which was slightly improved in + 0.5.7, needed a lot more work to generate the correct + typecast (the typecasts appear to be necessary in PG's + EXTRACT quite a lot of the time). The typecast is + now generated using a rule dictionary based + on PG's documentation for date/time/interval arithmetic. + It also accepts text() constructs again, which was broken + in 0.5.7. + + .. change:: + :tags: firebird + :tickets: 1646 + + Recognize more errors as disconnections. + +.. changelog:: + :version: 0.5.7 + :released: Sat Dec 26 2009 + + .. change:: + :tags: orm + :tickets: 1543 + + contains_eager() now works with the automatically + generated subquery that results when you say + "query(Parent).join(Parent.somejoinedsubclass)", i.e. + when Parent joins to a joined-table-inheritance subclass. + Previously contains_eager() would erroneously add the + subclass table to the query separately producing a + cartesian product. An example is in the ticket + description. + + .. change:: + :tags: orm + :tickets: 1553 + + query.options() now only propagate to loaded objects + for potential further sub-loads only for options where + such behavior is relevant, keeping + various unserializable options like those generated + by contains_eager() out of individual instance states. + + .. change:: + :tags: orm + :tickets: 1054 + + Session.execute() now locates table- and + mapper-specific binds based on a passed + in expression which is an insert()/update()/delete() + construct. + + .. change:: + :tags: orm + :tickets: + + Session.merge() now properly overwrites a many-to-one or + uselist=False attribute to None if the attribute + is also None in the given object to be merged. + + .. change:: + :tags: orm + :tickets: 1618 + + Fixed a needless select which would occur when merging + transient objects that contained a null primary key + identifier. + + .. change:: + :tags: orm + :tickets: 1585 + + Mutable collection passed to the "extension" attribute + of relation(), column_property() etc. will not be mutated + or shared among multiple instrumentation calls, preventing + duplicate extensions, such as backref populators, + from being inserted into the list. + + .. change:: + :tags: orm + :tickets: 1504 + + Fixed the call to get_committed_value() on CompositeProperty. + + .. change:: + :tags: orm + :tickets: 1602 + + Fixed bug where Query would crash if a join() with no clear + "left" side were called when a non-mapped column entity + appeared in the columns list. + + .. change:: + :tags: orm + :tickets: 1616, 1480 + + Fixed bug whereby composite columns wouldn't load properly + when configured on a joined-table subclass, introduced in + version 0.5.6 as a result of the fix for. thx to Scott Torborg. + + .. change:: + :tags: orm + :tickets: 1556 + + The "use get" behavior of many-to-one relations, i.e. that a + lazy load will fallback to the possibly cached query.get() + value, now works across join conditions where the two compared + types are not exactly the same class, but share the same + "affinity" - i.e. Integer and SmallInteger. Also allows + combinations of reflected and non-reflected types to work + with 0.5 style type reflection, such as PGText/Text (note 0.6 + reflects types as their generic versions). + + .. change:: + :tags: orm + :tickets: 1436 + + Fixed bug in query.update() when passing Cls.attribute + as keys in the value dict and using synchronize_session='expire' + ('fetch' in 0.6). + + .. change:: + :tags: sql + :tickets: 1603 + + Fixed bug in two-phase transaction whereby commit() method + didn't set the full state which allows subsequent close() + call to succeed. + + .. change:: + :tags: sql + :tickets: + + Fixed the "numeric" paramstyle, which apparently is the + default paramstyle used by Informixdb. + + .. change:: + :tags: sql + :tickets: 1574 + + Repeat expressions in the columns clause of a select + are deduped based on the identity of each clause element, + not the actual string. This allows positional + elements to render correctly even if they all render + identically, such as "qmark" style bind parameters. + + .. change:: + :tags: sql + :tickets: 1632 + + The cursor associated with connection pool connections + (i.e. _CursorFairy) now proxies `__iter__()` to the + underlying cursor correctly. + + .. change:: + :tags: sql + :tickets: 1556 + + types now support an "affinity comparison" operation, i.e. + that an Integer/SmallInteger are "compatible", or + a Text/String, PickleType/Binary, etc. Part of. + + .. change:: + :tags: sql + :tickets: 1641 + + Fixed bug preventing alias() of an alias() from being + cloned or adapted (occurs frequently in ORM operations). + + .. change:: + :tags: sqlite + :tickets: 1439 + + sqlite dialect properly generates CREATE INDEX for a table + that is in an alternate schema. + + .. change:: + :tags: postgresql + :tickets: 1085 + + Added support for reflecting the DOUBLE PRECISION type, + via a new postgres.PGDoublePrecision object. + This is postgresql.DOUBLE_PRECISION in 0.6. + + .. change:: + :tags: postgresql + :tickets: 460 + + Added support for reflecting the INTERVAL YEAR TO MONTH + and INTERVAL DAY TO SECOND syntaxes of the INTERVAL + type. + + .. change:: + :tags: postgresql + :tickets: 1576 + + Corrected the "has_sequence" query to take current schema, + or explicit sequence-stated schema, into account. + + .. change:: + :tags: postgresql + :tickets: 1611 + + Fixed the behavior of extract() to apply operator + precedence rules to the "::" operator when applying + the "timestamp" cast - ensures proper parenthesization. + + .. change:: + :tags: mssql + :tickets: 1561 + + Changed the name of TrustedConnection to + Trusted_Connection when constructing pyodbc connect + arguments + + .. change:: + :tags: oracle + :tickets: 1637 + + The "table_names" dialect function, used by MetaData + .reflect(), omits "index overflow tables", a system + table generated by Oracle when "index only tables" + with overflow are used. These tables aren't accessible + via SQL and can't be reflected. + + .. change:: + :tags: ext + :tickets: 1570, 1523 + + A column can be added to a joined-table declarative + superclass after the class has been constructed + (i.e. via class-level attribute assignment), and + the column will be propagated down to + subclasses. This is the reverse + situation as that of, fixed in 0.5.6. + + .. change:: + :tags: ext + :tickets: 1491 + + Fixed a slight inaccuracy in the sharding example. + Comparing equivalence of columns in the ORM is best + accomplished using col1.shares_lineage(col2). + + .. change:: + :tags: ext + :tickets: 1606 + + Removed unused `load()` method from ShardedQuery. + +.. changelog:: + :version: 0.5.6 + :released: Sat Sep 12 2009 + + .. change:: + :tags: orm + :tickets: 1300 + + Fixed bug whereby inheritance discriminator part of a + composite primary key would fail on updates. + Continuation of. + + .. change:: + :tags: orm + :tickets: 1507 + + Fixed bug which disallowed one side of a many-to-many + bidirectional reference to declare itself as "viewonly" + + .. change:: + :tags: orm + :tickets: 1526 + + Added an assertion that prevents a @validates function + or other AttributeExtension from loading an unloaded + collection such that internal state may be corrupted. + + .. change:: + :tags: orm + :tickets: 1519 + + Fixed bug which prevented two entities from mutually + replacing each other's primary key values within a single + flush() for some orderings of operations. + + .. change:: + :tags: orm + :tickets: 1485 + + Fixed an obscure issue whereby a joined-table subclass + with a self-referential eager load on the base class + would populate the related object's "subclass" table with + data from the "subclass" table of the parent. + + .. change:: + :tags: orm + :tickets: 1477 + + relations() now have greater ability to be "overridden", + meaning a subclass that explicitly specifies a relation() + overriding that of the parent class will be honored + during a flush. This is currently to support + many-to-many relations from concrete inheritance setups. + Outside of that use case, YMMV. + + .. change:: + :tags: orm + :tickets: 1483 + + Squeezed a few more unnecessary "lazy loads" out of + relation(). When a collection is mutated, many-to-one + backrefs on the other side will not fire off to load + the "old" value, unless "single_parent=True" is set. + A direct assignment of a many-to-one still loads + the "old" value in order to update backref collections + on that value, which may be present in the session + already, thus maintaining the 0.5 behavioral contract. + + .. change:: + :tags: orm + :tickets: 1480 + + Fixed bug whereby a load/refresh of joined table + inheritance attributes which were based on + column_property() or similar would fail to evaluate. + + .. change:: + :tags: orm + :tickets: 1488 + + Improved support for MapperProperty objects overriding + that of an inherited mapper for non-concrete + inheritance setups - attribute extensions won't randomly + collide with each other. + + .. change:: + :tags: orm + :tickets: 1487 + + UPDATE and DELETE do not support ORDER BY, LIMIT, OFFSET, + etc. in standard SQL. Query.update() and Query.delete() + now raise an exception if any of limit(), offset(), + order_by(), group_by(), or distinct() have been + called. + + .. change:: + :tags: orm + :tickets: + + Added AttributeExtension to sqlalchemy.orm.__all__ + + .. change:: + :tags: orm + :tickets: 1476 + + Improved error message when query() is called with + a non-SQL /entity expression. + + .. change:: + :tags: orm + :tickets: 1440 + + Using False or 0 as a polymorphic discriminator now + works on the base class as well as a subclass. + + .. change:: + :tags: orm + :tickets: 1424 + + Added enable_assertions(False) to Query which disables + the usual assertions for expected state - used + by Query subclasses to engineer custom state.. See + http://www.sqlalchemy.org/trac/wiki/UsageRecipes/PreFilteredQuery + for an example. + + .. change:: + :tags: orm + :tickets: 1501 + + Fixed recursion issue which occured if a mapped object's + `__len__()` or `__nonzero__()` method resulted in state + changes. + + .. change:: + :tags: orm + :tickets: 1506 + + Fixed incorrect exception raise in + Weak/StrongIdentityMap.add() + + .. change:: + :tags: orm + :tickets: 1522 + + Fixed the error message for "could not find a FROM clause" + in query.join() which would fail to issue correctly + if the query was against a pure SQL construct. + + .. change:: + :tags: orm + :tickets: 1486 + + Fixed a somewhat hypothetical issue which would result + in the wrong primary key being calculated for a mapper + using the old polymorphic_union function - but this + is old stuff. + + .. change:: + :tags: sql + :tickets: 1373 + + Fixed column.copy() to copy defaults and onupdates. + + .. change:: + :tags: sql + :tickets: + + Fixed a bug in extract() introduced in 0.5.4 whereby + the string "field" argument was getting treated as a + ClauseElement, causing various errors within more + complex SQL transformations. + + .. change:: + :tags: sql + :tickets: 1420 + + Unary expressions such as DISTINCT propagate their + type handling to result sets, allowing conversions like + unicode and such to take place. + + .. change:: + :tags: sql + :tickets: 1482 + + Fixed bug in Table and Column whereby passing empty + dict for "info" argument would raise an exception. + + .. change:: + :tags: oracle + :tickets: 1309 + + Backported 0.6 fix for Oracle alias names not getting + truncated. + + .. change:: + :tags: ext + :tickets: 1446 + + The collection proxies produced by associationproxy are now + pickleable. A user-defined proxy_factory however + is still not pickleable unless it defines __getstate__ + and __setstate__. + + .. change:: + :tags: ext + :tickets: 1468 + + Declarative will raise an informative exception if + __table_args__ is passed as a tuple with no dict argument. + Improved documentation. + + .. change:: + :tags: ext + :tickets: 1527 + + Table objects declared in the MetaData can now be used + in string expressions sent to primaryjoin/secondaryjoin/ + secondary - the name is pulled from the MetaData of the + declarative base. + + .. change:: + :tags: ext + :tickets: 1523 + + A column can be added to a joined-table subclass after + the class has been constructed (i.e. via class-level + attribute assignment). The column is added to the underlying + Table as always, but now the mapper will rebuild its + "join" to include the new column, instead of raising + an error about "no such column, use column_property() + instead". + + .. change:: + :tags: test + :tickets: + + Added examples into the test suite so they get exercised + regularly and cleaned up a couple deprecation warnings. + +.. changelog:: + :version: 0.5.5 + :released: Mon Jul 13 2009 + + .. change:: + :tags: general + :tickets: 970 + + unit tests have been migrated from unittest to nose. See + README.unittests for information on how to run the tests. + + .. change:: + :tags: orm + :tickets: + + The "foreign_keys" argument of relation() will now propagate + automatically to the backref in the same way that primaryjoin + and secondaryjoin do. For the extremely rare use case where + the backref of a relation() has intentionally different + "foreign_keys" configured, both sides now need to be + configured explicity (if they do in fact require this setting, + see the next note...). + + .. change:: + :tags: orm + :tickets: + + ...the only known (and really, really rare) use case where a + different foreign_keys setting was used on the + forwards/backwards side, a composite foreign key that + partially points to its own columns, has been enhanced such + that the fk->itself aspect of the relation won't be used to + determine relation direction. + + .. change:: + :tags: orm + :tickets: + + Session.mapper is now *deprecated*. + + Call session.add() if you'd like a free-standing object to be + part of your session. Otherwise, a DIY version of + Session.mapper is now documented at + http://www.sqlalchemy.org/trac/wiki/UsageRecipes/SessionAwareMapper + The method will remain deprecated throughout 0.6. + + .. change:: + :tags: orm + :tickets: 1431 + + Fixed Query being able to join() from individual columns of a + joined-table subclass entity, i.e. query(SubClass.foo, + SubcClass.bar).join(). In most cases, an error + "Could not find a FROM clause to join from" would be + raised. In a few others, the result would be returned in terms + of the base class rather than the subclass - so applications + which relied on this erroneous result need to be + adjusted. + + .. change:: + :tags: orm + :tickets: 1461 + + Fixed a bug involving contains_eager(), which would apply + itself to a secondary (i.e. lazy) load in a particular rare + case, producing cartesian products. improved the targeting of + query.options() on secondary loads overall. + + .. change:: + :tags: orm + :tickets: + + Fixed bug introduced in 0.5.4 whereby Composite types fail + when default-holding columns are flushed. + + .. change:: + :tags: orm + :tickets: 1426 + + Fixed another 0.5.4 bug whereby mutable attributes + (i.e. PickleType) wouldn't be deserialized correctly when the + whole object was serialized. + + .. change:: + :tags: orm + :tickets: + + Fixed bug whereby session.is_modified() would raise an + exception if any synonyms were in use. + + .. change:: + :tags: orm + :tickets: + + Fixed potential memory leak whereby previously pickled objects + placed back in a session would not be fully garbage collected + unless the Session were explicitly closed out. + + .. change:: + :tags: orm + :tickets: + + Fixed bug whereby list-based attributes, like pickletype and + PGArray, failed to be merged() properly. + + .. change:: + :tags: orm + :tickets: + + Repaired non-working attributes.set_committed_value function. + + .. change:: + :tags: orm + :tickets: + + Trimmed the pickle format for InstanceState which should + further reduce the memory footprint of pickled instances. The + format should be backwards compatible with that of 0.5.4 and + previous. + + .. change:: + :tags: orm + :tickets: 1463 + + sqlalchemy.orm.join and sqlalchemy.orm.outerjoin are now + added to __all__ in sqlalchemy.orm.*. + + .. change:: + :tags: orm + :tickets: 1458 + + Fixed bug where Query exception raise would fail when + a too-short composite primary key value were passed to + get(). + + .. change:: + :tags: sql + :tickets: + + Removed an obscure feature of execute() (including connection, + engine, Session) whereby a bindparam() construct can be sent + as a key to the params dictionary. This usage is undocumented + and is at the core of an issue whereby the bindparam() object + created implicitly by a text() construct may have the same + hash value as a string placed in the params dictionary and may + result in an inappropriate match when computing the final bind + parameters. Internal checks for this condition would add + significant latency to the critical task of parameter + rendering, so the behavior is removed. This is a backwards + incompatible change for any application that may have been + using this feature, however the feature has never been + documented. + + .. change:: + :tags: engine/pool + :tickets: + + Implemented recreate() for StaticPool. + +.. changelog:: + :version: 0.5.4p2 + :released: Tue May 26 2009 + + .. change:: + :tags: sql + :tickets: + + Repaired the printing of SQL exceptions which are not + based on parameters or are not executemany() style. + + .. change:: + :tags: postgresql + :tickets: + + Deprecated the hardcoded TIMESTAMP function, which when + used as func.TIMESTAMP(value) would render "TIMESTAMP value". + This breaks on some platforms as PostgreSQL doesn't allow + bind parameters to be used in this context. The hard-coded + uppercase is also inappropriate and there's lots of other + PG casts that we'd need to support. So instead, use + text constructs i.e. select(["timestamp '12/05/09'"]). + +.. changelog:: + :version: 0.5.4p1 + :released: Mon May 18 2009 + + .. change:: + :tags: orm + :tickets: + + Fixed an attribute error introduced in 0.5.4 which would + occur when merge() was used with an incomplete object. + +.. changelog:: + :version: 0.5.4 + :released: Sun May 17 2009 + + .. change:: + :tags: orm + :tickets: 1398 + + Significant performance enhancements regarding Sessions/flush() + in conjunction with large mapper graphs, large numbers of + objects: + + - Removed all* O(N) scanning behavior from the flush() process, + i.e. operations that were scanning the full session, + including an extremely expensive one that was erroneously + assuming primary key values were changing when this + was not the case. + + * one edge case remains which may invoke a full scan, + if an existing primary key attribute is modified + to a new value. + + - The Session's "weak referencing" behavior is now *full* - + no strong references whatsoever are made to a mapped object + or related items/collections in its __dict__. Backrefs and + other cycles in objects no longer affect the Session's ability + to lose all references to unmodified objects. Objects with + pending changes still are maintained strongly until flush. + + + The implementation also improves performance by moving + the "resurrection" process of garbage collected items + to only be relevant for mappings that map "mutable" + attributes (i.e. PickleType, composite attrs). This removes + overhead from the gc process and simplifies internal + behavior. + + If a "mutable" attribute change is the sole change on an object + which is then dereferenced, the mapper will not have access to + other attribute state when the UPDATE is issued. This may present + itself differently to some MapperExtensions. + + The change also affects the internal attribute API, but not + the AttributeExtension interface nor any of the publically + documented attribute functions. + + - The unit of work no longer genererates a graph of "dependency" + processors for the full graph of mappers during flush(), instead + creating such processors only for those mappers which represent + objects with pending changes. This saves a tremendous number + of method calls in the context of a large interconnected + graph of mappers. + + - Cached a wasteful "table sort" operation that previously + occured multiple times per flush, also removing significant + method call count from flush(). + + - Other redundant behaviors have been simplified in + mapper._save_obj(). + + .. change:: + :tags: orm + :tickets: + + Modified query_cls on DynamicAttributeImpl to accept a full + mixin version of the AppenderQuery, which allows subclassing + the AppenderMixin. + + .. change:: + :tags: orm + :tickets: 1300 + + The "polymorphic discriminator" column may be part of a + primary key, and it will be populated with the correct + discriminator value. + + .. change:: + :tags: orm + :tickets: + + Fixed the evaluator not being able to evaluate IS NULL clauses. + + .. change:: + :tags: orm + :tickets: 1352 + + Fixed the "set collection" function on "dynamic" relations to + initiate events correctly. Previously a collection could only + be assigned to a pending parent instance, otherwise modified + events would not be fired correctly. Set collection is now + compatible with merge(), fixes. + + .. change:: + :tags: orm + :tickets: + + Allowed pickling of PropertyOption objects constructed with + instrumented descriptors; previously, pickle errors would occur + when pickling an object which was loaded with a descriptor-based + option, such as query.options(eagerload(MyClass.foo)). + + .. change:: + :tags: orm + :tickets: 1357 + + Lazy loader will not use get() if the "lazy load" SQL clause + matches the clause used by get(), but contains some parameters + hardcoded. Previously the lazy strategy would fail with the + get(). Ideally get() would be used with the hardcoded + parameters but this would require further development. + + .. change:: + :tags: orm + :tickets: 1391 + + MapperOptions and other state associated with query.options() + is no longer bundled within callables associated with each + lazy/deferred-loading attribute during a load. + The options are now associated with the instance's + state object just once when it's populated. This removes + the need in most cases for per-instance/attribute loader + objects, improving load speed and memory overhead for + individual instances. + + .. change:: + :tags: orm + :tickets: 1360 + + Fixed another location where autoflush was interfering + with session.merge(). autoflush is disabled completely + for the duration of merge() now. + + .. change:: + :tags: orm + :tickets: 1406 + + Fixed bug which prevented "mutable primary key" dependency + logic from functioning properly on a one-to-one + relation(). + + .. change:: + :tags: orm + :tickets: + + Fixed bug in relation(), introduced in 0.5.3, + whereby a self referential relation + from a base class to a joined-table subclass would + not configure correctly. + + .. change:: + :tags: orm + :tickets: + + Fixed obscure mapper compilation issue when inheriting + mappers are used which would result in un-initialized + attributes. + + .. change:: + :tags: orm + :tickets: + + Fixed documentation for session weak_identity_map - + the default value is True, indicating a weak + referencing map in use. + + .. change:: + :tags: orm + :tickets: 1376 + + Fixed a unit of work issue whereby the foreign + key attribute on an item contained within a collection + owned by an object being deleted would not be set to + None if the relation() was self-referential. + + .. change:: + :tags: orm + :tickets: 1378 + + Fixed Query.update() and Query.delete() failures with eagerloaded + relations. + + .. change:: + :tags: orm + :tickets: + + It is now an error to specify both columns of a binary primaryjoin + condition in the foreign_keys or remote_side collection. Whereas + previously it was just nonsensical, but would succeed in a + non-deterministic way. + + .. change:: + :tags: ticket: 594, 1341, schema + :tickets: + + Added a quote_schema() method to the IdentifierPreparer class + so that dialects can override how schemas get handled. This + enables the MSSQL dialect to treat schemas as multipart + identifiers, such as 'database.owner'. + + .. change:: + :tags: sql + :tickets: + + Back-ported the "compiler" extension from SQLA 0.6. This + is a standardized interface which allows the creation of custom + ClauseElement subclasses and compilers. In particular it's + handy as an alternative to text() when you'd like to + build a construct that has database-specific compilations. + See the extension docs for details. + + .. change:: + :tags: sql + :tickets: 1413 + + Exception messages are truncated when the list of bound + parameters is larger than 10, preventing enormous + multi-page exceptions from filling up screens and logfiles + for large executemany() statements. + + .. change:: + :tags: sql + :tickets: + + ``sqlalchemy.extract()`` is now dialect sensitive and can + extract components of timestamps idiomatically across the + supported databases, including SQLite. + + .. change:: + :tags: sql + :tickets: 1353 + + Fixed __repr__() and other _get_colspec() methods on + ForeignKey constructed from __clause_element__() style + construct (i.e. declarative columns). + + .. change:: + :tags: mysql + :tickets: 1405 + + Reflecting a FOREIGN KEY construct will take into account + a dotted schema.tablename combination, if the foreign key + references a table in a remote schema. + + .. change:: + :tags: mssql + :tickets: + + Modified how savepoint logic works to prevent it from + stepping on non-savepoint oriented routines. Savepoint + support is still very experimental. + + .. change:: + :tags: mssql + :tickets: 1310 + + Added in reserved words for MSSQL that covers version 2008 + and all prior versions. + + .. change:: + :tags: mssql + :tickets: 1343 + + Corrected problem with information schema not working with a + binary collation based database. Cleaned up information schema + since it is only used by mssql now. + + .. change:: + :tags: sqlite + :tickets: 1402 + + Corrected the SLBoolean type so that it properly treats only 1 + as True. + + .. change:: + :tags: sqlite + :tickets: 1273 + + Corrected the float type so that it correctly maps to a + SLFloat type when being reflected. + + .. change:: + :tags: extensions + :tickets: 1379 + + Fixed adding of deferred or other column properties to a + declarative class. + +.. changelog:: + :version: 0.5.3 + :released: Tue Mar 24 2009 + + .. change:: + :tags: orm + :tickets: 1315 + + The "objects" argument to session.flush() is deprecated. + State which represents the linkage between a parent and + child object does not support "flushed" status on + one side of the link and not the other, so supporting + this operation leads to misleading results. + + .. change:: + :tags: orm + :tickets: + + Query now implements __clause_element__() which produces + its selectable, which means a Query instance can be accepted + in many SQL expressions, including col.in_(query), + union(query1, query2), select([foo]).select_from(query), + etc. + + .. change:: + :tags: orm + :tickets: 1337 + + Query.join() can now construct multiple FROM clauses, if + needed. Such as, query(A, B).join(A.x).join(B.y) + might say SELECT A.*, B.* FROM A JOIN X, B JOIN Y. + Eager loading can also tack its joins onto those + multiple FROM clauses. + + .. change:: + :tags: orm + :tickets: 1347 + + Fixed bug in dynamic_loader() where append/remove events + after construction time were not being propagated to the + UOW to pick up on flush(). + + .. change:: + :tags: orm + :tickets: + + Fixed bug where column_prefix wasn't being checked before + not mapping an attribute that already had class-level + name present. + + .. change:: + :tags: orm + :tickets: 1315 + + a session.expire() on a particular collection attribute + will clear any pending backref additions as well, so that + the next access correctly returns only what was present + in the database. Presents some degree of a workaround for, although we are considering removing the + flush([objects]) feature altogether. + + .. change:: + :tags: orm + :tickets: + + Session.scalar() now converts raw SQL strings to text() + the same way Session.execute() does and accepts same + alternative **kw args. + + .. change:: + :tags: orm + :tickets: + + improvements to the "determine direction" logic of + relation() such that the direction of tricky situations + like mapper(A.join(B)) -> relation-> mapper(B) can be + determined. + + .. change:: + :tags: orm + :tickets: 1306 + + When flushing partial sets of objects using session.flush([somelist]), + pending objects which remain pending after the operation won't + inadvertently be added as persistent. + + .. change:: + :tags: orm + :tickets: 1314 + + Added "post_configure_attribute" method to InstrumentationManager, + so that the "listen_for_events.py" example works again. + + .. change:: + :tags: orm + :tickets: + + a forward and complementing backwards reference which are both + of the same direction, i.e. ONETOMANY or MANYTOONE, + is now detected, and an error message is raised. + Saves crazy CircularDependencyErrors later on. + + .. change:: + :tags: orm + :tickets: + + Fixed bugs in Query regarding simultaneous selection of + multiple joined-table inheritance entities with common base + classes: + + - previously the adaption applied to "B" on + "A JOIN B" would be erroneously partially applied + to "A". + + - comparisons on relations (i.e. A.related==someb) + were not getting adapted when they should. + + - Other filterings, like + query(A).join(A.bs).filter(B.foo=='bar'), were erroneously + adapting "B.foo" as though it were an "A". + + .. change:: + :tags: orm + :tickets: 1325 + + Fixed adaptation of EXISTS clauses via any(), has(), etc. + in conjunction with an aliased object on the left and + of_type() on the right. + + .. change:: + :tags: orm + :tickets: + + Added an attribute helper method ``set_committed_value`` in + sqlalchemy.orm.attributes. Given an object, attribute name, + and value, will set the value on the object as part of its + "committed" state, i.e. state that is understood to have + been loaded from the database. Helps with the creation of + homegrown collection loaders and such. + + .. change:: + :tags: orm + :tickets: + + Query won't fail with weakref error when a non-mapper/class + instrumented descriptor is passed, raises + "Invalid column expession". + + .. change:: + :tags: orm + :tickets: + + Query.group_by() properly takes into account aliasing applied + to the FROM clause, such as with select_from(), using + with_polymorphic(), or using from_self(). + + .. change:: + :tags: sql + :tickets: + + An alias() of a select() will convert to a "scalar subquery" + when used in an unambiguously scalar context, i.e. it's used + in a comparison operation. This applies to + the ORM when using query.subquery() as well. + + .. change:: + :tags: sql + :tickets: 1302 + + Fixed missing _label attribute on Function object, others + when used in a select() with use_labels (such as when used + in an ORM column_property()). + + .. change:: + :tags: sql + :tickets: 1309 + + anonymous alias names now truncate down to the max length + allowed by the dialect. More significant on DBs like + Oracle with very small character limits. + + .. change:: + :tags: sql + :tickets: + + the __selectable__() interface has been replaced entirely + by __clause_element__(). + + .. change:: + :tags: sql + :tickets: 1299 + + The per-dialect cache used by TypeEngine to cache + dialect-specific types is now a WeakKeyDictionary. + This to prevent dialect objects from + being referenced forever for an application that + creates an arbitrarily large number of engines + or dialects. There is a small performance penalty + which will be resolved in 0.6. + + .. change:: + :tags: sqlite + :tickets: + + Fixed SQLite reflection methods so that non-present + cursor.description, which triggers an auto-cursor + close, will be detected so that no results doesn't + fail on recent versions of pysqlite which raise + an error when fetchone() called with no rows present. + + .. change:: + :tags: postgresql + :tickets: + + Index reflection won't fail when an index with + multiple expressions is encountered. + + .. change:: + :tags: postgresql + :tickets: 1327 + + Added PGUuid and PGBit types to + sqlalchemy.databases.postgres. + + .. change:: + :tags: postgresql + :tickets: 1327 + + Refection of unknown PG types won't crash when those + types are specified within a domain. + + .. change:: + :tags: mssql + :tickets: + + Preliminary support for pymssql 1.0.1 + + .. change:: + :tags: mssql + :tickets: + + Corrected issue on mssql where max_identifier_length was + not being respected. + + .. change:: + :tags: extensions + :tickets: + + Fixed a recursive pickling issue in serializer, triggered + by an EXISTS or other embedded FROM construct. + + .. change:: + :tags: extensions + :tickets: + + Declarative locates the "inherits" class using a search + through __bases__, to skip over mixins that are local + to subclasses. + + .. change:: + :tags: extensions + :tickets: + + Declarative figures out joined-table inheritance primary join + condition even if "inherits" mapper argument is given + explicitly. + + .. change:: + :tags: extensions + :tickets: + + Declarative will properly interpret the "foreign_keys" argument + on a backref() if it's a string. + + .. change:: + :tags: extensions + :tickets: + + Declarative will accept a table-bound column as a property + when used in conjunction with __table__, if the column is already + present in __table__. The column will be remapped to the given + key the same way as when added to the mapper() properties dict. + +.. changelog:: + :version: 0.5.2 + :released: Sat Jan 24 2009 + + .. change:: + :tags: orm + :tickets: + + Further refined 0.5.1's warning about delete-orphan cascade + placed on a many-to-many relation. First, the bad news: + the warning will apply to both many-to-many as well as + many-to-one relations. This is necessary since in both + cases, SQLA does not scan the full set of potential parents + when determining "orphan" status - for a persistent object + it only detects an in-python de-association event to establish + the object as an "orphan". Next, the good news: to support + one-to-one via a foreign key or assocation table, or to + support one-to-many via an association table, a new flag + single_parent=True may be set which indicates objects + linked to the relation are only meant to have a single parent. + The relation will raise an error if multiple parent-association + events occur within Python. + + .. change:: + :tags: orm + :tickets: 1292 + + Adjusted the attribute instrumentation change from 0.5.1 to + fully establish instrumentation for subclasses where the mapper + was created after the superclass had already been fully + instrumented. + + .. change:: + :tags: orm + :tickets: + + Fixed bug in delete-orphan cascade whereby two one-to-one + relations from two different parent classes to the same target + class would prematurely expunge the instance. + + .. change:: + :tags: orm + :tickets: + + Fixed an eager loading bug whereby self-referential eager + loading would prevent other eager loads, self referential or not, + from joining to the parent JOIN properly. Thanks to Alex K + for creating a great test case. + + .. change:: + :tags: orm + :tickets: + + session.expire() and related methods will not expire() unloaded + deferred attributes. This prevents them from being needlessly + loaded when the instance is refreshed. + + .. change:: + :tags: orm + :tickets: 1293 + + query.join()/outerjoin() will now properly join an aliased() + construct to the existing left side, even if query.from_self() + or query.select_from(someselectable) has been called. + + .. change:: + :tags: sql + :tickets: 1284 + + Further fixes to the "percent signs and spaces in column/table + names" functionality. + + .. change:: + :tags: mssql + :tickets: 1291 + + Restored convert_unicode handling. Results were being passed + on through without conversion. + + .. change:: + :tags: mssql + :tickets: 1282 + + Really fixing the decimal handling this time.. + + .. change:: + :tags: Ticket:1289, mssql + :tickets: + + Modified table reflection code to use only kwargs when + constructing tables. + +.. changelog:: + :version: 0.5.1 + :released: Sat Jan 17 2009 + + .. change:: + :tags: orm + :tickets: + + Removed an internal join cache which could potentially leak + memory when issuing query.join() repeatedly to ad-hoc + selectables. + + .. change:: + :tags: orm + :tickets: + + The "clear()", "save()", "update()", "save_or_update()" + Session methods have been deprecated, replaced by + "expunge_all()" and "add()". "expunge_all()" has also + been added to ScopedSession. + + .. change:: + :tags: orm + :tickets: + + Modernized the "no mapped table" exception and added a more + explicit __table__/__tablename__ exception to declarative. + + .. change:: + :tags: orm + :tickets: 1237 + + Concrete inheriting mappers now instrument attributes which + are inherited from the superclass, but are not defined for + the concrete mapper itself, with an InstrumentedAttribute that + issues a descriptive error when accessed. + + .. change:: + :tags: orm + :tickets: 1237, 781 + + Added a new `relation()` keyword `back_populates`. This + allows configuation of backreferences using explicit + relations. This is required when creating + bidirectional relations between a hierarchy of concrete + mappers and another class. + + .. change:: + :tags: orm + :tickets: 1237 + + Test coverage added for `relation()` objects specified on + concrete mappers. + + .. change:: + :tags: orm + :tickets: 1276 + + Query.from_self() as well as query.subquery() both disable + the rendering of eager joins inside the subquery produced. + The "disable all eager joins" feature is available publically + via a new query.enable_eagerloads() generative. + + .. change:: + :tags: orm + :tickets: + + Added a rudimental series of set operations to Query that + receive Query objects as arguments, including union(), + union_all(), intersect(), except_(), insertsect_all(), + except_all(). See the API documentation for + Query.union() for examples. + + .. change:: + :tags: orm + :tickets: + + Fixed bug that prevented Query.join() and eagerloads from + attaching to a query that selected from a union or aliased union. + + .. change:: + :tags: orm + :tickets: 1237 + + A short documentation example added for bidirectional + relations specified on concrete mappers. + + .. change:: + :tags: orm + :tickets: 1269 + + Mappers now instrument class attributes upon construction + with the final InstrumentedAttribute object which remains + persistent. The `_CompileOnAttr`/`__getattribute__()` + methodology has been removed. The net effect is that + Column-based mapped class attributes can now be used fully + at the class level without invoking a mapper compilation + operation, greatly simplifying typical usage patterns + within declarative. + + .. change:: + :tags: orm + :tickets: + + ColumnProperty (and front-end helpers such as ``deferred``) no + longer ignores unknown **keyword arguments. + + .. change:: + :tags: orm + :tickets: + + Fixed a bug with the unitofwork's "row switch" mechanism, + i.e. the conversion of INSERT/DELETE into an UPDATE, when + combined with joined-table inheritance and an object + which contained no defined values for the child table where + an UPDATE with no SET clause would be rendered. + + .. change:: + :tags: orm + :tickets: 1281 + + Using delete-orphan on a many-to-many relation is deprecated. + This produces misleading or erroneous results since SQLA does + not retrieve the full list of "parents" for m2m. To get delete-orphan + behavior with an m2m table, use an explcit association class + so that the individual association row is treated as a parent. + + .. change:: + :tags: orm + :tickets: 1281 + + delete-orphan cascade always requires delete cascade. Specifying + delete-orphan without delete now raises a deprecation warning. + + .. change:: + :tags: sql + :tickets: 1256 + + Improved the methodology to handling percent signs in column + names from. Added more tests. MySQL and + PostgreSQL dialects still do not issue correct CREATE TABLE + statements for identifiers with percent signs in them. + + .. change:: + :tags: schema + :tickets: 1214 + + Index now accepts column-oriented InstrumentedAttributes + (i.e. column-based mapped class attributes) as column + arguments. + + .. change:: + :tags: schema + :tickets: + + Column with no name (as in declarative) won't raise a + NoneType error when it's string output is requsted + (such as in a stack trace). + + .. change:: + :tags: schema + :tickets: 1278 + + Fixed bug when overriding a Column with a ForeignKey + on a reflected table, where derived columns (i.e. the + "virtual" columns of a select, etc.) would inadvertently + call upon schema-level cleanup logic intended only + for the original column. + + .. change:: + :tags: declarative + :tickets: + + Can now specify Column objects on subclasses which have no + table of their own (i.e. use single table inheritance). + The columns will be appended to the base table, but only + mapped by the subclass. + + .. change:: + :tags: declarative + :tickets: + + For both joined and single inheriting subclasses, the subclass + will only map those columns which are already mapped on the + superclass and those explicit on the subclass. Other + columns that are present on the `Table` will be excluded + from the mapping by default, which can be disabled + by passing a blank `exclude_properties` collection to the + `__mapper_args__`. This is so that single-inheriting + classes which define their own columns are the only classes + to map those columns. The effect is actually a more organized + mapping than you'd normally get with explicit `mapper()` + calls unless you set up the `exclude_properties` arguments + explicitly. + + .. change:: + :tags: declarative + :tickets: + + It's an error to add new Column objects to a declarative class + that specified an existing table using __table__. + + .. change:: + :tags: mysql + :tickets: + + Added the missing keywords from MySQL 4.1 so they get escaped + properly. + + .. change:: + :tags: mssql + :tickets: 1280 + + Corrected handling of large decimal values with more robust + tests. Removed string manipulation on floats. + + .. change:: + :tags: mssql + :tickets: + + Modified the do_begin handling in mssql to use the Cursor not + the Connection so it is DBAPI compatible. + + .. change:: + :tags: mssql + :tickets: + + Corrected SAVEPOINT support on adodbapi by changing the + handling of savepoint_release, which is unsupported on mssql. + +.. changelog:: + :version: 0.5.0 + :released: Tue Jan 06 2009 + + .. change:: + :tags: general + :tickets: + + Documentation has been converted to Sphinx. In particular, + the generated API documentation has been constructed into a + full blown "API Reference" section which organizes editorial + documentation combined with generated docstrings. Cross + linking between sections and API docs are vastly improved, a + javascript-powered search feature is provided, and a full + index of all classes, functions and members is provided. + + .. change:: + :tags: general + :tickets: + + setup.py now imports setuptools only optionally. If not + present, distutils is used. The new "pip" installer is + recommended over easy_install as it installs in a more + simplified way. + + .. change:: + :tags: general + :tickets: + + added an extremely basic illustration of a PostGIS integration + to the examples folder. + + .. change:: + :tags: orm + :tickets: + + Query.with_polymorphic() now accepts a third argument + "discriminator" which will replace the value of + mapper.polymorphic_on for that query. Mappers themselves no + longer require polymorphic_on to be set, even if the mapper + has a polymorphic_identity. When not set, the mapper will + load non-polymorphically by default. Together, these two + features allow a non-polymorphic concrete inheritance setup to + use polymorphic loading on a per-query basis, since concrete + setups are prone to many issues when used polymorphically in + all cases. + + .. change:: + :tags: orm + :tickets: + + dynamic_loader accepts a query_class= to customize the Query + classes used for both the dynamic collection and the queries + built from it. + + .. change:: + :tags: orm + :tickets: 1079 + + query.order_by() accepts None which will remove any pending + order_by state from the query, as well as cancel out any + mapper/relation configured ordering. This is primarily useful + for overriding the ordering specified on a dynamic_loader(). + + .. change:: + :tags: sql + :tickets: 935 + + RowProxy objects can be used in place of dictionary arguments + sent to connection.execute() and friends. + + .. change:: + :tags: dialect + :tickets: + + Added a new description_encoding attribute on the dialect that + is used for encoding the column name when processing the + metadata. This usually defaults to utf-8. + + .. change:: + :tags: mssql + :tickets: + + Added in a new MSGenericBinary type. This maps to the Binary + type so it can implement the specialized behavior of treating + length specified types as fixed-width Binary types and + non-length types as an unbound variable length Binary type. + + .. change:: + :tags: mssql + :tickets: 1249 + + Added in new types: MSVarBinary and MSImage. + + .. change:: + :tags: mssql + :tickets: + + Added in the MSReal, MSNText, MSSmallDateTime, MSTime, + MSDateTimeOffset, and MSDateTime2 types + + .. change:: + :tags: sqlite + :tickets: 1266 + + Table reflection now stores the actual DefaultClause value for + the column. + + .. change:: + :tags: sqlite + :tickets: + + bugfixes, behavioral changes + + .. change:: + :tags: orm + :tickets: + + Exceptions raised during compile_mappers() are now preserved + to provide "sticky behavior" - if a hasattr() call on a + pre-compiled mapped attribute triggers a failing compile and + suppresses the exception, subsequent compilation is blocked + and the exception will be reiterated on the next compile() + call. This issue occurs frequently when using declarative. + + .. change:: + :tags: orm + :tickets: + + property.of_type() is now recognized on a single-table + inheriting target, when used in the context of + prop.of_type(..).any()/has(), as well as + query.join(prop.of_type(...)). + + .. change:: + :tags: orm + :tickets: + + query.join() raises an error when the target of the join + doesn't match the property-based attribute - while it's + unlikely anyone is doing this, the SQLAlchemy author was + guilty of this particular loosey-goosey behavior. + + .. change:: + :tags: orm + :tickets: 1272 + + Fixed bug when using weak_instance_map=False where modified + events would not be intercepted for a flush(). + + .. change:: + :tags: orm + :tickets: 1268 + + Fixed some deep "column correspondence" issues which could + impact a Query made against a selectable containing multiple + versions of the same table, as well as unions and similar + which contained the same table columns in different column + positions at different levels. + + .. change:: + :tags: orm + :tickets: + + Custom comparator classes used in conjunction with + column_property(), relation() etc. can define new comparison + methods on the Comparator, which will become available via + __getattr__() on the InstrumentedAttribute. In the case of + synonym() or comparable_property(), attributes are resolved + first on the user-defined descriptor, then on the user-defined + comparator. + + .. change:: + :tags: orm + :tickets: 976 + + Added ScopedSession.is_active accessor. + + .. change:: + :tags: orm + :tickets: 1262 + + Can pass mapped attributes and column objects as keys to + query.update({}). + + .. change:: + :tags: orm + :tickets: + + Mapped attributes passed to the values() of an expression + level insert() or update() will use the keys of the mapped + columns, not that of the mapped attribute. + + .. change:: + :tags: orm + :tickets: 1242 + + Corrected problem with Query.delete() and Query.update() not + working properly with bind parameters. + + .. change:: + :tags: orm + :tickets: + + Query.select_from(), from_statement() ensure that the given + argument is a FromClause, or Text/Select/Union, respectively. + + .. change:: + :tags: orm + :tickets: 1253 + + Query() can be passed a "composite" attribute as a column + expression and it will be expanded. Somewhat related to. + + .. change:: + :tags: orm + :tickets: + + Query() is a little more robust when passed various column + expressions such as strings, clauselists, text() constructs + (which may mean it just raises an error more nicely). + + .. change:: + :tags: orm + :tickets: + + first() works as expected with Query.from_statement(). + + .. change:: + :tags: orm + :tickets: + + Fixed bug introduced in 0.5rc4 involving eager loading not + functioning for properties which were added to a mapper + post-compile using add_property() or equivalent. + + .. change:: + :tags: orm + :tickets: + + Fixed bug where many-to-many relation() with viewonly=True + would not correctly reference the link between + secondary->remote. + + .. change:: + :tags: orm + :tickets: 1232 + + Duplicate items in a list-based collection will be maintained + when issuing INSERTs to a "secondary" table in a many-to-many + relation. Assuming the m2m table has a unique or primary key + constraint on it, this will raise the expected constraint + violation instead of silently dropping the duplicate + entries. Note that the old behavior remains for a one-to-many + relation since collection entries in that case don't result in + INSERT statements and SQLA doesn't manually police + collections. + + .. change:: + :tags: orm + :tickets: + + Query.add_column() can accept FromClause objects in the same + manner as session.query() can. + + .. change:: + :tags: orm + :tickets: + + Comparison of many-to-one relation to NULL is properly + converted to IS NOT NULL based on not_(). + + .. change:: + :tags: orm + :tickets: 1087 + + Extra checks added to ensure explicit + primaryjoin/secondaryjoin are ClauseElement instances, to + prevent more confusing errors later on. + + .. change:: + :tags: orm + :tickets: 1236 + + Improved mapper() check for non-class classes. + + .. change:: + :tags: orm + :tickets: 5051 + + comparator_factory argument is now documented and supported by + all MapperProperty types, including column_property(), + relation(), backref(), and synonym(). + + .. change:: + :tags: orm + :tickets: + + Changed the name of PropertyLoader to RelationProperty, to be + consistent with all the other names. PropertyLoader is still + present as a synonym. + + .. change:: + :tags: orm + :tickets: 1099, 1228 + + fixed "double iter()" call causing bus errors in shard API, + removed errant result.close() left over from the 0.4 + version. + + .. change:: + :tags: orm + :tickets: + + made Session.merge cascades not trigger autoflush. Fixes + merged instances getting prematurely inserted with missing + values. + + .. change:: + :tags: orm + :tickets: + + Two fixes to help prevent out-of-band columns from being + rendered in polymorphic_union inheritance scenarios (which + then causes extra tables to be rendered in the FROM clause + causing cartesian products): + + - improvements to "column adaption" for a->b->c inheritance + situations to better locate columns that are related to + one another via multiple levels of indirection, rather + than rendering the non-adapted column. + + - the "polymorphic discriminator" column is only rendered + for the actual mapper being queried against. The column + won't be "pulled in" from a subclass or superclass mapper + since it's not needed. + + .. change:: + :tags: orm + :tickets: 1072 + + Fixed shard_id argument on ShardedSession.execute(). + + .. change:: + :tags: sql + :tickets: 1256 + + Columns can again contain percent signs within their + names. + + .. change:: + :tags: sql + :tickets: + + sqlalchemy.sql.expression.Function is now a public class. It + can be subclassed to provide user-defined SQL functions in an + imperative style, including with pre-established behaviors. + The postgis.py example illustrates one usage of this. + + .. change:: + :tags: sql + :tickets: + + PickleType now favors == comparison by default, if the + incoming object (such as a dict) implements __eq__(). If the + object does not implement __eq__() and mutable=True, a + deprecation warning is raised. + + .. change:: + :tags: sql + :tickets: 1215 + + Fixed the import weirdness in sqlalchemy.sql to not export + __names__. + + .. change:: + :tags: sql + :tickets: 1238 + + Using the same ForeignKey object repeatedly raises an error + instead of silently failing later. + + .. change:: + :tags: sql + :tickets: + + Added NotImplementedError for params() method on + Insert/Update/Delete constructs. These items currently don't + support this functionality, which also would be a little + misleading compared to values(). + + .. change:: + :tags: sql + :tickets: 650 + + Reflected foreign keys will properly locate their referenced + column, even if the column was given a "key" attribute + different from the reflected name. This is achieved via a new + flag on ForeignKey/ForeignKeyConstraint called "link_to_name", + if True means the given name is the referred-to column's name, + not its assigned key. + + .. change:: + :tags: sql + :tickets: 1253 + + select() can accept a ClauseList as a column in the same way + as a Table or other selectable and the interior expressions + will be used as column elements. + + .. change:: + :tags: sql + :tickets: + + the "passive" flag on session.is_modified() is correctly + propagated to the attribute manager. + + .. change:: + :tags: sql + :tickets: + + union() and union_all() will not whack any order_by() that has + been applied to the select()s inside. If you union() a + select() with order_by() (presumably to support LIMIT/OFFSET), + you should also call self_group() on it to apply parenthesis. + + .. change:: + :tags: engine/pool + :tickets: 1246 + + Connection.invalidate() checks for closed status to avoid + attribute errors. + + .. change:: + :tags: engine/pool + :tickets: 1094 + + NullPool supports reconnect on failure behavior. + + .. change:: + :tags: engine/pool + :tickets: 799 + + Added a mutex for the initial pool creation when using + pool.manage(dbapi). This prevents a minor case of "dogpile" + behavior which would otherwise occur upon a heavy load + startup. + + .. change:: + :tags: engine/pool + :tickets: + + _execute_clauseelement() goes back to being a private method. + Subclassing Connection is not needed now that ConnectionProxy + is available. + + .. change:: + :tags: documentation + :tickets: 1149, 1200 + + Tickets. + + .. change:: + :tags: documentation + :tickets: + + Added note about create_session() defaults. + + .. change:: + :tags: documentation + :tickets: + + Added section about metadata.reflect(). + + .. change:: + :tags: documentation + :tickets: + + Updated `TypeDecorator` section. + + .. change:: + :tags: documentation + :tickets: + + Rewrote the "threadlocal" strategy section of the docs due to + recent confusion over this feature. + + .. change:: + :tags: documentation + :tickets: + + Removed badly out of date 'polymorphic_fetch' and + 'select_table' docs from inheritance, reworked the second half + of "joined table inheritance". + + .. change:: + :tags: documentation + :tickets: + + Documented `comparator_factory` kwarg, added new doc section + "Custom Comparators". + + .. change:: + :tags: mssql + :tickets: 1254 + + Refactored the Date/Time types. The ``smalldatetime`` data + type no longer truncates to a date only, and will now be + mapped to the MSSmallDateTime type. + + .. change:: + :tags: mssql + :tickets: + + Corrected an issue with Numerics to accept an int. + + .. change:: + :tags: mssql + :tickets: + + Mapped ``char_length`` to the ``LEN()`` function. + + .. change:: + :tags: mssql + :tickets: + + If an ``INSERT`` includes a subselect the ``INSERT`` is + converted from an ``INSERT INTO VALUES`` construct to a + ``INSERT INTO SELECT`` construct. + + .. change:: + :tags: mssql + :tickets: + + If the column is part of a ``primary_key`` it will be ``NOT + NULL`` since MSSQL doesn't allow ``NULL`` in primary_key + columns. + + .. change:: + :tags: mssql + :tickets: 1249 + + ``MSBinary`` now returns a ``BINARY`` instead of an + ``IMAGE``. This is a backwards incompatible change in that + ``BINARY`` is a fixed length data type whereas ``IMAGE`` is a + variable length data type. + + .. change:: + :tags: mssql + :tickets: 1258 + + ``get_default_schema_name`` is now reflected from the database + based on the user's default schema. This only works with MSSQL + 2005 and later. + + .. change:: + :tags: mssql + :tickets: 1248 + + Added collation support through the use of a new collation + argument. This is supported on the following types: char, + nchar, varchar, nvarchar, text, ntext. + + .. change:: + :tags: mssql + :tickets: + + Changes to the connection string parameters favor DSN as the + default specification for pyodbc. See the mssql.py docstring + for detailed usage instructions. + + .. change:: + :tags: mssql + :tickets: + + Added experimental support of savepoints. It currently does + not work fully with sessions. + + .. change:: + :tags: mssql + :tickets: 1243 + + Support for three levels of column nullability: NULL, NOT + NULL, and the database's configured default. The default + Column configuration (nullable=True) will now generate NULL in + the DDL. Previously no specification was emitted and the + database default would take effect (usually NULL, but not + always). To explicitly request the database default, + configure columns with nullable=None and no specification will + be emitted in DDL. This is backwards incompatible + behavior. + + .. change:: + :tags: postgres + :tickets: 1267 + + "%" signs in text() constructs are automatically escaped to + "%%". Because of the backwards incompatible nature of this + change, a warning is emitted if '%%' is detected in the + string. + + .. change:: + :tags: postgres + :tickets: + + Calling alias.execute() in conjunction with + server_side_cursors won't raise AttributeError. + + .. change:: + :tags: postgres + :tickets: 714 + + Added Index reflection support to PostgreSQL, using a great + patch we long neglected, submitted by Ken + Kuhlman. + + .. change:: + :tags: oracle + :tickets: + + Adjusted the format of create_xid() to repair two-phase + commit. We now have field reports of Oracle two-phase commit + working properly with this change. + + .. change:: + :tags: oracle + :tickets: 1233 + + Added OracleNVarchar type, produces NVARCHAR2, and also + subclasses Unicode so that convert_unicode=True by default. + NVARCHAR2 reflects into this type automatically so these + columns pass unicode on a reflected table with no explicit + convert_unicode=True flags. + + .. change:: + :tags: oracle + :tickets: 1265 + + Fixed bug which was preventing out params of certain types + from being received; thanks a ton to huddlej at wwu.edu ! + + .. change:: + :tags: mysql + :tickets: + + "%" signs in text() constructs are automatically escaped to + "%%". Because of the backwards incompatible nature of this + change, a warning is emitted if '%%' is detected in the + string. + + .. change:: + :tags: mysql + :tickets: 1241 + + Fixed bug in exception raise when FK columns not present + during reflection. + + .. change:: + :tags: mysql + :tickets: + + Fixed bug involving reflection of a remote-schema table with a + foreign key ref to another table in that schema. + + .. change:: + :tags: associationproxy + :tickets: + + The association proxy properties are make themselves available + at the class level, e.g. MyClass.aproxy. Previously this + evaluated to None. + + .. change:: + :tags: declarative + :tickets: + + The full list of arguments accepted as string by backref() + includes 'primaryjoin', 'secondaryjoin', 'secondary', + 'foreign_keys', 'remote_side', 'order_by'. + +.. changelog:: + :version: 0.5.0rc4 + :released: Fri Nov 14 2008 + + .. change:: + :tags: orm + :tickets: + + Query.count() has been enhanced to do the "right thing" in a + wider variety of cases. It can now count multiple-entity + queries, as well as column-based queries. Note that this means + if you say query(A, B).count() without any joining criterion, + it's going to count the cartesian product of A*B. Any query + which is against column-based entities will automatically + issue "SELECT count(1) FROM (SELECT...)" so that the real + rowcount is returned, meaning a query such as + query(func.count(A.name)).count() will return a value of one, + since that query would return one row. + + .. change:: + :tags: orm + :tickets: + + Lots of performance tuning. A rough guesstimate over various + ORM operations places it 10% faster over 0.5.0rc3, 25-30% over + 0.4.8. + + .. change:: + :tags: orm + :tickets: + + bugfixes and behavioral changes + + .. change:: + :tags: general + :tickets: + + global "propigate"->"propagate" change. + + .. change:: + :tags: orm + :tickets: + + Adjustments to the enhanced garbage collection on + InstanceState to better guard against errors due to lost + state. + + .. change:: + :tags: orm + :tickets: 1220 + + Query.get() returns a more informative error message when + executed against multiple entities. + + .. change:: + :tags: orm + :tickets: 1140, 1221 + + Restored NotImplementedError on Cls.relation.in_() + + .. change:: + :tags: orm + :tickets: 1226 + + Fixed PendingDeprecationWarning involving order_by parameter + on relation(). + + .. change:: + :tags: sql + :tickets: + + Removed the 'properties' attribute of the Connection object, + Connection.info should be used. + + .. change:: + :tags: sql + :tickets: + + Restored "active rowcount" fetch before ResultProxy autocloses + the cursor. This was removed in 0.5rc3. + + .. change:: + :tags: sql + :tickets: + + Rearranged the `load_dialect_impl()` method in `TypeDecorator` + such that it will take effect even if the user-defined + `TypeDecorator` uses another `TypeDecorator` as its impl. + + .. change:: + :tags: access + :tickets: + + Added support for Currency type. + + .. change:: + :tags: access + :tickets: 1017 + + Functions were not return their result. + + .. change:: + :tags: access + :tickets: 1017 + + Corrected problem with joins. Access only support LEFT OUTER + or INNER not just JOIN by itself. + + .. change:: + :tags: mssql + :tickets: + + Lots of cleanup and fixes to correct problems with limit and + offset. + + .. change:: + :tags: mssql + :tickets: + + Correct situation where subqueries as part of a binary + expression need to be translated to use the IN and NOT IN + syntax. + + .. change:: + :tags: mssql + :tickets: 1216 + + Fixed E Notation issue that prevented the ability to insert + decimal values less than 1E-6. + + .. change:: + :tags: mssql + :tickets: 1217 + + Corrected problems with reflection when dealing with schemas, + particularly when those schemas are the default + schema. + + .. change:: + :tags: mssql + :tickets: + + Corrected problem with casting a zero length item to a + varchar. It now correctly adjusts the CAST. + + .. change:: + :tags: ext + :tickets: + + Can now use a custom "inherit_condition" in __mapper_args__ + when using declarative. + + .. change:: + :tags: ext + :tickets: + + fixed string-based "remote_side", "order_by" and others not + propagating correctly when used in backref(). + +.. changelog:: + :version: 0.5.0rc3 + :released: Fri Nov 07 2008 + + .. change:: + :tags: orm + :tickets: + + Added two new hooks to SessionExtension: after_bulk_delete() + and after_bulk_update(). after_bulk_delete() is called after + a bulk delete() operation on a query. after_bulk_update() is + called after a bulk update() operation on a query. + + .. change:: + :tags: sql + :tickets: + + SQL compiler optimizations and complexity reduction. The call + count for compiling a typical select() construct is 20% less + versus 0.5.0rc2. + + .. change:: + :tags: sql + :tickets: 1211 + + Dialects can now generate label names of adjustable + length. Pass in the argument "label_length=" to + create_engine() to adjust how many characters max will be + present in dynamically generated column labels, i.e. + "somecolumn AS somelabel". Any value less than 6 will result + in a label of minimal size, consisting of an underscore and a + numeric counter. The compiler uses the value of + dialect.max_identifier_length as a default. + + .. change:: + :tags: ext + :tickets: + + Added a new extension sqlalchemy.ext.serializer. Provides + Serializer/Deserializer "classes" which mirror + Pickle/Unpickle, as well as dumps() and loads(). This + serializer implements an "external object" pickler which keeps + key context-sensitive objects, including engines, sessions, + metadata, Tables/Columns, and mappers, outside of the pickle + stream, and can later restore the pickle using any + engine/metadata/session provider. This is used not for + pickling regular object instances, which are pickleable + without any special logic, but for pickling expression objects + and full Query objects, such that all mapper/engine/session + dependencies can be restored at unpickle time. + + .. change:: + :tags: oracle + :tickets: + + Wrote a docstring for Oracle dialect. Apparently that Ohloh + "few source code comments" label is starting to sting :). + + .. change:: + :tags: oracle + :tickets: 536 + + Removed FIRST_ROWS() optimize flag when using LIMIT/OFFSET, + can be reenabled with optimize_limits=True create_engine() + flag. + + .. change:: + :tags: oracle + :tickets: + + bugfixes and behavioral changes + + .. change:: + :tags: orm + :tickets: + + "not equals" comparisons of simple many-to-one relation to an + instance will not drop into an EXISTS clause and will compare + foreign key columns instead. + + .. change:: + :tags: orm + :tickets: + + Removed not-really-working use cases of comparing a collection + to an iterable. Use contains() to test for collection + membership. + + .. change:: + :tags: orm + :tickets: 1171 + + Improved the behavior of aliased() objects such that they more + accurately adapt the expressions generated, which helps + particularly with self-referential comparisons. + + .. change:: + :tags: orm + :tickets: + + Fixed bug involving primaryjoin/secondaryjoin conditions + constructed from class-bound attributes (as often occurs when + using declarative), which later would be inappropriately + aliased by Query, particularly with the various EXISTS based + comparators. + + .. change:: + :tags: orm + :tickets: + + Fixed bug when using multiple query.join() with an + aliased-bound descriptor which would lose the left alias. + + .. change:: + :tags: orm + :tickets: + + Improved weakref identity map memory management to no longer + require mutexing, resurrects garbage collected instance on a + lazy basis for an InstanceState with pending changes. + + .. change:: + :tags: orm + :tickets: + + InstanceState object now removes circular references to itself + upon disposal to keep it outside of cyclic garbage collection. + + .. change:: + :tags: orm + :tickets: + + relation() won't hide unrelated ForeignKey errors inside of + the "please specify primaryjoin" message when determining join + condition. + + .. change:: + :tags: orm + :tickets: 1218 + + Fixed bug in Query involving order_by() in conjunction with + multiple aliases of the same class (will add tests in) + + .. change:: + :tags: orm + :tickets: + + When using Query.join() with an explicit clause for the ON + clause, the clause will be aliased in terms of the left side + of the join, allowing scenarios like query(Source). + from_self().join((Dest, Source.id==Dest.source_id)) to work + properly. + + .. change:: + :tags: orm + :tickets: + + polymorphic_union() function respects the "key" of each Column + if they differ from the column's name. + + .. change:: + :tags: orm + :tickets: 1183 + + Repaired support for "passive-deletes" on a many-to-one + relation() with "delete" cascade. + + .. change:: + :tags: orm + :tickets: 1213 + + Fixed bug in composite types which prevented a primary-key + composite type from being mutated. + + .. change:: + :tags: orm + :tickets: 1202 + + Added more granularity to internal attribute access, such that + cascade and flush operations will not initialize unloaded + attributes and collections, leaving them intact for a + lazy-load later on. Backref events still initialize attrbutes + and collections for pending instances. + + .. change:: + :tags: sql + :tickets: 1212 + + Simplified the check for ResultProxy "autoclose without + results" to be based solely on presence of + cursor.description. All the regexp-based guessing about + statements returning rows has been removed. + + .. change:: + :tags: sql + :tickets: 1194 + + Direct execution of a union() construct will properly set up + result-row processing. + + .. change:: + :tags: sql + :tickets: + + The internal notion of an "OID" or "ROWID" column has been + removed. It's basically not used by any dialect, and the + possibility of its usage with psycopg2's cursor.lastrowid is + basically gone now that INSERT..RETURNING is available. + + .. change:: + :tags: sql + :tickets: + + Removed "default_order_by()" method on all FromClause objects. + + .. change:: + :tags: sql + :tickets: + + Repaired the table.tometadata() method so that a passed-in + schema argument is propagated to ForeignKey constructs. + + .. change:: + :tags: sql + :tickets: + + Slightly changed behavior of IN operator for comparing to + empty collections. Now results in inequality comparison + against self. More portable, but breaks with stored procedures + that aren't pure functions. + + .. change:: + :tags: oracle + :tickets: + + Setting the auto_convert_lobs to False on create_engine() will + also instruct the OracleBinary type to return the cx_oracle + LOB object unchanged. + + .. change:: + :tags: mysql + :tickets: + + Fixed foreign key reflection in the edge case where a Table's + explicit schema= is the same as the schema (database) the + connection is attached to. + + .. change:: + :tags: mysql + :tickets: + + No longer expects include_columns in table reflection to be + lower case. + + .. change:: + :tags: ext + :tickets: 1174 + + Fixed bug preventing declarative-bound "column" objects from + being used in column_mapped_collection(). + + .. change:: + :tags: misc + :tickets: 1077 + + util.flatten_iterator() func doesn't interpret strings with + __iter__() methods as iterators, such as in pypy. + +.. changelog:: + :version: 0.5.0rc2 + :released: Sun Oct 12 2008 + + .. change:: + :tags: orm + :tickets: + + Fixed bug involving read/write relation()s that contain + literal or other non-column expressions within their + primaryjoin condition equated to a foreign key column. + + .. change:: + :tags: orm + :tickets: + + "non-batch" mode in mapper(), a feature which allows mapper + extension methods to be called as each instance is + updated/inserted, now honors the insert order of the objects + given. + + .. change:: + :tags: orm + :tickets: + + Fixed RLock-related bug in mapper which could deadlock upon + reentrant mapper compile() calls, something that occurs when + using declarative constructs inside of ForeignKey objects. + + .. change:: + :tags: orm + :tickets: + + ScopedSession.query_property now accepts a query_cls factory, + overriding the session's configured query_cls. + + .. change:: + :tags: orm + :tickets: + + Fixed shared state bug interfering with ScopedSession.mapper's + ability to apply default __init__ implementations on object + subclasses. + + .. change:: + :tags: orm + :tickets: 1177 + + Fixed up slices on Query (i.e. query[x:y]) to work properly + for zero length slices, slices with None on either end. + + .. change:: + :tags: orm + :tickets: + + Added an example illustrating Celko's "nested sets" as a + SQLA mapping. + + .. change:: + :tags: orm + :tickets: + + contains_eager() with an alias argument works even when + the alias is embedded in a SELECT, as when sent to the + Query via query.select_from(). + + .. change:: + :tags: orm + :tickets: 1180 + + contains_eager() usage is now compatible with a Query that + also contains a regular eager load and limit/offset, in that + the columns are added to the Query-generated subquery. + + .. change:: + :tags: orm + :tickets: + + session.execute() will execute a Sequence object passed to + it (regression from 0.4). + + .. change:: + :tags: orm + :tickets: + + Removed the "raiseerror" keyword argument from object_mapper() + and class_mapper(). These functions raise in all cases + if the given class/instance is not mapped. + + .. change:: + :tags: orm + :tickets: + + Fixed session.transaction.commit() on a autocommit=False + session not starting a new transaction. + + .. change:: + :tags: orm + :tickets: + + Some adjustments to Session.identity_map's weak referencing + behavior to reduce asynchronous GC side effects. + + .. change:: + :tags: orm + :tickets: 1182 + + Adjustment to Session's post-flush accounting of newly + "clean" objects to better protect against operating on + objects as they're asynchronously gc'ed. + + .. change:: + :tags: sql + :tickets: 1074 + + column.in_(someselect) can now be used as a columns-clause + expression without the subquery bleeding into the FROM clause + + .. change:: + :tags: sqlite + :tickets: 968 + + Overhauled SQLite date/time bind/result processing to use + regular expressions and format strings, rather than + strptime/strftime, to generically support pre-1900 dates, + dates with microseconds. + + .. change:: + :tags: sqlite + :tickets: + + String's (and Unicode's, UnicodeText's, etc.) convert_unicode + logic disabled in the sqlite dialect, to adjust for pysqlite + 2.5.0's new requirement that only Python unicode objects are + accepted; + http://itsystementwicklung.de/pipermail/list-pysqlite/2008-March/000018.html + + .. change:: + :tags: mysql + :tickets: + + Temporary tables are now reflectable. + + .. change:: + :tags: oracle + :tickets: 1187 + + Oracle will detect string-based statements which contain + comments at the front before a SELECT as SELECT statements. + +.. changelog:: + :version: 0.5.0rc1 + :released: Thu Sep 11 2008 + + .. change:: + :tags: orm + :tickets: + + Query now has delete() and update(values) methods. This allows + to perform bulk deletes/updates with the Query object. + + .. change:: + :tags: orm + :tickets: + + The RowTuple object returned by Query(*cols) now features + keynames which prefer mapped attribute names over column keys, + column keys over column names, i.e. Query(Class.foo, + Class.bar) will have names "foo" and "bar" even if those are + not the names of the underlying Column objects. Direct Column + objects such as Query(table.c.col) will return the "key" + attribute of the Column. + + .. change:: + :tags: orm + :tickets: + + Added scalar() and value() methods to Query, each return a + single scalar value. scalar() takes no arguments and is + roughly equivalent to first()[0], value() + takes a single column expression and is roughly equivalent to + values(expr).next()[0]. + + .. change:: + :tags: orm + :tickets: + + Improved the determination of the FROM clause when placing SQL + expressions in the query() list of entities. In particular + scalar subqueries should not "leak" their inner FROM objects + out into the enclosing query. + + .. change:: + :tags: orm + :tickets: + + Joins along a relation() from a mapped class to a mapped + subclass, where the mapped subclass is configured with single + table inheritance, will include an IN clause which limits the + subtypes of the joined class to those requested, within the ON + clause of the join. This takes effect for eager load joins as + well as query.join(). Note that in some scenarios the IN + clause will appear in the WHERE clause of the query as well + since this discrimination has multiple trigger points. + + .. change:: + :tags: orm + :tickets: + + AttributeExtension has been refined such that the event + is fired before the mutation actually occurs. Additionally, + the append() and set() methods must now return the given value, + which is used as the value to be used in the mutation operation. + This allows creation of validating AttributeListeners which + raise before the action actually occurs, and which can change + the given value into something else before its used. + + .. change:: + :tags: orm + :tickets: + + column_property(), composite_property(), and relation() now + accept a single or list of AttributeExtensions using the + "extension" keyword argument. + + .. change:: + :tags: orm + :tickets: + + query.order_by().get() silently drops the "ORDER BY" from + the query issued by GET but does not raise an exception. + + .. change:: + :tags: orm + :tickets: + + Added a Validator AttributeExtension, as well as a + @validates decorator which is used in a similar fashion + as @reconstructor, and marks a method as validating + one or more mapped attributes. + + .. change:: + :tags: orm + :tickets: 1140 + + class.someprop.in_() raises NotImplementedError pending the + implementation of "in_" for relation + + .. change:: + :tags: orm + :tickets: 1127 + + Fixed primary key update for many-to-many collections where + the collection had not been loaded yet + + .. change:: + :tags: orm + :tickets: + + Fixed bug whereby deferred() columns with a group in conjunction + with an otherwise unrelated synonym() would produce + an AttributeError during deferred load. + + .. change:: + :tags: orm + :tickets: 1128 + + The before_flush() hook on SessionExtension takes place before + the list of new/dirty/deleted is calculated for the final + time, allowing routines within before_flush() to further + change the state of the Session before the flush proceeds. + + .. change:: + :tags: orm + :tickets: + + The "extension" argument to Session and others can now + optionally be a list, supporting events sent to multiple + SessionExtension instances. Session places SessionExtensions + in Session.extensions. + + .. change:: + :tags: orm + :tickets: + + Reentrant calls to flush() raise an error. This also serves + as a rudimentary, but not foolproof, check against concurrent + calls to Session.flush(). + + .. change:: + :tags: orm + :tickets: + + Improved the behavior of query.join() when joining to + joined-table inheritance subclasses, using explicit join + criteria (i.e. not on a relation). + + .. change:: + :tags: orm + :tickets: + + @orm.attributes.reconstitute and + MapperExtension.reconstitute have been renamed to + @orm.reconstructor and MapperExtension.reconstruct_instance + + .. change:: + :tags: orm + :tickets: 1129 + + Fixed @reconstructor hook for subclasses which inherit from a + base class. + + .. change:: + :tags: orm + :tickets: 1132 + + The composite() property type now supports a + __set_composite_values__() method on the composite class which + is required if the class represents state using attribute + names other than the column's keynames; default-generated + values now get populated properly upon flush. Also, + composites with attributes set to None compare correctly. + + .. change:: + :tags: orm + :tickets: + + The 3-tuple of iterables returned by attributes.get_history() + may now be a mix of lists and tuples. (Previously members + were always lists.) + + .. change:: + :tags: orm + :tickets: 1151 + + Fixed bug whereby changing a primary key attribute on an + entity where the attribute's previous value had been expired + would produce an error upon flush(). + + .. change:: + :tags: orm + :tickets: + + Fixed custom instrumentation bug whereby get_instance_dict() + was not called for newly constructed instances not loaded + by the ORM. + + .. change:: + :tags: orm + :tickets: 1150 + + Session.delete() adds the given object to the session if + not already present. This was a regression bug from 0.4. + + .. change:: + :tags: orm + :tickets: + + The `echo_uow` flag on `Session` is deprecated, and unit-of-work + logging is now application-level only, not per-session level. + + .. change:: + :tags: orm + :tickets: 1153 + + Removed conflicting `contains()` operator from + `InstrumentedAttribute` which didn't accept `escape` kwaarg. + + .. change:: + :tags: declarative + :tickets: 1161 + + Fixed bug whereby mapper couldn't initialize if a composite + primary key referenced another table that was not defined + yet. + + .. change:: + :tags: declarative + :tickets: + + Fixed exception throw which would occur when string-based + primaryjoin condition was used in conjunction with backref. + + .. change:: + :tags: schema + :tickets: 1033 + + Added "sorted_tables" accessor to MetaData, which returns + Table objects sorted in order of dependency as a list. + This deprecates the MetaData.table_iterator() method. + The "reverse=False" keyword argument has also been + removed from util.sort_tables(); use the Python + 'reversed' function to reverse the results. + + .. change:: + :tags: schema + :tickets: + + The 'length' argument to all Numeric types has been renamed + to 'scale'. 'length' is deprecated and is still accepted + with a warning. + + .. change:: + :tags: schema + :tickets: + + Dropped 0.3-compatibility for user defined types + (convert_result_value, convert_bind_param). + + .. change:: + :tags: sql + :tickets: 1068 + + Temporarily rolled back the "ORDER BY" enhancement from. This feature is on hold pending further + development. + + .. change:: + :tags: sql + :tickets: + + The exists() construct won't "export" its contained list + of elements as FROM clauses, allowing them to be used more + effectively in the columns clause of a SELECT. + + .. change:: + :tags: sql + :tickets: 798 + + and_() and or_() now generate a ColumnElement, allowing + boolean expressions as result columns, i.e. + select([and_(1, 0)]). + + .. change:: + :tags: sql + :tickets: + + Bind params now subclass ColumnElement which allows them to be + selectable by orm.query (they already had most ColumnElement + semantics). + + .. change:: + :tags: sql + :tickets: + + Added select_from() method to exists() construct, which becomes + more and more compatible with a regular select(). + + .. change:: + :tags: sql + :tickets: 1160 + + Added func.min(), func.max(), func.sum() as "generic functions", + which basically allows for their return type to be determined + automatically. Helps with dates on SQLite, decimal types, + others. + + .. change:: + :tags: sql + :tickets: + + added decimal.Decimal as an "auto-detect" type; bind parameters + and generic functions will set their type to Numeric when a + Decimal is used. + + .. change:: + :tags: mysql + :tickets: + + The 'length' argument to MSInteger, MSBigInteger, MSTinyInteger, + MSSmallInteger and MSYear has been renamed to 'display_width'. + + .. change:: + :tags: mysql + :tickets: 1146 + + Added MSMediumInteger type. + + .. change:: + :tags: mysql + :tickets: + + the function func.utc_timestamp() compiles to UTC_TIMESTAMP, without + the parenthesis, which seem to get in the way when using in + conjunction with executemany(). + + .. change:: + :tags: oracle + :tickets: 536 + + limit/offset no longer uses ROW NUMBER OVER to limit rows, + and instead uses subqueries in conjunction with a special + Oracle optimization comment. Allows LIMIT/OFFSET to work + in conjunction with DISTINCT. + + .. change:: + :tags: oracle + :tickets: 1155 + + has_sequence() now takes the current "schema" argument into + account + + .. change:: + :tags: oracle + :tickets: 1121 + + added BFILE to reflected type names + +.. changelog:: + :version: 0.5.0beta3 + :released: Mon Aug 04 2008 + + .. change:: + :tags: orm + :tickets: + + The "entity_name" feature of SQLAlchemy mappers has been + removed. For rationale, see http://tinyurl.com/6nm2ne + + .. change:: + :tags: orm + :tickets: + + the "autoexpire" flag on Session, sessionmaker(), and + scoped_session() has been renamed to "expire_on_commit". It + does not affect the expiration behavior of rollback(). + + .. change:: + :tags: orm + :tickets: + + fixed endless loop bug which could occur within a mapper's + deferred load of inherited attributes. + + .. change:: + :tags: orm + :tickets: + + a legacy-support flag "_enable_transaction_accounting" flag + added to Session which when False, disables all + transaction-level object accounting, including expire on + rollback, expire on commit, new/deleted list maintenance, and + autoflush on begin. + + .. change:: + :tags: orm + :tickets: + + The 'cascade' parameter to relation() accepts None as a value, + which is equivalent to no cascades. + + .. change:: + :tags: orm + :tickets: + + A critical fix to dynamic relations allows the "modified" + history to be properly cleared after a flush(). + + .. change:: + :tags: orm + :tickets: + + user-defined @properties on a class are detected and left in + place during mapper initialization. This means that a + table-bound column of the same name will not be mapped at all + if a @property is in the way (and the column is not remapped + to a different name), nor will an instrumented attribute from + an inherited class be applied. The same rules apply for names + excluded using the include_properties/exclude_properties + collections. + + .. change:: + :tags: orm + :tickets: + + Added a new SessionExtension hook called after_attach(). This + is called at the point of attachment for objects via add(), + add_all(), delete(), and merge(). + + .. change:: + :tags: orm + :tickets: 1111 + + A mapper which inherits from another, when inheriting the + columns of its inherited mapper, will use any reassigned + property names specified in that inheriting mapper. + Previously, if "Base" had reassigned "base_id" to the name + "id", "SubBase(Base)" would still get an attribute called + "base_id". This could be worked around by explicitly stating + the column in each submapper as well but this is fairly + unworkable and also impossible when using declarative. + + .. change:: + :tags: orm + :tickets: + + Fixed a series of potential race conditions in Session whereby + asynchronous GC could remove unmodified, no longer referenced + items from the session as they were present in a list of items + to be processed, typically during session.expunge_all() and + dependent methods. + + .. change:: + :tags: orm + :tickets: + + Some improvements to the _CompileOnAttr mechanism which should + reduce the probability of "Attribute x was not replaced during + compile" warnings. (this generally applies to SQLA hackers, + like Elixir devs). + + .. change:: + :tags: orm + :tickets: + + Fixed bug whereby the "unsaved, pending instance" FlushError + raised for a pending orphan would not take superclass mappers + into account when generating the list of relations responsible + for the error. + + .. change:: + :tags: sql + :tickets: + + func.count() with no arguments renders as COUNT(*), equivalent + to func.count(text('*')). + + .. change:: + :tags: sql + :tickets: 1068 + + simple label names in ORDER BY expressions render as + themselves, and not as a re-statement of their corresponding + expression. This feature is currently enabled only for + SQLite, MySQL, and PostgreSQL. It can be enabled on other + dialects as each is shown to support this + behavior. + + .. change:: + :tags: ext + :tickets: + + Class-bound attributes sent as arguments to relation()'s + remote_side and foreign_keys parameters are now accepted, + allowing them to be used with declarative. Additionally fixed + bugs involving order_by being specified as a class-bound + attribute in conjunction with eager loading. + + .. change:: + :tags: ext + :tickets: + + declarative initialization of Columns adjusted so that + non-renamed columns initialize in the same way as a non + declarative mapper. This allows an inheriting mapper to set + up its same-named "id" columns in particular such that the + parent "id" column is favored over the child column, reducing + database round trips when this value is requested. + + .. change:: + :tags: mysql + :tickets: 1110 + + Quoting of MSEnum values for use in CREATE TABLE is now + optional & will be quoted on demand as required. (Quoting was + always optional for use with existing tables.) + +.. changelog:: + :version: 0.5.0beta2 + :released: Mon Jul 14 2008 + + .. change:: + :tags: orm + :tickets: 870 + + In addition to expired attributes, deferred attributes also + load if their data is present in the result set. + + .. change:: + :tags: orm + :tickets: + + session.refresh() raises an informative error message if the + list of attributes does not include any column-based + attributes. + + .. change:: + :tags: orm + :tickets: + + query() raises an informative error message if no columns or + mappers are specified. + + .. change:: + :tags: orm + :tickets: + + lazy loaders now trigger autoflush before proceeding. This + allows expire() of a collection or scalar relation to function + properly in the context of autoflush. + + .. change:: + :tags: orm + :tickets: 887 + + column_property() attributes which represent SQL expressions + or columns that are not present in the mapped tables (such as + those from views) are automatically expired after an INSERT or + UPDATE, assuming they have not been locally modified, so that + they are refreshed with the most recent data upon access. + + .. change:: + :tags: orm + :tickets: 1082 + + Fixed explicit, self-referential joins between two + joined-table inheritance mappers when using query.join(cls, + aliased=True). + + .. change:: + :tags: orm + :tickets: + + Fixed query.join() when used in conjunction with a + columns-only clause and an SQL-expression ON clause in the + join. + + .. change:: + :tags: orm + :tickets: + + The "allow_column_override" flag from mapper() has been + removed. This flag is virtually always misunderstood. Its + specific functionality is available via the + include_properties/exclude_properties mapper arguments. + + .. change:: + :tags: orm + :tickets: 1066 + + Repaired `__str__()` method on Query. + + .. change:: + :tags: orm + :tickets: + + Session.bind gets used as a default even when table/mapper + specific binds are defined. + + .. change:: + :tags: schema + :tickets: 1075 + + Added prefixes option to `Table` that accepts a list of + strings to insert after CREATE in the CREATE TABLE statement. + + .. change:: + :tags: schema + :tickets: + + Unicode, UnicodeText types now set "assert_unicode" and + "convert_unicode" by default, but accept overriding + **kwargs for these values. + + .. change:: + :tags: sql + :tickets: + + Added new match() operator that performs a full-text search. + Supported on PostgreSQL, SQLite, MySQL, MS-SQL, and Oracle + backends. + + .. change:: + :tags: sqlite + :tickets: 1090 + + Modified SQLite's representation of "microseconds" to match + the output of str(somedatetime), i.e. in that the microseconds + are represented as fractional seconds in string format. This + makes SQLA's SQLite date type compatible with datetimes that + were saved directly using Pysqlite (which just calls str()). + Note that this is incompatible with the existing microseconds + values in a SQLA 0.4 generated SQLite database file. + + To get the old behavior globally: + + from sqlalchemy.databases.sqlite import DateTimeMixin + DateTimeMixin.__legacy_microseconds__ = True + + To get the behavior on individual DateTime types: + + t = sqlite.SLDateTime() + t.__legacy_microseconds__ = True + + Then use "t" as the type on the Column. + + .. change:: + :tags: sqlite + :tickets: + + SQLite Date, DateTime, and Time types only accept Python + datetime objects now, not strings. If you'd like to format + dates as strings yourself with SQLite, use a String type. If + you'd like them to return datetime objects anyway despite + their accepting strings as input, make a TypeDecorator around + String - SQLA doesn't encourage this pattern. + + .. change:: + :tags: extensions + :tickets: 1096 + + Declarative supports a __table_args__ class variable, which is + either a dictionary, or tuple of the form (arg1, arg2, ..., + {kwarg1:value, ...}) which contains positional + kw arguments + to be passed to the Table constructor. + +.. changelog:: + :version: 0.5.0beta1 + :released: Thu Jun 12 2008 + + .. change:: + :tags: + :tickets: + + The "__init__" trigger/decorator added by mapper now attempts + to exactly mirror the argument signature of the original + __init__. The pass-through for '_sa_session' is no longer + implicit- you must allow for this keyword argument in your + constructor. + + .. change:: + :tags: + :tickets: + + ClassState is renamed to ClassManager. + + .. change:: + :tags: + :tickets: + + Classes may supply their own InstrumentationManager by + providing a __sa_instrumentation_manager__ property. + + .. change:: + :tags: + :tickets: + + Custom instrumentation may use any mechanism to associate a + ClassManager with a class and an InstanceState with an + instance. Attributes on those objects are still the default + association mechanism used by SQLAlchemy's native + instrumentation. + + .. change:: + :tags: + :tickets: + + Moved entity_name, _sa_session_id, and _instance_key from the + instance object to the instance state. These values are still + available in the old way, which is now deprecated, using + descriptors attached to the class. A deprecation warning will + be issued when accessed. + + .. change:: + :tags: + :tickets: + + The _prepare_instrumentation alias for prepare_instrumentation + has been removed. + + .. change:: + :tags: + :tickets: + + sqlalchemy.exceptions has been renamed to sqlalchemy.exc. The + module may be imported under either name. + + .. change:: + :tags: + :tickets: + + ORM-related exceptions are now defined in sqlalchemy.orm.exc. + ConcurrentModificationError, FlushError, and + UnmappedColumnError compatibility aliases are installed in + sqlalchemy.exc during the import of sqlalchemy.orm. + + .. change:: + :tags: + :tickets: + + sqlalchemy.logging has been renamed to sqlalchemy.log. + + .. change:: + :tags: + :tickets: + + The transitional sqlalchemy.log.SADeprecationWarning alias for + the warning's definition in sqlalchemy.exc has been removed. + + .. change:: + :tags: + :tickets: + + exc.AssertionError has been removed and usage replaced with + Python's built-in AssertionError. + + .. change:: + :tags: + :tickets: + + The behavior of MapperExtensions attached to multiple, + entity_name= primary mappers for a single class has been + altered. The first mapper() defined for a class is the only + mapper eligible for the MapperExtension 'instrument_class', + 'init_instance' and 'init_failed' events. This is backwards + incompatible; previously the extensions of last mapper defined + would receive these events. + + .. change:: + :tags: firebird + :tickets: + + Added support for returning values from inserts (2.0+ only), + updates and deletes (2.1+ only). + + .. change:: + :tags: general + :tickets: + + global "propigate"->"propagate" change. + + .. change:: + :tags: orm + :tickets: + + polymorphic_union() function respects the "key" of each + Column if they differ from the column's name. + + .. change:: + :tags: orm + :tickets: 1199 + + Fixed 0.4-only bug preventing composite columns + from working properly with inheriting mappers + + .. change:: + :tags: orm + :tickets: + + Fixed RLock-related bug in mapper which could deadlock upon + reentrant mapper compile() calls, something that occurs when + using declarative constructs inside of ForeignKey objects. + Ported from 0.5. + + .. change:: + :tags: orm + :tickets: 1213 + + Fixed bug in composite types which prevented a primary-key + composite type from being mutated. + + .. change:: + :tags: orm + :tickets: 976 + + Added ScopedSession.is_active accessor. + + .. change:: + :tags: orm + :tickets: 939 + + Class-bound accessor can be used as the argument to + relation() order_by. + + .. change:: + :tags: orm + :tickets: 1072 + + Fixed shard_id argument on ShardedSession.execute(). + + .. change:: + :tags: sql + :tickets: 1246 + + Connection.invalidate() checks for closed status + to avoid attribute errors. + + .. change:: + :tags: sql + :tickets: 1094 + + NullPool supports reconnect on failure behavior. + + .. change:: + :tags: sql + :tickets: 1299 + + The per-dialect cache used by TypeEngine to cache + dialect-specific types is now a WeakKeyDictionary. + This to prevent dialect objects from + being referenced forever for an application that + creates an arbitrarily large number of engines + or dialects. There is a small performance penalty + which will be resolved in 0.6. + + .. change:: + :tags: sql + :tickets: + + Fixed SQLite reflection methods so that non-present + cursor.description, which triggers an auto-cursor + close, will be detected so that no results doesn't + fail on recent versions of pysqlite which raise + an error when fetchone() called with no rows present. + + .. change:: + :tags: postgres + :tickets: 714 + + Added Index reflection support to Postgres, using a + great patch we long neglected, submitted by + Ken Kuhlman. + + .. change:: + :tags: mysql + :tickets: 1241 + + Fixed bug in exception raise when FK columns not present + during reflection. + + .. change:: + :tags: oracle + :tickets: 1265 + + Fixed bug which was preventing out params of certain types + from being received; thanks a ton to huddlej at wwu.edu ! diff --git a/doc/build/changelog/changelog_06.rst b/doc/build/changelog/changelog_06.rst new file mode 100644 index 0000000000..0ec7027cea --- /dev/null +++ b/doc/build/changelog/changelog_06.rst @@ -0,0 +1,5406 @@ + +============== +0.6 Changelog +============== + + +.. changelog:: + :version: 0.6.9 + :released: Sat May 05 2012 + + .. change:: + :tags: general + :tickets: 2279 + + Adjusted the "importlater" mechanism, which is + used internally to resolve import cycles, + such that the usage of __import__ is completed + when the import of sqlalchemy or sqlalchemy.orm + is done, thereby avoiding any usage of __import__ + after the application starts new threads, + fixes. + + .. change:: + :tags: orm + :tickets: 2197 + + Fixed bug whereby the source clause + used by query.join() would be inconsistent + if against a column expression that combined + multiple entities together. + + .. change:: + :tags: orm, bug + :tickets: 2310 + + fixed inappropriate evaluation of user-mapped + object in a boolean context within query.get(). + + .. change:: + :tags: orm + :tickets: 2228 + + Fixed bug apparent only in Python 3 whereby + sorting of persistent + pending objects during + flush would produce an illegal comparison, + if the persistent object primary key + is not a single integer. + + .. change:: + :tags: orm + :tickets: 2234 + + Fixed bug where query.join() + aliased=True + from a joined-inh structure to itself on + relationship() with join condition on the child + table would convert the lead entity into the + joined one inappropriately. + + .. change:: + :tags: orm + :tickets: 2287 + + Fixed bug whereby mapper.order_by attribute would + be ignored in the "inner" query within a + subquery eager load. . + + .. change:: + :tags: orm + :tickets: 2215 + + Fixed bug whereby if a mapped class + redefined __hash__() or __eq__() to something + non-standard, which is a supported use case + as SQLA should never consult these, + the methods would be consulted if the class + was part of a "composite" (i.e. non-single-entity) + result set. + + .. change:: + :tags: orm + :tickets: 2188 + + Fixed subtle bug that caused SQL to blow + up if: column_property() against subquery + + joinedload + LIMIT + order by the column + property() occurred. . + + .. change:: + :tags: orm + :tickets: 2207 + + The join condition produced by with_parent + as well as when using a "dynamic" relationship + against a parent will generate unique + bindparams, rather than incorrectly repeating + the same bindparam. . + + .. change:: + :tags: orm + :tickets: 2199 + + Repaired the "no statement condition" + assertion in Query which would attempt + to raise if a generative method were called + after from_statement() were called.. + + .. change:: + :tags: orm + :tickets: 1776 + + Cls.column.collate("some collation") now + works. + + .. change:: + :tags: orm, bug + :tickets: 2297 + + Fixed the error formatting raised when + a tuple is inadvertently passed to session.query(). + + .. change:: + :tags: engine + :tickets: 2317 + + Backported the fix for introduced + in 0.7.4, which ensures that the connection + is in a valid state before attempting to call + rollback()/prepare()/release() on savepoint + and two-phase transactions. + + .. change:: + :tags: sql + :tickets: 2188 + + Fixed two subtle bugs involving column + correspondence in a selectable, + one with the same labeled subquery repeated, the other + when the label has been "grouped" and + loses itself. Affects. + + .. change:: + :tags: sql + :tickets: + + Fixed bug whereby "warn on unicode" flag + would get set for the String type + when used with certain dialects. This + bug is not in 0.7. + + .. change:: + :tags: sql + :tickets: 2270 + + Fixed bug whereby with_only_columns() method of + Select would fail if a selectable were passed.. However, the FROM behavior is + still incorrect here, so you need 0.7 in + any case for this use case to be usable. + + .. change:: + :tags: schema + :tickets: + + Added an informative error message when + ForeignKeyConstraint refers to a column name in + the parent that is not found. + + .. change:: + :tags: postgresql + :tickets: 2291, 2141 + + Fixed bug related to whereby the + same modified index behavior in PG 9 affected + primary key reflection on a renamed column.. + + .. change:: + :tags: mysql + :tickets: 2186 + + Fixed OurSQL dialect to use ansi-neutral + quote symbol "'" for XA commands instead + of '"'. . + + .. change:: + :tags: mysql + :tickets: 2225 + + a CREATE TABLE will put the COLLATE option + after CHARSET, which appears to be part of + MySQL's arbitrary rules regarding if it will actually + work or not. + + .. change:: + :tags: mssql, bug + :tickets: 2269 + + Decode incoming values when retrieving + list of index names and the names of columns + within those indexes. + + .. change:: + :tags: oracle + :tickets: 2200 + + Added ORA-00028 to disconnect codes, use + cx_oracle _Error.code to get at the code,. + + .. change:: + :tags: oracle + :tickets: 2220 + + repaired the oracle.RAW type which did not + generate the correct DDL. + + .. change:: + :tags: oracle + :tickets: 2212 + + added CURRENT to reserved word list. + + .. change:: + :tags: examples + :tickets: 2266 + + Adjusted dictlike-polymorphic.py example + to apply the CAST such that it works on + PG, other databases. + +.. changelog:: + :version: 0.6.8 + :released: Sun Jun 05 2011 + + .. change:: + :tags: orm + :tickets: 2144 + + Calling query.get() against a column-based entity is + invalid, this condition now raises a deprecation warning. + + .. change:: + :tags: orm + :tickets: 2151 + + a non_primary mapper will inherit the _identity_class + of the primary mapper. This so that a non_primary + established against a class that's normally in an + inheritance mapping will produce results that are + identity-map compatible with that of the primary + mapper + + .. change:: + :tags: orm + :tickets: 2148 + + Backported 0.7's identity map implementation, which + does not use a mutex around removal. This as some users + were still getting deadlocks despite the adjustments + in 0.6.7; the 0.7 approach that doesn't use a mutex + does not appear to produce "dictionary changed size" + issues, the original rationale for the mutex. + + .. change:: + :tags: orm + :tickets: 2163 + + Fixed the error message emitted for "can't + execute syncrule for destination column 'q'; + mapper 'X' does not map this column" to + reference the correct mapper. . + + .. change:: + :tags: orm + :tickets: 2149 + + Fixed bug where determination of "self referential" + relationship would fail with no workaround + for joined-inh subclass related to itself, + or joined-inh subclass related to a subclass + of that with no cols in the sub-sub class + in the join condition. + + .. change:: + :tags: orm + :tickets: 2153 + + mapper() will ignore non-configured foreign keys + to unrelated tables when determining inherit + condition between parent and child class. + This is equivalent to behavior already + applied to declarative. Note that 0.7 has a + more comprehensive solution to this, altering + how join() itself determines an FK error. + + .. change:: + :tags: orm + :tickets: 2171 + + Fixed bug whereby mapper mapped to an anonymous + alias would fail if logging were used, due to + unescaped % sign in the alias name. + + .. change:: + :tags: orm + :tickets: 2170 + + Modify the text of the message which occurs + when the "identity" key isn't detected on + flush, to include the common cause that + the Column isn't set up to detect + auto-increment correctly;. + + .. change:: + :tags: orm + :tickets: 2182 + + Fixed bug where transaction-level "deleted" + collection wouldn't be cleared of expunged + states, raising an error if they later + became transient. + + .. change:: + :tags: sql + :tickets: 2147 + + Fixed bug whereby if FetchedValue was passed + to column server_onupdate, it would not + have its parent "column" assigned, added + test coverage for all column default assignment + patterns. + + .. change:: + :tags: sql + :tickets: 2167 + + Fixed bug whereby nesting a label of a select() + with another label in it would produce incorrect + exported columns. Among other things this would + break an ORM column_property() mapping against + another column_property(). . + + .. change:: + :tags: engine + :tickets: 2178 + + Adjusted the __contains__() method of + a RowProxy result row such that no exception + throw is generated internally; + NoSuchColumnError() also will generate its + message regardless of whether or not the column + construct can be coerced to a string.. + + .. change:: + :tags: postgresql + :tickets: 2141 + + Fixed bug affecting PG 9 whereby index reflection + would fail if against a column whose name + had changed. . + + .. change:: + :tags: postgresql + :tickets: 2175 + + Some unit test fixes regarding numeric arrays, + MATCH operator. A potential floating-point + inaccuracy issue was fixed, and certain tests + of the MATCH operator only execute within an + EN-oriented locale for now. . + + .. change:: + :tags: mssql + :tickets: 2169 + + Fixed bug in MSSQL dialect whereby the aliasing + applied to a schema-qualified table would leak + into enclosing select statements. + + .. change:: + :tags: mssql + :tickets: 2159 + + Fixed bug whereby DATETIME2 type would fail on + the "adapt" step when used in result sets or + bound parameters. This issue is not in 0.7. + +.. changelog:: + :version: 0.6.7 + :released: Wed Apr 13 2011 + + .. change:: + :tags: orm + :tickets: 2087 + + Tightened the iterate vs. remove mutex around the + identity map iteration, attempting to reduce the + chance of an (extremely rare) reentrant gc operation + causing a deadlock. Might remove the mutex in + 0.7. + + .. change:: + :tags: orm + :tickets: 2030 + + Added a `name` argument to `Query.subquery()`, to allow + a fixed name to be assigned to the alias object. + + .. change:: + :tags: orm + :tickets: 2019 + + A warning is emitted when a joined-table inheriting mapper + has no primary keys on the locally mapped table + (but has pks on the superclass table). + + .. change:: + :tags: orm + :tickets: 2038 + + Fixed bug where "middle" class in a polymorphic hierarchy + would have no 'polymorphic_on' column if it didn't also + specify a 'polymorphic_identity', leading to strange + errors upon refresh, wrong class loaded when querying + from that target. Also emits the correct WHERE criterion + when using single table inheritance. + + .. change:: + :tags: orm + :tickets: 1995 + + Fixed bug where a column with a SQL or server side default + that was excluded from a mapping with include_properties + or exclude_properties would result in UnmappedColumnError. + + .. change:: + :tags: orm + :tickets: 2046 + + A warning is emitted in the unusual case that an + append or similar event on a collection occurs after + the parent object has been dereferenced, which + prevents the parent from being marked as "dirty" + in the session. This will be an exception in 0.7. + + .. change:: + :tags: orm + :tickets: 2098 + + Fixed bug in query.options() whereby a path + applied to a lazyload using string keys could + overlap a same named attribute on the wrong + entity. Note 0.7 has an updated version of this + fix. + + .. change:: + :tags: orm + :tickets: 2063 + + Reworded the exception raised when a flush + is attempted of a subclass that is not polymorphic + against the supertype. + + .. change:: + :tags: orm + :tickets: 2123 + + Some fixes to the state handling regarding + backrefs, typically when autoflush=False, where + the back-referenced collection wouldn't + properly handle add/removes with no net + change. Thanks to Richard Murri for the + test case + patch. + + .. change:: + :tags: orm + :tickets: 2130 + + a "having" clause would be copied from the + inside to the outside query if from_self() + were used.. + + .. change:: + :tags: sql + :tickets: 2028 + + Column.copy(), as used in table.tometadata(), copies the + 'doc' attribute. + + .. change:: + :tags: sql + :tickets: 2023 + + Added some defs to the resultproxy.c extension so that + the extension compiles and runs on Python 2.4. + + .. change:: + :tags: sql + :tickets: 2042 + + The compiler extension now supports overriding the default + compilation of expression._BindParamClause including that + the auto-generated binds within the VALUES/SET clause + of an insert()/update() statement will also use the new + compilation rules. + + .. change:: + :tags: sql + :tickets: 2089 + + Added accessors to ResultProxy "returns_rows", "is_insert" + + .. change:: + :tags: sql + :tickets: 2116 + + The limit/offset keywords to select() as well + as the value passed to select.limit()/offset() + will be coerced to integer. + + .. change:: + :tags: engine + :tickets: 2102 + + Fixed bug in QueuePool, SingletonThreadPool whereby + connections that were discarded via overflow or periodic + cleanup() were not explicitly closed, leaving garbage + collection to the task instead. This generally only + affects non-reference-counting backends like Jython + and Pypy. Thanks to Jaimy Azle for spotting + this. + + .. change:: + :tags: sqlite + :tickets: 2115 + + Fixed bug where reflection of foreign key + created as "REFERENCES " without + col name would fail. + + .. change:: + :tags: postgresql + :tickets: 1083 + + When explicit sequence execution derives the name + of the auto-generated sequence of a SERIAL column, + which currently only occurs if implicit_returning=False, + now accommodates if the table + column name is greater + than 63 characters using the same logic Postgresql uses. + + .. change:: + :tags: postgresql + :tickets: 2044 + + Added an additional libpq message to the list of "disconnect" + exceptions, "could not receive data from server" + + .. change:: + :tags: postgresql + :tickets: 2092 + + Added RESERVED_WORDS for postgresql dialect. + + .. change:: + :tags: postgresql + :tickets: 2073 + + Fixed the BIT type to allow a "length" parameter, "varying" + parameter. Reflection also fixed. + + .. change:: + :tags: informix + :tickets: 2092 + + Added RESERVED_WORDS informix dialect. + + .. change:: + :tags: mssql + :tickets: 2071 + + Rewrote the query used to get the definition of a view, + typically when using the Inspector interface, to + use sys.sql_modules instead of the information schema, + thereby allowing views definitions longer than 4000 + characters to be fully returned. + + .. change:: + :tags: mysql + :tickets: 2047 + + oursql dialect accepts the same "ssl" arguments in + create_engine() as that of MySQLdb. + + .. change:: + :tags: firebird + :tickets: 2083 + + The "implicit_returning" flag on create_engine() is + honored if set to False. + + .. change:: + :tags: oracle + :tickets: 2100 + + Using column names that would require quotes + for the column itself or for a name-generated + bind parameter, such as names with special + characters, underscores, non-ascii characters, + now properly translate bind parameter keys when + talking to cx_oracle. + + .. change:: + :tags: oracle + :tickets: 2116 + + Oracle dialect adds use_binds_for_limits=False + create_engine() flag, will render the LIMIT/OFFSET + values inline instead of as binds, reported to + modify the execution plan used by Oracle. + + .. change:: + :tags: ext + :tickets: 2090 + + The horizontal_shard ShardedSession class accepts the common + Session argument "query_cls" as a constructor argument, + to enable further subclassing of ShardedQuery. + + .. change:: + :tags: declarative + :tickets: 2050 + + Added an explicit check for the case that the name + 'metadata' is used for a column attribute on a + declarative class. + + .. change:: + :tags: declarative + :tickets: 2061 + + Fix error message referencing old @classproperty + name to reference @declared_attr + + .. change:: + :tags: declarative + :tickets: 2091 + + Arguments in __mapper_args__ that aren't "hashable" + aren't mistaken for always-hashable, possibly-column + arguments. + + .. change:: + :tags: documentation + :tickets: 2029 + + Documented SQLite DATE/TIME/DATETIME types. + + .. change:: + :tags: examples + :tickets: 2090 + + The Beaker caching example allows a "query_cls" argument + to the query_callable() function. + +.. changelog:: + :version: 0.6.6 + :released: Sat Jan 08 2011 + + .. change:: + :tags: orm + :tickets: + + Fixed bug whereby a non-"mutable" attribute modified event + which occurred on an object that was clean except for + preceding mutable attribute changes would fail to strongly + reference itself in the identity map. This would cause the + object to be garbage collected, losing track of any changes + that weren't previously saved in the "mutable changes" + dictionary. + + .. change:: + :tags: orm + :tickets: 2013 + + Fixed bug whereby "passive_deletes='all'" wasn't passing + the correct symbols to lazy loaders during flush, thereby + causing an unwarranted load. + + .. change:: + :tags: orm + :tickets: 1997 + + Fixed bug which prevented composite mapped + attributes from being used on a mapped select statement.. Note the workings of composite are slated to + change significantly in 0.7. + + .. change:: + :tags: orm + :tickets: 1976 + + active_history flag also added to composite(). + The flag has no effect in 0.6, but is instead + a placeholder flag for forwards compatibility, + as it applies in 0.7 for composites. + + .. change:: + :tags: orm + :tickets: 2002 + + Fixed uow bug whereby expired objects passed to + Session.delete() would not have unloaded references + or collections taken into account when deleting + objects, despite passive_deletes remaining at + its default of False. + + .. change:: + :tags: orm + :tickets: 1987 + + A warning is emitted when version_id_col is specified + on an inheriting mapper when the inherited mapper + already has one, if those column expressions are not + the same. + + .. change:: + :tags: orm + :tickets: 1954 + + "innerjoin" flag doesn't take effect along the chain + of joinedload() joins if a previous join in that chain + is an outer join, thus allowing primary rows without + a referenced child row to be correctly returned + in results. + + .. change:: + :tags: orm + :tickets: 1964 + + Fixed bug regarding "subqueryload" strategy whereby + strategy would fail if the entity was an aliased() + construct. + + .. change:: + :tags: orm + :tickets: 2014 + + Fixed bug regarding "subqueryload" strategy whereby + the join would fail if using a multi-level load + of the form from A->joined-subclass->C + + .. change:: + :tags: orm + :tickets: 1968 + + Fixed indexing of Query objects by -1. It was erroneously + transformed to the empty slice -1:0 that resulted in + IndexError. + + .. change:: + :tags: orm + :tickets: 1971 + + The mapper argument "primary_key" can be passed as a + single column as well as a list or tuple. + The documentation examples that illustrated it as a + scalar value have been changed to lists. + + .. change:: + :tags: orm + :tickets: 1961 + + Added active_history flag to relationship() + and column_property(), forces attribute events to + always load the "old" value, so that it's available to + attributes.get_history(). + + .. change:: + :tags: orm + :tickets: 1977 + + Query.get() will raise if the number of params + in a composite key is too large, as well as too + small. + + .. change:: + :tags: orm + :tickets: 1992 + + Backport of "optimized get" fix from 0.7, + improves the generation of joined-inheritance + "load expired row" behavior. + + .. change:: + :tags: orm + :tickets: + + A little more verbiage to the "primaryjoin" error, + in an unusual condition that the join condition + "works" for viewonly but doesn't work for non-viewonly, + and foreign_keys wasn't used - adds "foreign_keys" to + the suggestion. Also add "foreign_keys" to the + suggestion for the generic "direction" error. + + .. change:: + :tags: sql + :tickets: 1984 + + Fixed operator precedence rules for multiple + chains of a single non-associative operator. + I.e. "x - (y - z)" will compile as "x - (y - z)" + and not "x - y - z". Also works with labels, + i.e. "x - (y - z).label('foo')" + + .. change:: + :tags: sql + :tickets: 1967 + + The 'info' attribute of Column is copied during + Column.copy(), i.e. as occurs when using columns + in declarative mixins. + + .. change:: + :tags: sql + :tickets: + + Added a bind processor for booleans which coerces + to int, for DBAPIs such as pymssql that naively call + str() on values. + + .. change:: + :tags: sql + :tickets: 2000 + + CheckConstraint will copy its 'initially', 'deferrable', + and '_create_rule' attributes within a copy()/tometadata() + + .. change:: + :tags: engine + :tickets: + + The "unicode warning" against non-unicode bind data + is now raised only when the + Unicode type is used explictly; not when + convert_unicode=True is used on the engine + or String type. + + .. change:: + :tags: engine + :tickets: 1978 + + Fixed memory leak in C version of Decimal result + processor. + + .. change:: + :tags: engine + :tickets: 1871 + + Implemented sequence check capability for the C + version of RowProxy, as well as 2.7 style + "collections.Sequence" registration for RowProxy. + + .. change:: + :tags: engine + :tickets: 1998 + + Threadlocal engine methods rollback(), commit(), + prepare() won't raise if no transaction is in progress; + this was a regression introduced in 0.6. + + .. change:: + :tags: engine + :tickets: 2004 + + Threadlocal engine returns itself upon begin(), + begin_nested(); engine then implements contextmanager + methods to allow the "with" statement. + + .. change:: + :tags: postgresql + :tickets: 1984 + + Single element tuple expressions inside an IN clause + parenthesize correctly, also from + + .. change:: + :tags: postgresql + :tickets: 1955 + + Ensured every numeric, float, int code, scalar + array, + are recognized by psycopg2 and pg8000's "numeric" + base type. + + .. change:: + :tags: postgresql + :tickets: 1956 + + Added as_uuid=True flag to the UUID type, will receive + and return values as Python UUID() objects rather than + strings. Currently, the UUID type is only known to + work with psycopg2. + + .. change:: + :tags: postgresql + :tickets: 1989 + + Fixed bug whereby KeyError would occur with non-ENUM + supported PG versions after a pool dispose+recreate + would occur. + + .. change:: + :tags: mysql + :tickets: 1960 + + Fixed error handling for Jython + zxjdbc, such that + has_table() property works again. Regression from + 0.6.3 (we don't have a Jython buildbot, sorry) + + .. change:: + :tags: sqlite + :tickets: 1851 + + The REFERENCES clause in a CREATE TABLE that includes + a remote schema to another table with the same schema + name now renders the remote name without + the schema clause, as required by SQLite. + + .. change:: + :tags: sqlite + :tickets: + + On the same theme, the REFERENCES clause in a CREATE TABLE + that includes a remote schema to a *different* schema + than that of the parent table doesn't render at all, + as cross-schema references do not appear to be supported. + + .. change:: + :tags: mssql + :tickets: 1770 + + The rewrite of index reflection in was + unfortunately not tested correctly, and returned incorrect + results. This regression is now fixed. + + .. change:: + :tags: oracle + :tickets: 1953 + + The cx_oracle "decimal detection" logic, which takes place + for for result set columns with ambiguous numeric characteristics, + now uses the decimal point character determined by the locale/ + NLS_LANG setting, using an on-first-connect detection of + this character. cx_oracle 5.0.3 or greater is also required + when using a non-period-decimal-point NLS_LANG setting.. + + .. change:: + :tags: firebird + :tickets: 2012 + + Firebird numeric type now checks for Decimal explicitly, + lets float() pass right through, thereby allowing + special values such as float('inf'). + + .. change:: + :tags: declarative + :tickets: 1972 + + An error is raised if __table_args__ is not in tuple + or dict format, and is not None. + + .. change:: + :tags: sqlsoup + :tickets: 1975 + + Added "map_to()" method to SqlSoup, which is a "master" + method which accepts explicit arguments for each aspect of + the selectable and mapping, including a base class per + mapping. + + .. change:: + :tags: sqlsoup + :tickets: + + Mapped selectables used with the map(), with_labels(), + join() methods no longer put the given argument into the + internal "cache" dictionary. Particularly since the + join() and select() objects are created in the method + itself this was pretty much a pure memory leaking behavior. + + .. change:: + :tags: examples + :tickets: + + The versioning example now supports detection of changes + in an associated relationship(). + +.. changelog:: + :version: 0.6.5 + :released: Sun Oct 24 2010 + + .. change:: + :tags: orm + :tickets: 1914 + + Added a new "lazyload" option "immediateload". + Issues the usual "lazy" load operation automatically + as the object is populated. The use case + here is when loading objects to be placed in + an offline cache, or otherwise used after + the session isn't available, and straight 'select' + loading, not 'joined' or 'subquery', is desired. + + .. change:: + :tags: orm + :tickets: 1920 + + New Query methods: query.label(name), query.as_scalar(), + return the query's statement as a scalar subquery + with /without label; + query.with_entities(*ent), replaces the SELECT list of + the query with new entities. + Roughly equivalent to a generative form of query.values() + which accepts mapped entities as well as column + expressions. + + .. change:: + :tags: orm + :tickets: + + Fixed recursion bug which could occur when moving + an object from one reference to another, with + backrefs involved, where the initiating parent + was a subclass (with its own mapper) of the + previous parent. + + .. change:: + :tags: orm + :tickets: 1918 + + Fixed a regression in 0.6.4 which occurred if you + passed an empty list to "include_properties" on + mapper() + + .. change:: + :tags: orm + :tickets: + + Fixed labeling bug in Query whereby the NamedTuple + would mis-apply labels if any of the column + expressions were un-labeled. + + .. change:: + :tags: orm + :tickets: 1925 + + Patched a case where query.join() would adapt the + right side to the right side of the left's join + inappropriately + + .. change:: + :tags: orm + :tickets: + + Query.select_from() has been beefed up to help + ensure that a subsequent call to query.join() + will use the select_from() entity, assuming it's + a mapped entity and not a plain selectable, + as the default "left" side, not the first entity + in the Query object's list of entities. + + .. change:: + :tags: orm + :tickets: + + The exception raised by Session when it is used + subsequent to a subtransaction rollback (which is what + happens when a flush fails in autocommit=False mode) has + now been reworded (this is the "inactive due to a + rollback in a subtransaction" message). In particular, + if the rollback was due to an exception during flush(), + the message states this is the case, and reiterates the + string form of the original exception that occurred + during flush. If the session is closed due to explicit + usage of subtransactions (not very common), the message + just states this is the case. + + .. change:: + :tags: orm + :tickets: + + The exception raised by Mapper when repeated requests to + its initialization are made after initialization already + failed no longer assumes the "hasattr" case, since + there's other scenarios in which this message gets + emitted, and the message also does not compound onto + itself multiple times - you get the same message for + each attempt at usage. The misnomer "compiles" is being + traded out for "initialize". + + .. change:: + :tags: orm + :tickets: 1935 + + Fixed bug in query.update() where 'evaluate' or 'fetch' + expiration would fail if the column expression key was + a class attribute with a different keyname as the + actual column name. + + .. change:: + :tags: orm + :tickets: + + Added an assertion during flush which ensures + that no NULL-holding identity keys were generated + on "newly persistent" objects. + This can occur when user defined code inadvertently + triggers flushes on not-fully-loaded objects. + + .. change:: + :tags: orm + :tickets: 1910 + + lazy loads for relationship attributes now use + the current state, not the "committed" state, + of foreign and primary key attributes + when issuing SQL, if a flush is not in process. + Previously, only the database-committed state would + be used. In particular, this would cause a many-to-one + get()-on-lazyload operation to fail, as autoflush + is not triggered on these loads when the attributes are + determined and the "committed" state may not be + available. + + .. change:: + :tags: orm + :tickets: + + A new flag on relationship(), load_on_pending, allows + the lazy loader to fire off on pending objects without a + flush taking place, as well as a transient object that's + been manually "attached" to the session. Note that this + flag blocks attribute events from taking place when an + object is loaded, so backrefs aren't available until + after a flush. The flag is only intended for very + specific use cases. + + .. change:: + :tags: orm + :tickets: + + Another new flag on relationship(), cascade_backrefs, + disables the "save-update" cascade when the event was + initiated on the "reverse" side of a bidirectional + relationship. This is a cleaner behavior so that + many-to-ones can be set on a transient object without + it getting sucked into the child object's session, + while still allowing the forward collection to + cascade. We *might* default this to False in 0.7. + + .. change:: + :tags: orm + :tickets: + + Slight improvement to the behavior of + "passive_updates=False" when placed only on the + many-to-one side of a relationship; documentation has + been clarified that passive_updates=False should really + be on the one-to-many side. + + .. change:: + :tags: orm + :tickets: + + Placing passive_deletes=True on a many-to-one emits + a warning, since you probably intended to put it on + the one-to-many side. + + .. change:: + :tags: orm + :tickets: + + Fixed bug that would prevent "subqueryload" from + working correctly with single table inheritance + for a relationship from a subclass - the "where + type in (x, y, z)" only gets placed on the inside, + instead of repeatedly. + + .. change:: + :tags: orm + :tickets: + + When using from_self() with single table inheritance, + the "where type in (x, y, z)" is placed on the outside + of the query only, instead of repeatedly. May make + some more adjustments to this. + + .. change:: + :tags: orm + :tickets: 1924 + + scoped_session emits a warning when configure() is + called if a Session is already present (checks only the + current thread) + + .. change:: + :tags: orm + :tickets: 1932 + + reworked the internals of mapper.cascade_iterator() to + cut down method calls by about 9% in some circumstances. + + .. change:: + :tags: sql + :tickets: + + Fixed bug in TypeDecorator whereby the dialect-specific + type was getting pulled in to generate the DDL for a + given type, which didn't always return the correct result. + + .. change:: + :tags: sql + :tickets: + + TypeDecorator can now have a fully constructed type + specified as its "impl", in addition to a type class. + + .. change:: + :tags: sql + :tickets: + + TypeDecorator will now place itself as the resulting + type for a binary expression where the type coercion + rules would normally return its impl type - previously, + a copy of the impl type would be returned which would + have the TypeDecorator embedded into it as the "dialect" + impl, this was probably an unintentional way of achieving + the desired effect. + + .. change:: + :tags: sql + :tickets: + + TypeDecorator.load_dialect_impl() returns "self.impl" by + default, i.e. not the dialect implementation type of + "self.impl". This to support compilation correctly. + Behavior can be user-overridden in exactly the same way + as before to the same effect. + + .. change:: + :tags: sql + :tickets: + + Added type_coerce(expr, type_) expression element. + Treats the given expression as the given type when evaluating + expressions and processing result rows, but does not + affect the generation of SQL, other than an anonymous + label. + + .. change:: + :tags: sql + :tickets: + + Table.tometadata() now copies Index objects associated + with the Table as well. + + .. change:: + :tags: sql + :tickets: + + Table.tometadata() issues a warning if the given Table + is already present in the target MetaData - the existing + Table object is returned. + + .. change:: + :tags: sql + :tickets: + + An informative error message is raised if a Column + which has not yet been assigned a name, i.e. as in + declarative, is used in a context where it is + exported to the columns collection of an enclosing + select() construct, or if any construct involving + that column is compiled before its name is + assigned. + + .. change:: + :tags: sql + :tickets: 1862 + + as_scalar(), label() can be called on a selectable + which contains a Column that is not yet named. + + .. change:: + :tags: sql + :tickets: 1907 + + Fixed recursion overflow which could occur when operating + with two expressions both of type "NullType", but + not the singleton NULLTYPE instance. + + .. change:: + :tags: declarative + :tickets: 1922 + + @classproperty (soon/now @declared_attr) takes effect for + __mapper_args__, __table_args__, __tablename__ on + a base class that is not a mixin, as well as mixins. + + .. change:: + :tags: declarative + :tickets: 1915 + + @classproperty 's official name/location for usage + with declarative is sqlalchemy.ext.declarative.declared_attr. + Same thing, but moving there since it is more of a + "marker" that's specific to declararative, + not just an attribute technique. + + .. change:: + :tags: declarative + :tickets: 1931, 1930 + + Fixed bug whereby columns on a mixin wouldn't propagate + correctly to a single-table, or joined-table, + inheritance scheme where the attribute name is + different than that of the column.,. + + .. change:: + :tags: declarative + :tickets: + + A mixin can now specify a column that overrides + a column of the same name associated with a superclass. + Thanks to Oystein Haaland. + + .. change:: + :tags: engine + :tickets: + + Fixed a regression in 0.6.4 whereby the change that + allowed cursor errors to be raised consistently broke + the result.lastrowid accessor. Test coverage has + been added for result.lastrowid. Note that lastrowid + is only supported by Pysqlite and some MySQL drivers, + so isn't super-useful in the general case. + + .. change:: + :tags: engine + :tickets: + + the logging message emitted by the engine when + a connection is first used is now "BEGIN (implicit)" + to emphasize that DBAPI has no explicit begin(). + + .. change:: + :tags: engine + :tickets: 1936 + + added "views=True" option to metadata.reflect(), + will add the list of available views to those + being reflected. + + .. change:: + :tags: engine + :tickets: 1899 + + engine_from_config() now accepts 'debug' for + 'echo', 'echo_pool', 'force' for 'convert_unicode', + boolean values for 'use_native_unicode'. + + .. change:: + :tags: postgresql + :tickets: + + Added "as_tuple" flag to ARRAY type, returns results + as tuples instead of lists to allow hashing. + + .. change:: + :tags: postgresql + :tickets: 1933 + + Fixed bug which prevented "domain" built from a + custom type such as "enum" from being reflected. + + .. change:: + :tags: mysql + :tickets: 1940 + + Fixed bug involving reflection of CURRENT_TIMESTAMP + default used with ON UPDATE clause, thanks to + Taavi Burns + + .. change:: + :tags: oracle + :tickets: 1878 + + The implicit_retunring argument to create_engine() + is now honored regardless of detected version of + Oracle. Previously, the flag would be forced + to False if server version info was < 10. + + .. change:: + :tags: mssql + :tickets: 1946 + + Fixed reflection bug which did not properly handle + reflection of unknown types. + + .. change:: + :tags: mssql + :tickets: 1943 + + Fixed bug where aliasing of tables with "schema" would + fail to compile properly. + + .. change:: + :tags: mssql + :tickets: 1770 + + Rewrote the reflection of indexes to use sys. + catalogs, so that column names of any configuration + (spaces, embedded commas, etc.) can be reflected. + Note that reflection of indexes requires SQL + Server 2005 or greater. + + .. change:: + :tags: mssql + :tickets: 1952 + + mssql+pymssql dialect now honors the "port" portion + of the URL instead of discarding it. + + .. change:: + :tags: informix + :tickets: 1906 + + *Major* cleanup / modernization of the Informix + dialect for 0.6, courtesy Florian Apolloner. + + .. change:: + :tags: tests + :tickets: + + the NoseSQLAlchemyPlugin has been moved to a + new package "sqlalchemy_nose" which installs + along with "sqlalchemy". This so that the "nosetests" + script works as always but also allows the + --with-coverage option to turn on coverage before + SQLAlchemy modules are imported, allowing coverage + to work correctly. + + .. change:: + :tags: misc + :tickets: 1890 + + CircularDependencyError now has .cycles and .edges + members, which are the set of elements involved in + one or more cycles, and the set of edges as 2-tuples. + +.. changelog:: + :version: 0.6.4 + :released: Tue Sep 07 2010 + + .. change:: + :tags: orm + :tickets: + + The name ConcurrentModificationError has been + changed to StaleDataError, and descriptive + error messages have been revised to reflect + exactly what the issue is. Both names will + remain available for the forseeable future + for schemes that may be specifying + ConcurrentModificationError in an "except:" + clause. + + .. change:: + :tags: orm + :tickets: 1891 + + Added a mutex to the identity map which mutexes + remove operations against iteration methods, + which now pre-buffer before returning an + iterable. This because asyncrhonous gc + can remove items via the gc thread at any time. + + .. change:: + :tags: orm + :tickets: + + The Session class is now present in sqlalchemy.orm.*. + We're moving away from the usage of create_session(), + which has non-standard defaults, for those situations + where a one-step Session constructor is desired. Most + users should stick with sessionmaker() for general use, + however. + + .. change:: + :tags: orm + :tickets: + + query.with_parent() now accepts transient objects + and will use the non-persistent values of their pk/fk + attributes in order to formulate the criterion. + Docs are also clarified as to the purpose of with_parent(). + + .. change:: + :tags: orm + :tickets: + + The include_properties and exclude_properties arguments + to mapper() now accept Column objects as members in + addition to strings. This so that same-named Column + objects, such as those within a join(), can be + disambiguated. + + .. change:: + :tags: orm + :tickets: 1896 + + A warning is now emitted if a mapper is created against a + join or other single selectable that includes multiple + columns with the same name in its .c. collection, + and those columns aren't explictly named as part of + the same or separate attributes (or excluded). + In 0.7 this warning will be an exception. Note that + this warning is not emitted when the combination occurs + as a result of inheritance, so that attributes + still allow being overridden naturally.. In 0.7 this will be improved further. + + .. change:: + :tags: orm + :tickets: 1896 + + The primary_key argument to mapper() can now specify + a series of columns that are only a subset of + the calculated "primary key" columns of the mapped + selectable, without an error being raised. This + helps for situations where a selectable's effective + primary key is simpler than the number of columns + in the selectable that are actually marked as + "primary_key", such as a join against two + tables on their primary key columns. + + .. change:: + :tags: orm + :tickets: + + An object that's been deleted now gets a flag + 'deleted', which prohibits the object from + being re-add()ed to the session, as previously + the object would live in the identity map + silently until its attributes were accessed. + The make_transient() function now resets this + flag along with the "key" flag. + + .. change:: + :tags: orm + :tickets: + + make_transient() can be safely called on an + already transient instance. + + .. change:: + :tags: orm + :tickets: + + a warning is emitted in mapper() if the polymorphic_on + column is not present either in direct or derived + form in the mapped selectable or in the + with_polymorphic selectable, instead of silently + ignoring it. Look for this to become an + exception in 0.7. + + .. change:: + :tags: orm + :tickets: + + Another pass through the series of error messages + emitted when relationship() is configured with + ambiguous arguments. The "foreign_keys" + setting is no longer mentioned, as it is almost + never needed and it is preferable users set up + correct ForeignKey metadata, which is now the + recommendation. If 'foreign_keys' + is used and is incorrect, the message suggests + the attribute is probably unnecessary. Docs + for the attribute are beefed up. This + because all confused relationship() users on the + ML appear to be attempting to use foreign_keys + due to the message, which only confuses them + further since Table metadata is much clearer. + + .. change:: + :tags: orm + :tickets: 1877 + + If the "secondary" table has no ForeignKey metadata + and no foreign_keys is set, even though the + user is passing screwed up information, it is assumed + that primary/secondaryjoin expressions should + consider only and all cols in "secondary" to be + foreign. It's not possible with "secondary" for + the foreign keys to be elsewhere in any case. + A warning is now emitted instead of an error, + and the mapping succeeds. + + .. change:: + :tags: orm + :tickets: 1856 + + Moving an o2m object from one collection to + another, or vice versa changing the referenced + object by an m2o, where the foreign key is also a + member of the primary key, will now be more + carefully checked during flush if the change in + value of the foreign key on the "many" side is the + result of a change in the primary key of the "one" + side, or if the "one" is just a different object. + In one case, a cascade-capable DB would have + cascaded the value already and we need to look at + the "new" PK value to do an UPDATE, in the other we + need to continue looking at the "old". We now look + at the "old", assuming passive_updates=True, + unless we know it was a PK switch that + triggered the change. + + .. change:: + :tags: orm + :tickets: 1857 + + The value of version_id_col can be changed + manually, and this will result in an UPDATE + of the row. Versioned UPDATEs and DELETEs + now use the "committed" value of the + version_id_col in the WHERE clause and + not the pending changed value. The + version generator is also bypassed if + manual changes are present on the attribute. + + .. change:: + :tags: orm + :tickets: + + Repaired the usage of merge() when used with + concrete inheriting mappers. Such mappers frequently + have so-called "concrete" attributes, which are + subclass attributes that "disable" propagation from + the parent - these needed to allow a merge() + operation to pass through without effect. + + .. change:: + :tags: orm + :tickets: 1863 + + Specifying a non-column based argument + for column_mapped_collection, including string, + text() etc., will raise an error message that + specifically asks for a column element, no longer + misleads with incorrect information about + text() or literal(). + + .. change:: + :tags: orm + :tickets: + + Similarly, for relationship(), foreign_keys, + remote_side, order_by - all column-based + expressions are enforced - lists of strings + are explicitly disallowed since this is a + very common error + + .. change:: + :tags: orm + :tickets: 1864 + + Dynamic attributes don't support collection + population - added an assertion for when + set_committed_value() is called, as well as + when joinedload() or subqueryload() options + are applied to a dynamic attribute, instead + of failure / silent failure. + + .. change:: + :tags: orm + :tickets: 1852 + + Fixed bug whereby generating a Query derived + from one which had the same column repeated + with different label names, typically + in some UNION situations, would fail to + propagate the inner columns completely to + the outer query. + + .. change:: + :tags: orm + :tickets: 1881 + + object_session() raises the proper + UnmappedInstanceError when presented with an + unmapped instance. + + .. change:: + :tags: orm + :tickets: + + Applied further memoizations to calculated Mapper + properties, with significant (~90%) runtime mapper.py + call count reduction in heavily polymorphic mapping + configurations. + + .. change:: + :tags: orm + :tickets: + + mapper _get_col_to_prop private method used + by the versioning example is deprecated; + now use mapper.get_property_by_column() which + will remain the public method for this. + + .. change:: + :tags: orm + :tickets: + + the versioning example works correctly now + if versioning on a col that was formerly + NULL. + + .. change:: + :tags: sql + :tickets: + + Calling execute() on an alias() construct is pending + deprecation for 0.7, as it is not itself an + "executable" construct. It currently "proxies" its + inner element and is conditionally "executable" but + this is not the kind of ambiguity we like these days. + + .. change:: + :tags: sql + :tickets: + + The execute() and scalar() methods of ClauseElement + are now moved appropriately to the Executable + subclass. ClauseElement.execute()/ scalar() are still + present and are pending deprecation in 0.7, but note + these would always raise an error anyway if you were + not an Executable (unless you were an alias(), see + previous note). + + .. change:: + :tags: sql + :tickets: + + Added basic math expression coercion for + Numeric->Integer, + so that resulting type is Numeric regardless + of the direction of the expression. + + .. change:: + :tags: sql + :tickets: 1855 + + Changed the scheme used to generate truncated + "auto" index names when using the "index=True" + flag on Column. The truncation only takes + place with the auto-generated name, not one + that is user-defined (an error would be + raised instead), and the truncation scheme + itself is now based on a fragment of an md5 + hash of the identifier name, so that multiple + indexes on columns with similar names still + have unique names. + + .. change:: + :tags: sql + :tickets: 1412 + + The generated index name also is based on + a "max index name length" attribute which is + separate from the "max identifier length" - + this to appease MySQL who has a max length + of 64 for index names, separate from their + overall max length of 255. + + .. change:: + :tags: sql + :tickets: + + the text() construct, if placed in a column + oriented situation, will at least return NULLTYPE + for its type instead of None, allowing it to + be used a little more freely for ad-hoc column + expressions than before. literal_column() + is still the better choice, however. + + .. change:: + :tags: sql + :tickets: + + Added full description of parent table/column, + target table/column in error message raised when + ForeignKey can't resolve target. + + .. change:: + :tags: sql + :tickets: 1865 + + Fixed bug whereby replacing composite foreign key + columns in a reflected table would cause an attempt + to remove the reflected constraint from the table + a second time, raising a KeyError. + + .. change:: + :tags: sql + :tickets: + + the _Label construct, i.e. the one that is produced + whenever you say somecol.label(), now counts itself + in its "proxy_set" unioned with that of it's + contained column's proxy set, instead of + directly returning that of the contained column. + This allows column correspondence + operations which depend on the identity of the + _Labels themselves to return the correct result + + .. change:: + :tags: sql + :tickets: 1852 + + fixes ORM bug. + + .. change:: + :tags: engine + :tickets: + + Calling fetchone() or similar on a result that + has already been exhausted, has been closed, + or is not a result-returning result now + raises ResourceClosedError, a subclass of + InvalidRequestError, in all cases, regardless + of backend. Previously, some DBAPIs would + raise ProgrammingError (i.e. pysqlite), others + would return None leading to downstream breakages + (i.e. MySQL-python). + + .. change:: + :tags: engine + :tickets: 1894 + + Fixed bug in Connection whereby if a "disconnect" + event occurred in the "initialize" phase of the + first connection pool connect, an AttributeError + would be raised when the Connection would attempt + to invalidate the DBAPI connection. + + .. change:: + :tags: engine + :tickets: + + Connection, ResultProxy, as well as Session use + ResourceClosedError for all "this + connection/transaction/result is closed" types of + errors. + + .. change:: + :tags: engine + :tickets: + + Connection.invalidate() can be called more than + once and subsequent calls do nothing. + + .. change:: + :tags: declarative + :tickets: + + if @classproperty is used with a regular class-bound + mapper property attribute, it will be called to get the + actual attribute value during initialization. Currently, + there's no advantage to using @classproperty on a column + or relationship attribute of a declarative class that + isn't a mixin - evaluation is at the same time as if + @classproperty weren't used. But here we at least allow + it to function as expected. + + .. change:: + :tags: declarative + :tickets: + + Fixed bug where "Can't add additional column" message + would display the wrong name. + + .. change:: + :tags: postgresql + :tickets: + + Fixed the psycopg2 dialect to use its + set_isolation_level() method instead of relying + upon the base "SET SESSION ISOLATION" command, + as psycopg2 resets the isolation level on each new + transaction otherwise. + + .. change:: + :tags: mssql + :tickets: + + Fixed "default schema" query to work with + pymssql backend. + + .. change:: + :tags: firebird + :tickets: + + Fixed bug whereby a column default would fail to + reflect if the "default" keyword were lower case. + + .. change:: + :tags: oracle + :tickets: 1879 + + Added ROWID type to the Oracle dialect, for those + cases where an explicit CAST might be needed. + + .. change:: + :tags: oracle + :tickets: 1867 + + Oracle reflection of indexes has been tuned so + that indexes which include some or all primary + key columns, but not the same set of columns + as that of the primary key, are reflected. + Indexes which contain the identical columns + as that of the primary key are skipped within + reflection, as the index in that case is assumed + to be the auto-generated primary key index. + Previously, any index with PK columns present + would be skipped. Thanks to Kent Bower + for the patch. + + .. change:: + :tags: oracle + :tickets: 1868 + + Oracle now reflects the names of primary key + constraints - also thanks to Kent Bower. + + .. change:: + :tags: informix + :tickets: 1904 + + Applied patches from to get + basic Informix functionality up again. We + rely upon end-user testing to ensure that + Informix is working to some degree. + + .. change:: + :tags: documentation + :tickets: + + The docs have been reorganized such that the "API + Reference" section is gone - all the docstrings from + there which were public API are moved into the + context of the main doc section that talks about it. + Main docs divided into "SQLAlchemy Core" and + "SQLAlchemy ORM" sections, mapper/relationship docs + have been broken out. Lots of sections rewritten + and/or reorganized. + + .. change:: + :tags: examples + :tickets: + + The beaker_caching example has been reorgnized + such that the Session, cache manager, + declarative_base are part of environment, and + custom cache code is portable and now within + "caching_query.py". This allows the example to + be easier to "drop in" to existing projects. + + .. change:: + :tags: examples + :tickets: 1887 + + the history_meta versioning recipe sets "unique=False" + when copying columns, so that the versioning + table handles multiple rows with repeating values. + +.. changelog:: + :version: 0.6.3 + :released: Thu Jul 15 2010 + + .. change:: + :tags: orm + :tickets: 1845 + + Removed errant many-to-many load in unitofwork + which triggered unnecessarily on expired/unloaded + collections. This load now takes place only if + passive_updates is False and the parent primary + key has changed, or if passive_deletes is False + and a delete of the parent has occurred. + + .. change:: + :tags: orm + :tickets: 1853 + + Column-entities (i.e. query(Foo.id)) copy their + state more fully when queries are derived from + themselves + a selectable (i.e. from_self(), + union(), etc.), so that join() and such have the + correct state to work from. + + .. change:: + :tags: orm + :tickets: 1853 + + Fixed bug where Query.join() would fail if + querying a non-ORM column then joining without + an on clause when a FROM clause is already + present, now raises a checked exception the + same way it does when the clause is not + present. + + .. change:: + :tags: orm + :tickets: 1142 + + Improved the check for an "unmapped class", + including the case where the superclass is mapped + but the subclass is not. Any attempts to access + cls._sa_class_manager.mapper now raise + UnmappedClassError(). + + .. change:: + :tags: orm + :tickets: + + Added "column_descriptions" accessor to Query, + returns a list of dictionaries containing + naming/typing information about the entities + the Query will return. Can be helpful for + building GUIs on top of ORM queries. + + .. change:: + :tags: mysql + :tickets: 1848 + + The _extract_error_code() method now works + correctly with each MySQL dialect ( + MySQL-python, OurSQL, MySQL-Connector-Python, + PyODBC). Previously, + the reconnect logic would fail for OperationalError + conditions, however since MySQLdb and OurSQL + have their own reconnect feature, there was no + symptom for these drivers here unless one + watched the logs. + + .. change:: + :tags: oracle + :tickets: 1840 + + More tweaks to cx_oracle Decimal handling. + "Ambiguous" numerics with no decimal place + are coerced to int at the connection handler + level. The advantage here is that ints + come back as ints without SQLA type + objects being involved and without needless + conversion to Decimal first. + + Unfortunately, some exotic subquery cases + can even see different types between + individual result rows, so the Numeric + handler, when instructed to return Decimal, + can't take full advantage of "native decimal" + mode and must run isinstance() on every value + to check if its Decimal already. Reopen of + +.. changelog:: + :version: 0.6.2 + :released: Tue Jul 06 2010 + + .. change:: + :tags: orm + :tickets: + + Query.join() will check for a call of the + form query.join(target, clause_expression), + i.e. missing the tuple, and raise an informative + error message that this is the wrong calling form. + + .. change:: + :tags: orm + :tickets: 1824 + + Fixed bug regarding flushes on self-referential + bi-directional many-to-many relationships, where + two objects made to mutually reference each other + in one flush would fail to insert a row for both + sides. Regression from 0.5. + + .. change:: + :tags: orm + :tickets: + + the post_update feature of relationship() has been + reworked architecturally to integrate more closely + with the new 0.6 unit of work. The motivation + for the change is so that multiple "post update" + calls, each affecting different foreign key + columns of the same row, are executed in a single + UPDATE statement, rather than one UPDATE + statement per column per row. Multiple row + updates are also batched into executemany()s as + possible, while maintaining consistent row ordering. + + .. change:: + :tags: orm + :tickets: + + Query.statement, Query.subquery(), etc. now transfer + the values of bind parameters, i.e. those specified + by query.params(), into the resulting SQL expression. + Previously the values would not be transferred + and bind parameters would come out as None. + + .. change:: + :tags: orm + :tickets: + + Subquery-eager-loading now works with Query objects + which include params(), as well as get() Queries. + + .. change:: + :tags: orm + :tickets: + + Can now call make_transient() on an instance that + is referenced by parent objects via many-to-one, + without the parent's foreign key value getting + temporarily set to None - this was a function + of the "detect primary key switch" flush handler. + It now ignores objects that are no longer + in the "persistent" state, and the parent's + foreign key identifier is left unaffected. + + .. change:: + :tags: orm + :tickets: + + query.order_by() now accepts False, which cancels + any existing order_by() state on the Query, allowing + subsequent generative methods to be called which do + not support ORDER BY. This is not the same as the + already existing feature of passing None, which + suppresses any existing order_by() settings, including + those configured on the mapper. False will make it + as though order_by() was never called, while + None is an active setting. + + .. change:: + :tags: orm + :tickets: + + An instance which is moved to "transient", has + an incomplete or missing set of primary key + attributes, and contains expired attributes, will + raise an InvalidRequestError if an expired attribute + is accessed, instead of getting a recursion overflow. + + .. change:: + :tags: orm + :tickets: + + The make_transient() function is now in the generated + documentation. + + .. change:: + :tags: orm + :tickets: + + make_transient() removes all "loader" callables from + the state being made transient, removing any + "expired" state - all unloaded attributes reset back + to undefined, None/empty on access. + + .. change:: + :tags: sql + :tickets: 1822 + + The warning emitted by the Unicode and String types + with convert_unicode=True no longer embeds the actual + value passed. This so that the Python warning + registry does not continue to grow in size, the warning + is emitted once as per the warning filter settings, + and large string values don't pollute the output. + + .. change:: + :tags: sql + :tickets: + + Fixed bug that would prevent overridden clause + compilation from working for "annotated" expression + elements, which are often generated by the ORM. + + .. change:: + :tags: sql + :tickets: 1400 + + The argument to "ESCAPE" of a LIKE operator or similar + is passed through render_literal_value(), which may + implement escaping of backslashes. + + .. change:: + :tags: sql + :tickets: + + Fixed bug in Enum type which blew away native_enum + flag when used with TypeDecorators or other adaption + scenarios. + + .. change:: + :tags: sql + :tickets: + + Inspector hits bind.connect() when invoked to ensure + initialize has been called. the internal name ".conn" + is changed to ".bind", since that's what it is. + + .. change:: + :tags: sql + :tickets: + + Modified the internals of "column annotation" such that + a custom Column subclass can safely override + _constructor to return Column, for the purposes of + making "configurational" column classes that aren't + involved in proxying, etc. + + .. change:: + :tags: sql + :tickets: 1829 + + Column.copy() takes along the "unique" attribute + among others, fixes regarding declarative + mixins + + .. change:: + :tags: postgresql + :tickets: 1400 + + render_literal_value() is overridden which escapes + backslashes, currently applies to the ESCAPE clause + of LIKE and similar expressions. + Ultimately this will have to detect the value of + "standard_conforming_strings" for full behavior. + + .. change:: + :tags: postgresql + :tickets: 1836 + + Won't generate "CREATE TYPE" / "DROP TYPE" if + using types.Enum on a PG version prior to 8.3 - + the supports_native_enum flag is fully + honored. + + .. change:: + :tags: mysql + :tickets: 1826 + + MySQL dialect doesn't emit CAST() for MySQL version + detected < 4.0.2. This allows the unicode + check on connect to proceed. + + .. change:: + :tags: mysql + :tickets: + + MySQL dialect now detects NO_BACKSLASH_ESCAPES sql + mode, in addition to ANSI_QUOTES. + + .. change:: + :tags: mysql + :tickets: 1400 + + render_literal_value() is overridden which escapes + backslashes, currently applies to the ESCAPE clause + of LIKE and similar expressions. This behavior + is derived from detecting the value of + NO_BACKSLASH_ESCAPES. + + .. change:: + :tags: oracle + :tickets: 1819 + + Fixed ora-8 compatibility flags such that they + don't cache a stale value from before the first + database connection actually occurs. + + .. change:: + :tags: oracle + :tickets: 1840 + + Oracle's "native decimal" metadata begins to return + ambiguous typing information about numerics + when columns are embedded in subqueries as well + as when ROWNUM is consulted with subqueries, as we + do for limit/offset. We've added these ambiguous + conditions to the cx_oracle "convert to Decimal()" + handler, so that we receive numerics as Decimal + in more cases instead of as floats. These are + then converted, if requested, into Integer + or Float, or otherwise kept as the lossless + Decimal. + + .. change:: + :tags: mssql + :tickets: 1825 + + If server_version_info is outside the usual + range of (8, ), (9, ), (10, ), a warning is emitted + which suggests checking that the FreeTDS version + configuration is using 7.0 or 8.0, not 4.2. + + .. change:: + :tags: firebird + :tickets: 1823 + + Fixed incorrect signature in do_execute(), error + introduced in 0.6.1. + + .. change:: + :tags: firebird + :tickets: 1813 + + Firebird dialect adds CHAR, VARCHAR types which + accept a "charset" flag, to support Firebird + "CHARACTER SET" clause. + + .. change:: + :tags: declarative + :tickets: 1805, 1796, 1751 + + Added support for @classproperty to provide + any kind of schema/mapping construct from a + declarative mixin, including columns with foreign + keys, relationships, column_property, deferred. + This solves all such issues on declarative mixins. + An error is raised if any MapperProperty subclass + is specified on a mixin without using @classproperty. + + .. change:: + :tags: declarative + :tickets: 1821 + + a mixin class can now define a column that matches + one which is present on a __table__ defined on a + subclass. It cannot, however, define one that is + not present in the __table__, and the error message + here now works. + + .. change:: + :tags: extension, compiler + :tickets: 1838 + + The 'default' compiler is automatically copied over + when overriding the compilation of a built in + clause construct, so no KeyError is raised if the + user-defined compiler is specific to certain + backends and compilation for a different backend + is invoked. + + .. change:: + :tags: documentation + :tickets: 1820 + + Added documentation for the Inspector. + + .. change:: + :tags: documentation + :tickets: 1830 + + Fixed @memoized_property and @memoized_instancemethod + decorators so that Sphinx documentation picks up + these attributes and methods, such as + ResultProxy.inserted_primary_key. + +.. changelog:: + :version: 0.6.1 + :released: Mon May 31 2010 + + .. change:: + :tags: orm + :tickets: 1782 + + Fixed regression introduced in 0.6.0 involving improper + history accounting on mutable attributes. + + .. change:: + :tags: orm + :tickets: 1807 + + Fixed regression introduced in 0.6.0 unit of work refactor + that broke updates for bi-directional relationship() + with post_update=True. + + .. change:: + :tags: orm + :tickets: 1789 + + session.merge() will not expire attributes on the returned + instance if that instance is "pending". + + .. change:: + :tags: orm + :tickets: 1802 + + fixed __setstate__ method of CollectionAdapter to not + fail during deserialize where parent InstanceState not + yet unserialized. + + .. change:: + :tags: orm + :tickets: 1797 + + Added internal warning in case an instance without a + full PK happened to be expired and then was asked + to refresh. + + .. change:: + :tags: orm + :tickets: + + Added more aggressive caching to the mapper's usage of + UPDATE, INSERT, and DELETE expressions. Assuming the + statement has no per-object SQL expressions attached, + the expression objects are cached by the mapper after + the first create, and their compiled form is stored + persistently in a cache dictionary for the duration of + the related Engine. The cache is an LRUCache for the + rare case that a mapper receives an extremely + high number of different column patterns as UPDATEs. + + .. change:: + :tags: sql + :tickets: 1793 + + expr.in_() now accepts a text() construct as the argument. + Grouping parenthesis are added automatically, i.e. usage + is like `col.in_(text("select id from table"))`. + + .. change:: + :tags: sql + :tickets: + + Columns of _Binary type (i.e. LargeBinary, BLOB, etc.) + will coerce a "basestring" on the right side into a + _Binary as well so that required DBAPI processing + takes place. + + .. change:: + :tags: sql + :tickets: 1801 + + Added table.add_is_dependent_on(othertable), allows manual + placement of dependency rules between two Table objects + for use within create_all(), drop_all(), sorted_tables. + + .. change:: + :tags: sql + :tickets: 1778 + + Fixed bug that prevented implicit RETURNING from functioning + properly with composite primary key that contained zeroes. + + .. change:: + :tags: sql + :tickets: + + Fixed errant space character when generating ADD CONSTRAINT + for a named UNIQUE constraint. + + .. change:: + :tags: sql + :tickets: 1571 + + Fixed "table" argument on constructor of ForeginKeyConstraint + + .. change:: + :tags: sql + :tickets: 1786 + + Fixed bug in connection pool cursor wrapper whereby if a + cursor threw an exception on close(), the logging of the + message would fail. + + .. change:: + :tags: sql + :tickets: + + the _make_proxy() method of ColumnClause and Column now use + self.__class__ to determine the class of object to be returned + instead of hardcoding to ColumnClause/Column, making it slightly + easier to produce specific subclasses of these which work in + alias/subquery situations. + + .. change:: + :tags: sql + :tickets: 1798 + + func.XXX() doesn't inadvertently resolve to non-Function + classes (e.g. fixes func.text()). + + .. change:: + :tags: engines + :tickets: 1781 + + Fixed building the C extensions on Python 2.4. + + .. change:: + :tags: engines + :tickets: + + Pool classes will reuse the same "pool_logging_name" setting + after a dispose() occurs. + + .. change:: + :tags: engines + :tickets: + + Engine gains an "execution_options" argument and + update_execution_options() method, which will apply to + all connections generated by this engine. + + .. change:: + :tags: mysql + :tickets: 1794 + + func.sysdate() emits "SYSDATE()", i.e. with the ending + parenthesis, on MySQL. + + .. change:: + :tags: sqlite + :tickets: 1812 + + Fixed concatenation of constraints when "PRIMARY KEY" + constraint gets moved to column level due to SQLite + AUTOINCREMENT keyword being rendered. + + .. change:: + :tags: oracle + :tickets: 1775 + + Added a check for cx_oracle versions lower than version 5, + in which case the incompatible "output type handler" won't + be used. This will impact decimal accuracy and some + unicode handling issues. + + .. change:: + :tags: oracle + :tickets: 1790 + + Fixed use_ansi=False mode, which was producing broken + WHERE clauses in pretty much all cases. + + .. change:: + :tags: oracle + :tickets: 1808 + + Re-established support for Oracle 8 with cx_oracle, + including that use_ansi is set to False automatically, + NVARCHAR2 and NCLOB are not rendered for Unicode, + "native unicode" check doesn't fail, cx_oracle + "native unicode" mode is disabled, VARCHAR() is emitted + with bytes count instead of char count. + + .. change:: + :tags: oracle + :tickets: 1670 + + oracle_xe 5 doesn't accept a Python unicode object in + its connect string in normal Python 2.x mode - so we coerce + to str() directly. non-ascii characters aren't supported + in connect strings here since we don't know what encoding + we could use. + + .. change:: + :tags: oracle + :tickets: 1815 + + FOR UPDATE is emitted in the syntactically correct position + when limit/offset is used, i.e. the ROWNUM subquery. + However, Oracle can't really handle FOR UPDATE with ORDER BY + or with subqueries, so its still not very usable, but at + least SQLA gets the SQL past the Oracle parser. + + .. change:: + :tags: firebird + :tickets: 1521 + + Added a label to the query used within has_table() and + has_sequence() to work with older versions of Firebird + that don't provide labels for result columns. + + .. change:: + :tags: firebird + :tickets: 1779 + + Added integer coercion to the "type_conv" attribute when + passed via query string, so that it is properly interpreted + by Kinterbasdb. + + .. change:: + :tags: firebird + :tickets: 1646 + + Added 'connection shutdown' to the list of exception strings + which indicate a dropped connection. + + .. change:: + :tags: sqlsoup + :tickets: 1783 + + the SqlSoup constructor accepts a `base` argument which specifies + the base class to use for mapped classes, the default being + `object`. + +.. changelog:: + :version: 0.6.0 + :released: Sun Apr 18 2010 + + .. change:: + :tags: orm + :tickets: 1742, 1081 + + Unit of work internals have been rewritten. Units of work + with large numbers of objects interdependent objects + can now be flushed without recursion overflows + as there is no longer reliance upon recursive calls. The number of internal structures now stays + constant for a particular session state, regardless of + how many relationships are present on mappings. The flow + of events now corresponds to a linear list of steps, + generated by the mappers and relationships based on actual + work to be done, filtered through a single topological sort + for correct ordering. Flush actions are assembled using + far fewer steps and less memory. + + .. change:: + :tags: orm + :tickets: + + Along with the UOW rewrite, this also removes an issue + introduced in 0.6beta3 regarding topological cycle detection + for units of work with long dependency cycles. We now use + an algorithm written by Guido (thanks Guido!). + + .. change:: + :tags: orm + :tickets: 1764 + + one-to-many relationships now maintain a list of positive + parent-child associations within the flush, preventing + previous parents marked as deleted from cascading a + delete or NULL foreign key set on those child objects, + despite the end-user not removing the child from the old + association. + + .. change:: + :tags: orm + :tickets: 1495 + + A collection lazy load will switch off default + eagerloading on the reverse many-to-one side, since + that loading is by definition unnecessary. + + .. change:: + :tags: orm + :tickets: + + Session.refresh() now does an equivalent expire() + on the given instance first, so that the "refresh-expire" + cascade is propagated. Previously, refresh() was + not affected in any way by the presence of "refresh-expire" + cascade. This is a change in behavior versus that + of 0.6beta2, where the "lockmode" flag passed to refresh() + would cause a version check to occur. Since the instance + is first expired, refresh() always upgrades the object + to the most recent version. + + .. change:: + :tags: orm + :tickets: 1754 + + The 'refresh-expire' cascade, when reaching a pending object, + will expunge the object if the cascade also includes + "delete-orphan", or will simply detach it otherwise. + + .. change:: + :tags: orm + :tickets: 1756 + + id(obj) is no longer used internally within topological.py, + as the sorting functions now require hashable objects + only. + + .. change:: + :tags: orm + :tickets: + + The ORM will set the docstring of all generated descriptors + to None by default. This can be overridden using 'doc' + (or if using Sphinx, attribute docstrings work too). + + .. change:: + :tags: orm + :tickets: + + Added kw argument 'doc' to all mapper property callables + as well as Column(). Will assemble the string 'doc' as + the '__doc__' attribute on the descriptor. + + .. change:: + :tags: orm + :tickets: 1761 + + Usage of version_id_col on a backend that supports + cursor.rowcount for execute() but not executemany() now works + when a delete is issued (already worked for saves, since those + don't use executemany()). For a backend that doesn't support + cursor.rowcount at all, a warning is emitted the same + as with saves. + + .. change:: + :tags: orm + :tickets: + + The ORM now short-term caches the "compiled" form of + insert() and update() constructs when flushing lists of + objects of all the same class, thereby avoiding redundant + compilation per individual INSERT/UPDATE within an + individual flush() call. + + .. change:: + :tags: orm + :tickets: + + internal getattr(), setattr(), getcommitted() methods + on ColumnProperty, CompositeProperty, RelationshipProperty + have been underscored (i.e. are private), signature has + changed. + + .. change:: + :tags: engines + :tickets: 1757 + + The C extension now also works with DBAPIs which use custom + sequences as row (and not only tuples). + + .. change:: + :tags: sql + :tickets: 1755 + + Restored some bind-labeling logic from 0.5 which ensures + that tables with column names that overlap another column + of the form "_" won't produce + errors if column._label is used as a bind name during + an UPDATE. Test coverage which wasn't present in 0.5 + has been added. + + .. change:: + :tags: sql + :tickets: 1729 + + somejoin.select(fold_equivalents=True) is no longer + deprecated, and will eventually be rolled into a more + comprehensive version of the feature for. + + .. change:: + :tags: sql + :tickets: 1759 + + the Numeric type raises an *enormous* warning when expected + to convert floats to Decimal from a DBAPI that returns floats. + This includes SQLite, Sybase, MS-SQL. + + .. change:: + :tags: sql + :tickets: + + Fixed an error in expression typing which caused an endless + loop for expressions with two NULL types. + + .. change:: + :tags: sql + :tickets: + + Fixed bug in execution_options() feature whereby the existing + Transaction and other state information from the parent + connection would not be propagated to the sub-connection. + + .. change:: + :tags: sql + :tickets: + + Added new 'compiled_cache' execution option. A dictionary + where Compiled objects will be cached when the Connection + compiles a clause expression into a dialect- and parameter- + specific Compiled object. It is the user's responsibility to + manage the size of this dictionary, which will have keys + corresponding to the dialect, clause element, the column + names within the VALUES or SET clause of an INSERT or UPDATE, + as well as the "batch" mode for an INSERT or UPDATE statement. + + .. change:: + :tags: sql + :tickets: 1769 + + Added get_pk_constraint() to reflection.Inspector, similar + to get_primary_keys() except returns a dict that includes the + name of the constraint, for supported backends (PG so far). + + .. change:: + :tags: sql + :tickets: 1771 + + Table.create() and Table.drop() no longer apply metadata- + level create/drop events. + + .. change:: + :tags: ext + :tickets: + + the compiler extension now allows @compiles decorators + on base classes that extend to child classes, @compiles + decorators on child classes that aren't broken by a + @compiles decorator on the base class. + + .. change:: + :tags: ext + :tickets: + + Declarative will raise an informative error message + if a non-mapped class attribute is referenced in the + string-based relationship() arguments. + + .. change:: + :tags: ext + :tickets: + + Further reworked the "mixin" logic in declarative to + additionally allow __mapper_args__ as a @classproperty + on a mixin, such as to dynamically assign polymorphic_identity. + + .. change:: + :tags: postgresql + :tickets: 1071 + + Postgresql now reflects sequence names associated with + SERIAL columns correctly, after the name of of the sequence + has been changed. Thanks to Kumar McMillan for the patch. + + .. change:: + :tags: postgresql + :tickets: + + Repaired missing import in psycopg2._PGNumeric type when + unknown numeric is received. + + .. change:: + :tags: postgresql + :tickets: + + psycopg2/pg8000 dialects now aware of REAL[], FLOAT[], + DOUBLE_PRECISION[], NUMERIC[] return types without + raising an exception. + + .. change:: + :tags: postgresql + :tickets: 1769 + + Postgresql reflects the name of primary key constraints, + if one exists. + + .. change:: + :tags: oracle + :tickets: + + Now using cx_oracle output converters so that the + DBAPI returns natively the kinds of values we prefer: + + .. change:: + :tags: oracle + :tickets: 1759 + + NUMBER values with positive precision + scale convert + to cx_oracle.STRING and then to Decimal. This + allows perfect precision for the Numeric type when + using cx_oracle. + + .. change:: + :tags: oracle + :tickets: + + STRING/FIXED_CHAR now convert to unicode natively. + SQLAlchemy's String types then don't need to + apply any kind of conversions. + + .. change:: + :tags: firebird + :tickets: + + The functionality of result.rowcount can be disabled on a + per-engine basis by setting 'enable_rowcount=False' + on create_engine(). Normally, cursor.rowcount is called + after any UPDATE or DELETE statement unconditionally, + because the cursor is then closed and Firebird requires + an open cursor in order to get a rowcount. This + call is slightly expensive however so it can be disabled. + To re-enable on a per-execution basis, the + 'enable_rowcount=True' execution option may be used. + + .. change:: + :tags: examples + :tickets: + + Updated attribute_shard.py example to use a more robust + method of searching a Query for binary expressions which + compare columns against literal values. + +.. changelog:: + :version: 0.6beta3 + :released: Sun Mar 28 2010 + + .. change:: + :tags: orm + :tickets: 1675 + + Major feature: Added new "subquery" loading capability to + relationship(). This is an eager loading option which + generates a second SELECT for each collection represented + in a query, across all parents at once. The query + re-issues the original end-user query wrapped in a subquery, + applies joins out to the target collection, and loads + all those collections fully in one result, similar to + "joined" eager loading but using all inner joins and not + re-fetching full parent rows repeatedly (as most DBAPIs seem + to do, even if columns are skipped). Subquery loading is + available at mapper config level using "lazy='subquery'" and + at the query options level using "subqueryload(props..)", + "subqueryload_all(props...)". + + .. change:: + :tags: orm + :tickets: + + To accomodate the fact that there are now two kinds of eager + loading available, the new names for eagerload() and + eagerload_all() are joinedload() and joinedload_all(). The + old names will remain as synonyms for the foreseeable future. + + .. change:: + :tags: orm + :tickets: + + The "lazy" flag on the relationship() function now accepts + a string argument for all kinds of loading: "select", "joined", + "subquery", "noload" and "dynamic", where the default is now + "select". The old values of True/ + False/None still retain their usual meanings and will remain + as synonyms for the foreseeable future. + + .. change:: + :tags: orm + :tickets: 921 + + Added with_hint() method to Query() construct. This calls + directly down to select().with_hint() and also accepts + entities as well as tables and aliases. See with_hint() in the + SQL section below. + + .. change:: + :tags: orm + :tickets: + + Fixed bug in Query whereby calling q.join(prop).from_self(...). + join(prop) would fail to render the second join outside the + subquery, when joining on the same criterion as was on the + inside. + + .. change:: + :tags: orm + :tickets: + + Fixed bug in Query whereby the usage of aliased() constructs + would fail if the underlying table (but not the actual alias) + were referenced inside the subquery generated by + q.from_self() or q.select_from(). + + .. change:: + :tags: orm + :tickets: + + Fixed bug which affected all eagerload() and similar options + such that "remote" eager loads, i.e. eagerloads off of a lazy + load such as query(A).options(eagerload(A.b, B.c)) + wouldn't eagerload anything, but using eagerload("b.c") would + work fine. + + .. change:: + :tags: orm + :tickets: + + Query gains an add_columns(*columns) method which is a multi- + version of add_column(col). add_column(col) is future + deprecated. + + .. change:: + :tags: orm + :tickets: + + Query.join() will detect if the end result will be + "FROM A JOIN A", and will raise an error if so. + + .. change:: + :tags: orm + :tickets: + + Query.join(Cls.propname, from_joinpoint=True) will check more + carefully that "Cls" is compatible with the current joinpoint, + and act the same way as Query.join("propname", from_joinpoint=True) + in that regard. + + .. change:: + :tags: sql + :tickets: 921 + + Added with_hint() method to select() construct. Specify + a table/alias, hint text, and optional dialect name, and + "hints" will be rendered in the appropriate place in the + statement. Works for Oracle, Sybase, MySQL. + + .. change:: + :tags: sql + :tickets: 1747 + + Fixed bug introduced in 0.6beta2 where column labels would + render inside of column expressions already assigned a label. + + .. change:: + :tags: postgresql + :tickets: 877 + + The psycopg2 dialect will log NOTICE messages via the + "sqlalchemy.dialects.postgresql" logger name. + + .. change:: + :tags: postgresql + :tickets: 997 + + the TIME and TIMESTAMP types are now availble from the + postgresql dialect directly, which add the PG-specific + argument 'precision' to both. 'precision' and + 'timezone' are correctly reflected for both TIME and + TIMEZONE types. + + .. change:: + :tags: mysql + :tickets: 1752 + + No longer guessing that TINYINT(1) should be BOOLEAN + when reflecting - TINYINT(1) is returned. Use Boolean/ + BOOLEAN in table definition to get boolean conversion + behavior. + + .. change:: + :tags: oracle + :tickets: 1744 + + The Oracle dialect will issue VARCHAR type definitions + using character counts, i.e. VARCHAR2(50 CHAR), so that + the column is sized in terms of characters and not bytes. + Column reflection of character types will also use + ALL_TAB_COLUMNS.CHAR_LENGTH instead of + ALL_TAB_COLUMNS.DATA_LENGTH. Both of these behaviors take + effect when the server version is 9 or higher - for + version 8, the old behaviors are used. + + .. change:: + :tags: declarative + :tickets: 1746 + + Using a mixin won't break if the mixin implements an + unpredictable __getattribute__(), i.e. Zope interfaces. + + .. change:: + :tags: declarative + :tickets: 1749 + + Using @classdecorator and similar on mixins to define + __tablename__, __table_args__, etc. now works if + the method references attributes on the ultimate + subclass. + + .. change:: + :tags: declarative + :tickets: 1751 + + relationships and columns with foreign keys aren't + allowed on declarative mixins, sorry. + + .. change:: + :tags: ext + :tickets: + + The sqlalchemy.orm.shard module now becomes an extension, + sqlalchemy.ext.horizontal_shard. The old import + works with a deprecation warning. + +.. changelog:: + :version: 0.6beta2 + :released: Sat Mar 20 2010 + + .. change:: + :tags: py3k + :tickets: + + Improved the installation/test setup regarding Python 3, + now that Distribute runs on Py3k. distribute_setup.py + is now included. See README.py3k for Python 3 installation/ + testing instructions. + + .. change:: + :tags: orm + :tickets: 1740 + + The official name for the relation() function is now + relationship(), to eliminate confusion over the relational + algebra term. relation() however will remain available + in equal capacity for the foreseeable future. + + .. change:: + :tags: orm + :tickets: 1692 + + Added "version_id_generator" argument to Mapper, this is a + callable that, given the current value of the "version_id_col", + returns the next version number. Can be used for alternate + versioning schemes such as uuid, timestamps. + + .. change:: + :tags: orm + :tickets: + + added "lockmode" kw argument to Session.refresh(), will + pass through the string value to Query the same as + in with_lockmode(), will also do version check for a + version_id_col-enabled mapping. + + .. change:: + :tags: orm + :tickets: 1188 + + Fixed bug whereby calling query(A).join(A.bs).add_entity(B) + in a joined inheritance scenario would double-add B as a + target and produce an invalid query. + + .. change:: + :tags: orm + :tickets: 1674 + + Fixed bug in session.rollback() which involved not removing + formerly "pending" objects from the session before + re-integrating "deleted" objects, typically occured with + natural primary keys. If there was a primary key conflict + between them, the attach of the deleted would fail + internally. The formerly "pending" objects are now expunged + first. + + .. change:: + :tags: orm + :tickets: 1719 + + Removed a lot of logging that nobody really cares about, + logging that remains will respond to live changes in the + log level. No significant overhead is added. + + .. change:: + :tags: orm + :tickets: + + Fixed bug in session.merge() which prevented dict-like + collections from merging. + + .. change:: + :tags: orm + :tickets: + + session.merge() works with relations that specifically + don't include "merge" in their cascade options - the target + is ignored completely. + + .. change:: + :tags: orm + :tickets: 1681 + + session.merge() will not expire existing scalar attributes + on an existing target if the target has a value for that + attribute, even if the incoming merged doesn't have + a value for the attribute. This prevents unnecessary loads + on existing items. Will still mark the attr as expired + if the destination doesn't have the attr, though, which + fulfills some contracts of deferred cols. + + .. change:: + :tags: orm + :tickets: 1680 + + The "allow_null_pks" flag is now called "allow_partial_pks", + defaults to True, acts like it did in 0.5 again. Except, + it also is implemented within merge() such that a SELECT + won't be issued for an incoming instance with partially + NULL primary key if the flag is False. + + .. change:: + :tags: orm + :tickets: 1737 + + Fixed bug in 0.6-reworked "many-to-one" optimizations + such that a many-to-one that is against a non-primary key + column on the remote table (i.e. foreign key against a + UNIQUE column) will pull the "old" value in from the + database during a change, since if it's in the session + we will need it for proper history/backref accounting, + and we can't pull from the local identity map on a + non-primary key column. + + .. change:: + :tags: orm + :tickets: 1731 + + fixed internal error which would occur if calling has() + or similar complex expression on a single-table inheritance + relation(). + + .. change:: + :tags: orm + :tickets: 1688 + + query.one() no longer applies LIMIT to the query, this to + ensure that it fully counts all object identities present + in the result, even in the case where joins may conceal + multiple identities for two or more rows. As a bonus, + one() can now also be called with a query that issued + from_statement() to start with since it no longer modifies + the query. + + .. change:: + :tags: orm + :tickets: 1727 + + query.get() now returns None if queried for an identifier + that is present in the identity map with a different class + than the one requested, i.e. when using polymorphic loading. + + .. change:: + :tags: orm + :tickets: 1706 + + A major fix in query.join(), when the "on" clause is an + attribute of an aliased() construct, but there is already + an existing join made out to a compatible target, query properly + joins to the right aliased() construct instead of sticking + onto the right side of the existing join. + + .. change:: + :tags: orm + :tickets: 1362 + + Slight improvement to the fix for to not issue + needless updates of the primary key column during a so-called + "row switch" operation, i.e. add + delete of two objects + with the same PK. + + .. change:: + :tags: orm + :tickets: + + Now uses sqlalchemy.orm.exc.DetachedInstanceError when an + attribute load or refresh action fails due to object + being detached from any Session. UnboundExecutionError + is specific to engines bound to sessions and statements. + + .. change:: + :tags: orm + :tickets: + + Query called in the context of an expression will render + disambiguating labels in all cases. Note that this does + not apply to the existing .statement and .subquery() + accessor/method, which still honors the .with_labels() + setting that defaults to False. + + .. change:: + :tags: orm + :tickets: 1676 + + Query.union() retains disambiguating labels within the + returned statement, thus avoiding various SQL composition + errors which can result from column name conflicts. + + .. change:: + :tags: orm + :tickets: + + Fixed bug in attribute history that inadvertently invoked + __eq__ on mapped instances. + + .. change:: + :tags: orm + :tickets: + + Some internal streamlining of object loading grants a + small speedup for large results, estimates are around + 10-15%. Gave the "state" internals a good solid + cleanup with less complexity, datamembers, + method calls, blank dictionary creates. + + .. change:: + :tags: orm + :tickets: 1689 + + Documentation clarification for query.delete() + + .. change:: + :tags: orm + :tickets: + + Fixed cascade bug in many-to-one relation() when attribute + was set to None, introduced in r6711 (cascade deleted + items into session during add()). + + .. change:: + :tags: orm + :tickets: 1736 + + Calling query.order_by() or query.distinct() before calling + query.select_from(), query.with_polymorphic(), or + query.from_statement() raises an exception now instead of + silently dropping those criterion. + + .. change:: + :tags: orm + :tickets: 1735 + + query.scalar() now raises an exception if more than one + row is returned. All other behavior remains the same. + + .. change:: + :tags: orm + :tickets: 1692 + + Fixed bug which caused "row switch" logic, that is an + INSERT and DELETE replaced by an UPDATE, to fail when + version_id_col was in use. + + .. change:: + :tags: sql + :tickets: 1714 + + join() will now simulate a NATURAL JOIN by default. Meaning, + if the left side is a join, it will attempt to join the right + side to the rightmost side of the left first, and not raise + any exceptions about ambiguous join conditions if successful + even if there are further join targets across the rest of + the left. + + .. change:: + :tags: sql + :tickets: + + The most common result processors conversion function were + moved to the new "processors" module. Dialect authors are + encouraged to use those functions whenever they correspond + to their needs instead of implementing custom ones. + + .. change:: + :tags: sql + :tickets: 1694, 1698 + + SchemaType and subclasses Boolean, Enum are now serializable, + including their ddl listener and other event callables. + + .. change:: + :tags: sql + :tickets: + + Some platforms will now interpret certain literal values + as non-bind parameters, rendered literally into the SQL + statement. This to support strict SQL-92 rules that are + enforced by some platforms including MS-SQL and Sybase. + In this model, bind parameters aren't allowed in the + columns clause of a SELECT, nor are certain ambiguous + expressions like "?=?". When this mode is enabled, the base + compiler will render the binds as inline literals, but only across + strings and numeric values. Other types such as dates + will raise an error, unless the dialect subclass defines + a literal rendering function for those. The bind parameter + must have an embedded literal value already or an error + is raised (i.e. won't work with straight bindparam('x')). + Dialects can also expand upon the areas where binds are not + accepted, such as within argument lists of functions + (which don't work on MS-SQL when native SQL binding is used). + + .. change:: + :tags: sql + :tickets: + + Added "unicode_errors" parameter to String, Unicode, etc. + Behaves like the 'errors' keyword argument to + the standard library's string.decode() functions. This flag + requires that `convert_unicode` is set to `"force"` - otherwise, + SQLAlchemy is not guaranteed to handle the task of unicode + conversion. Note that this flag adds significant performance + overhead to row-fetching operations for backends that already + return unicode objects natively (which most DBAPIs do). This + flag should only be used as an absolute last resort for reading + strings from a column with varied or corrupted encodings, + which only applies to databases that accept invalid encodings + in the first place (i.e. MySQL. *not* PG, Sqlite, etc.) + + .. change:: + :tags: sql + :tickets: + + Added math negation operator support, -x. + + .. change:: + :tags: sql + :tickets: + + FunctionElement subclasses are now directly executable the + same way any func.foo() construct is, with automatic + SELECT being applied when passed to execute(). + + .. change:: + :tags: sql + :tickets: + + The "type" and "bind" keyword arguments of a func.foo() + construct are now local to "func." constructs and are + not part of the FunctionElement base class, allowing + a "type" to be handled in a custom constructor or + class-level variable. + + .. change:: + :tags: sql + :tickets: + + Restored the keys() method to ResultProxy. + + .. change:: + :tags: sql + :tickets: 1647, 1683 + + The type/expression system now does a more complete job + of determining the return type from an expression + as well as the adaptation of the Python operator into + a SQL operator, based on the full left/right/operator + of the given expression. In particular + the date/time/interval system created for Postgresql + EXTRACT in has now been generalized into + the type system. The previous behavior which often + occured of an expression "column + literal" forcing + the type of "literal" to be the same as that of "column" + will now usually not occur - the type of + "literal" is first derived from the Python type of the + literal, assuming standard native Python types + date + types, before falling back to that of the known type + on the other side of the expression. If the + "fallback" type is compatible (i.e. CHAR from String), + the literal side will use that. TypeDecorator + types override this by default to coerce the "literal" + side unconditionally, which can be changed by implementing + the coerce_compared_value() method. Also part of. + + .. change:: + :tags: sql + :tickets: + + Made sqlalchemy.sql.expressions.Executable part of public + API, used for any expression construct that can be sent to + execute(). FunctionElement now inherits Executable so that + it gains execution_options(), which are also propagated + to the select() that's generated within execute(). + Executable in turn subclasses _Generative which marks + any ClauseElement that supports the @_generative + decorator - these may also become "public" for the benefit + of the compiler extension at some point. + + .. change:: + :tags: sql + :tickets: 1579 + + A change to the solution for - an end-user + defined bind parameter name that directly conflicts with + a column-named bind generated directly from the SET or + VALUES clause of an update/insert generates a compile error. + This reduces call counts and eliminates some cases where + undesirable name conflicts could still occur. + + .. change:: + :tags: sql + :tickets: 1705 + + Column() requires a type if it has no foreign keys (this is + not new). An error is now raised if a Column() has no type + and no foreign keys. + + .. change:: + :tags: sql + :tickets: 1717 + + the "scale" argument of the Numeric() type is honored when + coercing a returned floating point value into a string + on its way to Decimal - this allows accuracy to function + on SQLite, MySQL. + + .. change:: + :tags: sql + :tickets: + + the copy() method of Column now copies over uninitialized + "on table attach" events. Helps with the new declarative + "mixin" capability. + + .. change:: + :tags: engines + :tickets: + + Added an optional C extension to speed up the sql layer by + reimplementing RowProxy and the most common result processors. + The actual speedups will depend heavily on your DBAPI and + the mix of datatypes used in your tables, and can vary from + a 30% improvement to more than 200%. It also provides a modest + (~15-20%) indirect improvement to ORM speed for large queries. + Note that it is *not* built/installed by default. + See README for installation instructions. + + .. change:: + :tags: engines + :tickets: + + the execution sequence pulls all rowcount/last inserted ID + info from the cursor before commit() is called on the + DBAPI connection in an "autocommit" scenario. This helps + mxodbc with rowcount and is probably a good idea overall. + + .. change:: + :tags: engines + :tickets: 1719 + + Opened up logging a bit such that isEnabledFor() is called + more often, so that changes to the log level for engine/pool + will be reflected on next connect. This adds a small + amount of method call overhead. It's negligible and will make + life a lot easier for all those situations when logging + just happens to be configured after create_engine() is called. + + .. change:: + :tags: engines + :tickets: + + The assert_unicode flag is deprecated. SQLAlchemy will raise + a warning in all cases where it is asked to encode a non-unicode + Python string, as well as when a Unicode or UnicodeType type + is explicitly passed a bytestring. The String type will do nothing + for DBAPIs that already accept Python unicode objects. + + .. change:: + :tags: engines + :tickets: + + Bind parameters are sent as a tuple instead of a list. Some + backend drivers will not accept bind parameters as a list. + + .. change:: + :tags: engines + :tickets: + + threadlocal engine wasn't properly closing the connection + upon close() - fixed that. + + .. change:: + :tags: engines + :tickets: + + Transaction object doesn't rollback or commit if it isn't + "active", allows more accurate nesting of begin/rollback/commit. + + .. change:: + :tags: engines + :tickets: + + Python unicode objects as binds result in the Unicode type, + not string, thus eliminating a certain class of unicode errors + on drivers that don't support unicode binds. + + .. change:: + :tags: engines + :tickets: 1555 + + Added "logging_name" argument to create_engine(), Pool() constructor + as well as "pool_logging_name" argument to create_engine() which + filters down to that of Pool. Issues the given string name + within the "name" field of logging messages instead of the default + hex identifier string. + + .. change:: + :tags: engines + :tickets: + + The visit_pool() method of Dialect is removed, and replaced with + on_connect(). This method returns a callable which receives + the raw DBAPI connection after each one is created. The callable + is assembled into a first_connect/connect pool listener by the + connection strategy if non-None. Provides a simpler interface + for dialects. + + .. change:: + :tags: engines + :tickets: 1728 + + StaticPool now initializes, disposes and recreates without + opening a new connection - the connection is only opened when + first requested. dispose() also works on AssertionPool now. + + .. change:: + :tags: ticket: 1673, metadata + :tickets: + + Added the ability to strip schema information when using + "tometadata" by passing "schema=None" as an argument. If schema + is not specified then the table's schema is retained. + + .. change:: + :tags: declarative + :tickets: + + DeclarativeMeta exclusively uses cls.__dict__ (not dict_) + as the source of class information; _as_declarative exclusively + uses the dict_ passed to it as the source of class information + (which when using DeclarativeMeta is cls.__dict__). This should + in theory make it easier for custom metaclasses to modify + the state passed into _as_declarative. + + .. change:: + :tags: declarative + :tickets: 1707 + + declarative now accepts mixin classes directly, as a means + to provide common functional and column-based elements on + all subclasses, as well as a means to propagate a fixed + set of __table_args__ or __mapper_args__ to subclasses. + For custom combinations of __table_args__/__mapper_args__ from + an inherited mixin to local, descriptors can now be used. + New details are all up in the Declarative documentation. + Thanks to Chris Withers for putting up with my strife + on this. + + .. change:: + :tags: declarative + :tickets: 1393 + + the __mapper_args__ dict is copied when propagating to a subclass, + and is taken straight off the class __dict__ to avoid any + propagation from the parent. mapper inheritance already + propagates the things you want from the parent mapper. + + .. change:: + :tags: declarative + :tickets: 1732 + + An exception is raised when a single-table subclass specifies + a column that is already present on the base class. + + .. change:: + :tags: mysql + :tickets: 1655 + + Fixed reflection bug whereby when COLLATE was present, + nullable flag and server defaults would not be reflected. + + .. change:: + :tags: mysql + :tickets: + + Fixed reflection of TINYINT(1) "boolean" columns defined with + integer flags like UNSIGNED. + + .. change:: + :tags: mysql + :tickets: 1668 + + Further fixes for the mysql-connector dialect. + + .. change:: + :tags: mysql + :tickets: 1496 + + Composite PK table on InnoDB where the "autoincrement" column + isn't first will emit an explicit "KEY" phrase within + CREATE TABLE thereby avoiding errors. + + .. change:: + :tags: mysql + :tickets: 1634 + + Added reflection/create table support for a wide range + of MySQL keywords. + + .. change:: + :tags: mysql + :tickets: 1580 + + Fixed import error which could occur reflecting tables on + a Windows host + + .. change:: + :tags: mssql + :tickets: + + Re-established support for the pymssql dialect. + + .. change:: + :tags: mssql + :tickets: + + Various fixes for implicit returning, reflection, + etc. - the MS-SQL dialects aren't quite complete + in 0.6 yet (but are close) + + .. change:: + :tags: mssql + :tickets: 1710 + + Added basic support for mxODBC. + + .. change:: + :tags: mssql + :tickets: + + Removed the text_as_varchar option. + + .. change:: + :tags: oracle + :tickets: + + "out" parameters require a type that is supported by + cx_oracle. An error will be raised if no cx_oracle + type can be found. + + .. change:: + :tags: oracle + :tickets: + + Oracle 'DATE' now does not perform any result processing, + as the DATE type in Oracle stores full date+time objects, + that's what you'll get. Note that the generic types.Date + type *will* still call value.date() on incoming values, + however. When reflecting a table, the reflected type + will be 'DATE'. + + .. change:: + :tags: oracle + :tickets: 1670 + + Added preliminary support for Oracle's WITH_UNICODE + mode. At the very least this establishes initial + support for cx_Oracle with Python 3. When WITH_UNICODE + mode is used in Python 2.xx, a large and scary warning + is emitted asking that the user seriously consider + the usage of this difficult mode of operation. + + .. change:: + :tags: oracle + :tickets: 1712 + + The except_() method now renders as MINUS on Oracle, + which is more or less equivalent on that platform. + + .. change:: + :tags: oracle + :tickets: 651 + + Added support for rendering and reflecting + TIMESTAMP WITH TIME ZONE, i.e. TIMESTAMP(timezone=True). + + .. change:: + :tags: oracle + :tickets: + + Oracle INTERVAL type can now be reflected. + + .. change:: + :tags: sqlite + :tickets: 1685 + + Added "native_datetime=True" flag to create_engine(). + This will cause the DATE and TIMESTAMP types to skip + all bind parameter and result row processing, under + the assumption that PARSE_DECLTYPES has been enabled + on the connection. Note that this is not entirely + compatible with the "func.current_date()", which + will be returned as a string. + + .. change:: + :tags: sybase + :tickets: + + Implemented a preliminary working dialect for Sybase, + with sub-implementations for Python-Sybase as well + as Pyodbc. Handles table + creates/drops and basic round trip functionality. + Does not yet include reflection or comprehensive + support of unicode/special expressions/etc. + + .. change:: + :tags: examples + :tickets: + + Changed the beaker cache example a bit to have a separate + RelationCache option for lazyload caching. This object + does a lookup among any number of potential attributes + more efficiently by grouping several into a common structure. + Both FromCache and RelationCache are simpler individually. + + .. change:: + :tags: documentation + :tickets: 1700 + + Major cleanup work in the docs to link class, function, and + method names into the API docs. + +.. changelog:: + :version: 0.6beta1 + :released: Wed Feb 03 2010 + + .. change:: + :tags: release, major + :tickets: + + For the full set of feature descriptions, see + http://www.sqlalchemy.org/trac/wiki/06Migration . + This document is a work in progress. + + .. change:: + :tags: release, major + :tickets: + + All bug fixes and feature enhancements from the most + recent 0.5 version and below are also included within 0.6. + + .. change:: + :tags: release, major + :tickets: + + Platforms targeted now include Python 2.4/2.5/2.6, Python + 3.1, Jython2.5. + + .. change:: + :tags: orm + :tickets: + + Changes to query.update() and query.delete(): + - the 'expire' option on query.update() has been renamed to + 'fetch', thus matching that of query.delete(). + 'expire' is deprecated and issues a warning. + + - query.update() and query.delete() both default to + 'evaluate' for the synchronize strategy. + + - the 'synchronize' strategy for update() and delete() + raises an error on failure. There is no implicit fallback + onto "fetch". Failure of evaluation is based on the + structure of criteria, so success/failure is deterministic + based on code structure. + + .. change:: + :tags: orm + :tickets: 1186, 1492, 1544 + + Enhancements on many-to-one relations: + - many-to-one relations now fire off a lazyload in fewer + cases, including in most cases will not fetch the "old" + value when a new one is replaced. + + - many-to-one relation to a joined-table subclass now uses + get() for a simple load (known as the "use_get" + condition), i.e. Related->Sub(Base), without the need to + redefine the primaryjoin condition in terms of the base + table. + + - specifying a foreign key with a declarative column, i.e. + ForeignKey(MyRelatedClass.id) doesn't break the "use_get" + condition from taking place + + - relation(), eagerload(), and eagerload_all() now feature + an option called "innerjoin". Specify `True` or `False` to + control whether an eager join is constructed as an INNER + or OUTER join. Default is `False` as always. The mapper + options will override whichever setting is specified on + relation(). Should generally be set for many-to-one, not + nullable foreign key relations to allow improved join + performance. + + - the behavior of eagerloading such that the main query is + wrapped in a subquery when LIMIT/OFFSET are present now + makes an exception for the case when all eager loads are + many-to-one joins. In those cases, the eager joins are + against the parent table directly along with the + limit/offset without the extra overhead of a subquery, + since a many-to-one join does not add rows to the result. + + .. change:: + :tags: orm + :tickets: + + Enhancements / Changes on Session.merge(): + + .. change:: + :tags: orm + :tickets: + + the "dont_load=True" flag on Session.merge() is deprecated + and is now "load=False". + + .. change:: + :tags: orm + :tickets: + + Session.merge() is performance optimized, using half the + call counts for "load=False" mode compared to 0.5 and + significantly fewer SQL queries in the case of collections + for "load=True" mode. + + .. change:: + :tags: orm + :tickets: + + merge() will not issue a needless merge of attributes if the + given instance is the same instance which is already present. + + .. change:: + :tags: orm + :tickets: + + merge() now also merges the "options" associated with a given + state, i.e. those passed through query.options() which follow + along with an instance, such as options to eagerly- or + lazyily- load various attributes. This is essential for + the construction of highly integrated caching schemes. This + is a subtle behavioral change vs. 0.5. + + .. change:: + :tags: orm + :tickets: + + A bug was fixed regarding the serialization of the "loader + path" present on an instance's state, which is also necessary + when combining the usage of merge() with serialized state + and associated options that should be preserved. + + .. change:: + :tags: orm + :tickets: + + The all new merge() is showcased in a new comprehensive + example of how to integrate Beaker with SQLAlchemy. See + the notes in the "examples" note below. + + .. change:: + :tags: orm + :tickets: 1362 + + Primary key values can now be changed on a joined-table inheritance + object, and ON UPDATE CASCADE will be taken into account when + the flush happens. Set the new "passive_updates" flag to False + on mapper() when using SQLite or MySQL/MyISAM. + + .. change:: + :tags: orm + :tickets: 1671 + + flush() now detects when a primary key column was updated by + an ON UPDATE CASCADE operation from another primary key, and + can then locate the row for a subsequent UPDATE on the new PK + value. This occurs when a relation() is there to establish + the relationship as well as passive_updates=True. + + .. change:: + :tags: orm + :tickets: + + the "save-update" cascade will now cascade the pending *removed* + values from a scalar or collection attribute into the new session + during an add() operation. This so that the flush() operation + will also delete or modify rows of those disconnected items. + + .. change:: + :tags: orm + :tickets: 1531 + + Using a "dynamic" loader with a "secondary" table now produces + a query where the "secondary" table is *not* aliased. This + allows the secondary Table object to be used in the "order_by" + attribute of the relation(), and also allows it to be used + in filter criterion against the dynamic relation. + + .. change:: + :tags: orm + :tickets: 1643 + + relation() with uselist=False will emit a warning when + an eager or lazy load locates more than one valid value for + the row. This may be due to primaryjoin/secondaryjoin + conditions which aren't appropriate for an eager LEFT OUTER + JOIN or for other conditions. + + .. change:: + :tags: orm + :tickets: 1633 + + an explicit check occurs when a synonym() is used with + map_column=True, when a ColumnProperty (deferred or otherwise) + exists separately in the properties dictionary sent to mapper + with the same keyname. Instead of silently replacing + the existing property (and possible options on that property), + an error is raised. + + .. change:: + :tags: orm + :tickets: + + a "dynamic" loader sets up its query criterion at construction + time so that the actual query is returned from non-cloning + accessors like "statement". + + .. change:: + :tags: orm + :tickets: + + the "named tuple" objects returned when iterating a + Query() are now pickleable. + + .. change:: + :tags: orm + :tickets: 1542 + + mapping to a select() construct now requires that you + make an alias() out of it distinctly. This to eliminate + confusion over such issues as + + .. change:: + :tags: orm + :tickets: 1537 + + query.join() has been reworked to provide more consistent + behavior and more flexibility (includes) + + .. change:: + :tags: orm + :tickets: + + query.select_from() accepts multiple clauses to produce + multiple comma separated entries within the FROM clause. + Useful when selecting from multiple-homed join() clauses. + + .. change:: + :tags: orm + :tickets: + + query.select_from() also accepts mapped classes, aliased() + constructs, and mappers as arguments. In particular this + helps when querying from multiple joined-table classes to ensure + the full join gets rendered. + + .. change:: + :tags: orm + :tickets: 1135 + + query.get() can be used with a mapping to an outer join + where one or more of the primary key values are None. + + .. change:: + :tags: orm + :tickets: 1568 + + query.from_self(), query.union(), others which do a + "SELECT * from (SELECT...)" type of nesting will do + a better job translating column expressions within the subquery + to the columns clause of the outer query. This is + potentially backwards incompatible with 0.5, in that this + may break queries with literal expressions that do not have labels + applied (i.e. literal('foo'), etc.) + + .. change:: + :tags: orm + :tickets: 1622 + + relation primaryjoin and secondaryjoin now check that they + are column-expressions, not just clause elements. this prohibits + things like FROM expressions being placed there directly. + + .. change:: + :tags: orm + :tickets: 1415 + + `expression.null()` is fully understood the same way + None is when comparing an object/collection-referencing + attribute within query.filter(), filter_by(), etc. + + .. change:: + :tags: orm + :tickets: 1052 + + added "make_transient()" helper function which transforms a + persistent/ detached instance into a transient one (i.e. + deletes the instance_key and removes from any session.) + + .. change:: + :tags: orm + :tickets: 1339 + + the allow_null_pks flag on mapper() is deprecated, and + the feature is turned "on" by default. This means that + a row which has a non-null value for any of its primary key + columns will be considered an identity. The need for this + scenario typically only occurs when mapping to an outer join. + + .. change:: + :tags: orm + :tickets: + + the mechanics of "backref" have been fully merged into the + finer grained "back_populates" system, and take place entirely + within the _generate_backref() method of RelationProperty. This + makes the initialization procedure of RelationProperty + simpler and allows easier propagation of settings (such as from + subclasses of RelationProperty) into the reverse reference. + The internal BackRef() is gone and backref() returns a plain + tuple that is understood by RelationProperty. + + .. change:: + :tags: orm + :tickets: 1569 + + The version_id_col feature on mapper() will raise a warning when + used with dialects that don't support "rowcount" adequately. + + .. change:: + :tags: orm + :tickets: + + added "execution_options()" to Query, to so options can be + passed to the resulting statement. Currently only + Select-statements have these options, and the only option + used is "stream_results", and the only dialect which knows + "stream_results" is psycopg2. + + .. change:: + :tags: orm + :tickets: + + Query.yield_per() will set the "stream_results" statement + option automatically. + + .. change:: + :tags: orm + :tickets: + + Deprecated or removed: + * 'allow_null_pks' flag on mapper() is deprecated. It does + nothing now and the setting is "on" in all cases. + * 'transactional' flag on sessionmaker() and others is + removed. Use 'autocommit=True' to indicate 'transactional=False'. + * 'polymorphic_fetch' argument on mapper() is removed. + Loading can be controlled using the 'with_polymorphic' + option. + * 'select_table' argument on mapper() is removed. Use + 'with_polymorphic=("*", )' for this + functionality. + * 'proxy' argument on synonym() is removed. This flag + did nothing throughout 0.5, as the "proxy generation" + behavior is now automatic. + * Passing a single list of elements to eagerload(), + eagerload_all(), contains_eager(), lazyload(), + defer(), and undefer() instead of multiple positional + *args is deprecated. + * Passing a single list of elements to query.order_by(), + query.group_by(), query.join(), or query.outerjoin() + instead of multiple positional *args is deprecated. + * query.iterate_instances() is removed. Use query.instances(). + * Query.query_from_parent() is removed. Use the + sqlalchemy.orm.with_parent() function to produce a + "parent" clause, or alternatively query.with_parent(). + * query._from_self() is removed, use query.from_self() + instead. + * the "comparator" argument to composite() is removed. + Use "comparator_factory". + * RelationProperty._get_join() is removed. + * the 'echo_uow' flag on Session is removed. Use + logging on the "sqlalchemy.orm.unitofwork" name. + * session.clear() is removed. use session.expunge_all(). + * session.save(), session.update(), session.save_or_update() + are removed. Use session.add() and session.add_all(). + * the "objects" flag on session.flush() remains deprecated. + * the "dont_load=True" flag on session.merge() is deprecated + in favor of "load=False". + * ScopedSession.mapper remains deprecated. See the + usage recipe at + http://www.sqlalchemy.org/trac/wiki/UsageRecipes/SessionAwareMapper + * passing an InstanceState (internal SQLAlchemy state object) to + attributes.init_collection() or attributes.get_history() is + deprecated. These functions are public API and normally + expect a regular mapped object instance. + * the 'engine' parameter to declarative_base() is removed. + Use the 'bind' keyword argument. + + .. change:: + :tags: sql + :tickets: + + the "autocommit" flag on select() and text() as well + as select().autocommit() are deprecated - now call + .execution_options(autocommit=True) on either of those + constructs, also available directly on Connection and orm.Query. + + .. change:: + :tags: sql + :tickets: + + the autoincrement flag on column now indicates the column + which should be linked to cursor.lastrowid, if that method + is used. See the API docs for details. + + .. change:: + :tags: sql + :tickets: 1566 + + an executemany() now requires that all bound parameter + sets require that all keys are present which are + present in the first bound parameter set. The structure + and behavior of an insert/update statement is very much + determined by the first parameter set, including which + defaults are going to fire off, and a minimum of + guesswork is performed with all the rest so that performance + is not impacted. For this reason defaults would otherwise + silently "fail" for missing parameters, so this is now guarded + against. + + .. change:: + :tags: sql + :tickets: + + returning() support is native to insert(), update(), + delete(). Implementations of varying levels of + functionality exist for Postgresql, Firebird, MSSQL and + Oracle. returning() can be called explicitly with column + expressions which are then returned in the resultset, + usually via fetchone() or first(). + + insert() constructs will also use RETURNING implicitly to + get newly generated primary key values, if the database + version in use supports it (a version number check is + performed). This occurs if no end-user returning() was + specified. + + .. change:: + :tags: sql + :tickets: 1665 + + union(), intersect(), except() and other "compound" types + of statements have more consistent behavior w.r.t. + parenthesizing. Each compound element embedded within + another will now be grouped with parenthesis - previously, + the first compound element in the list would not be grouped, + as SQLite doesn't like a statement to start with + parenthesis. However, Postgresql in particular has + precedence rules regarding INTERSECT, and it is + more consistent for parenthesis to be applied equally + to all sub-elements. So now, the workaround for SQLite + is also what the workaround for PG was previously - + when nesting compound elements, the first one usually needs + ".alias().select()" called on it to wrap it inside + of a subquery. + + .. change:: + :tags: sql + :tickets: 1579 + + insert() and update() constructs can now embed bindparam() + objects using names that match the keys of columns. These + bind parameters will circumvent the usual route to those + keys showing up in the VALUES or SET clause of the generated + SQL. + + .. change:: + :tags: sql + :tickets: 1524 + + the Binary type now returns data as a Python string + (or a "bytes" type in Python 3), instead of the built- + in "buffer" type. This allows symmetric round trips + of binary data. + + .. change:: + :tags: sql + :tickets: + + Added a tuple_() construct, allows sets of expressions + to be compared to another set, typically with IN against + composite primary keys or similar. Also accepts an + IN with multiple columns. The "scalar select can + have only one column" error message is removed - will + rely upon the database to report problems with + col mismatch. + + .. change:: + :tags: sql + :tickets: + + User-defined "default" and "onupdate" callables which + accept a context should now call upon + "context.current_parameters" to get at the dictionary + of bind parameters currently being processed. This + dict is available in the same way regardless of + single-execute or executemany-style statement execution. + + .. change:: + :tags: sql + :tickets: 1428 + + multi-part schema names, i.e. with dots such as + "dbo.master", are now rendered in select() labels + with underscores for dots, i.e. "dbo_master_table_column". + This is a "friendly" label that behaves better + in result sets. + + .. change:: + :tags: sql + :tickets: + + removed needless "counter" behavior with select() + labelnames that match a column name in the table, + i.e. generates "tablename_id" for "id", instead of + "tablename_id_1" in an attempt to avoid naming + conflicts, when the table has a column actually + named "tablename_id" - this is because + the labeling logic is always applied to all columns + so a naming conflict will never occur. + + .. change:: + :tags: sql + :tickets: 1628 + + calling expr.in_([]), i.e. with an empty list, emits a warning + before issuing the usual "expr != expr" clause. The + "expr != expr" can be very expensive, and it's preferred + that the user not issue in_() if the list is empty, + instead simply not querying, or modifying the criterion + as appropriate for more complex situations. + + .. change:: + :tags: sql + :tickets: + + Added "execution_options()" to select()/text(), which set the + default options for the Connection. See the note in "engines". + + .. change:: + :tags: sql + :tickets: 1131 + + Deprecated or removed: + * "scalar" flag on select() is removed, use + select.as_scalar(). + * "shortname" attribute on bindparam() is removed. + * postgres_returning, firebird_returning flags on + insert(), update(), delete() are deprecated, use + the new returning() method. + * fold_equivalents flag on join is deprecated (will remain + until is implemented) + + .. change:: + :tags: engines + :tickets: 443 + + transaction isolation level may be specified with + create_engine(... isolation_level="..."); available on + postgresql and sqlite. + + .. change:: + :tags: engines + :tickets: + + Connection has execution_options(), generative method + which accepts keywords that affect how the statement + is executed w.r.t. the DBAPI. Currently supports + "stream_results", causes psycopg2 to use a server + side cursor for that statement, as well as + "autocommit", which is the new location for the "autocommit" + option from select() and text(). select() and + text() also have .execution_options() as well as + ORM Query(). + + .. change:: + :tags: engines + :tickets: 1630 + + fixed the import for entrypoint-driven dialects to + not rely upon silly tb_info trick to determine import + error status. + + .. change:: + :tags: engines + :tickets: + + added first() method to ResultProxy, returns first row and + closes result set immediately. + + .. change:: + :tags: engines + :tickets: + + RowProxy objects are now pickleable, i.e. the object returned + by result.fetchone(), result.fetchall() etc. + + .. change:: + :tags: engines + :tickets: + + RowProxy no longer has a close() method, as the row no longer + maintains a reference to the parent. Call close() on + the parent ResultProxy instead, or use autoclose. + + .. change:: + :tags: engines + :tickets: 1586 + + ResultProxy internals have been overhauled to greatly reduce + method call counts when fetching columns. Can provide a large + speed improvement (up to more than 100%) when fetching large + result sets. The improvement is larger when fetching columns + that have no type-level processing applied and when using + results as tuples (instead of as dictionaries). Many + thanks to Elixir's Gaëtan de Menten for this dramatic + improvement ! + + .. change:: + :tags: engines + :tickets: + + Databases which rely upon postfetch of "last inserted id" + to get at a generated sequence value (i.e. MySQL, MS-SQL) + now work correctly when there is a composite primary key + where the "autoincrement" column is not the first primary + key column in the table. + + .. change:: + :tags: engines + :tickets: + + the last_inserted_ids() method has been renamed to the + descriptor "inserted_primary_key". + + .. change:: + :tags: engines + :tickets: 1554 + + setting echo=False on create_engine() now sets the loglevel + to WARN instead of NOTSET. This so that logging can be + disabled for a particular engine even if logging + for "sqlalchemy.engine" is enabled overall. Note that the + default setting of "echo" is `None`. + + .. change:: + :tags: engines + :tickets: + + ConnectionProxy now has wrapper methods for all transaction + lifecycle events, including begin(), rollback(), commit() + begin_nested(), begin_prepared(), prepare(), release_savepoint(), + etc. + + .. change:: + :tags: engines + :tickets: + + Connection pool logging now uses both INFO and DEBUG + log levels for logging. INFO is for major events such + as invalidated connections, DEBUG for all the acquire/return + logging. `echo_pool` can be False, None, True or "debug" + the same way as `echo` works. + + .. change:: + :tags: engines + :tickets: 1621 + + All pyodbc-dialects now support extra pyodbc-specific + kw arguments 'ansi', 'unicode_results', 'autocommit'. + + .. change:: + :tags: engines + :tickets: + + the "threadlocal" engine has been rewritten and simplified + and now supports SAVEPOINT operations. + + .. change:: + :tags: engines + :tickets: + + deprecated or removed + * result.last_inserted_ids() is deprecated. Use + result.inserted_primary_key + * dialect.get_default_schema_name(connection) is now + public via dialect.default_schema_name. + * the "connection" argument from engine.transaction() and + engine.run_callable() is removed - Connection itself + now has those methods. All four methods accept + *args and **kwargs which are passed to the given callable, + as well as the operating connection. + + .. change:: + :tags: schema + :tickets: 1541 + + the `__contains__()` method of `MetaData` now accepts + strings or `Table` objects as arguments. If given + a `Table`, the argument is converted to `table.key` first, + i.e. "[schemaname.]" + + .. change:: + :tags: schema + :tickets: + + deprecated MetaData.connect() and + ThreadLocalMetaData.connect() have been removed - send + the "bind" attribute to bind a metadata. + + .. change:: + :tags: schema + :tickets: + + deprecated metadata.table_iterator() method removed (use + sorted_tables) + + .. change:: + :tags: schema + :tickets: + + deprecated PassiveDefault - use DefaultClause. + + .. change:: + :tags: schema + :tickets: + + the "metadata" argument is removed from DefaultGenerator + and subclasses, but remains locally present on Sequence, + which is a standalone construct in DDL. + + .. change:: + :tags: schema + :tickets: + + Removed public mutability from Index and Constraint + objects: + - ForeignKeyConstraint.append_element() + - Index.append_column() + - UniqueConstraint.append_column() + - PrimaryKeyConstraint.add() + - PrimaryKeyConstraint.remove() + These should be constructed declaratively (i.e. in one + construction). + + .. change:: + :tags: schema + :tickets: 1545 + + The "start" and "increment" attributes on Sequence now + generate "START WITH" and "INCREMENT BY" by default, + on Oracle and Postgresql. Firebird doesn't support + these keywords right now. + + .. change:: + :tags: schema + :tickets: + + UniqueConstraint, Index, PrimaryKeyConstraint all accept + lists of column names or column objects as arguments. + + .. change:: + :tags: schema + :tickets: + + Other removed things: + - Table.key (no idea what this was for) + - Table.primary_key is not assignable - use + table.append_constraint(PrimaryKeyConstraint(...)) + - Column.bind (get via column.table.bind) + - Column.metadata (get via column.table.metadata) + - Column.sequence (use column.default) + - ForeignKey(constraint=some_parent) (is now private _constraint) + + .. change:: + :tags: schema + :tickets: + + The use_alter flag on ForeignKey is now a shortcut option + for operations that can be hand-constructed using the + DDL() event system. A side effect of this refactor is + that ForeignKeyConstraint objects with use_alter=True + will *not* be emitted on SQLite, which does not support + ALTER for foreign keys. + + .. change:: + :tags: schema + :tickets: 1605 + + ForeignKey and ForeignKeyConstraint objects now correctly + copy() all their public keyword arguments. + + .. change:: + :tags: reflection/inspection + :tickets: + + Table reflection has been expanded and generalized into + a new API called "sqlalchemy.engine.reflection.Inspector". + The Inspector object provides fine-grained information about + a wide variety of schema information, with room for expansion, + including table names, column names, view definitions, sequences, + indexes, etc. + + .. change:: + :tags: reflection/inspection + :tickets: + + Views are now reflectable as ordinary Table objects. The same + Table constructor is used, with the caveat that "effective" + primary and foreign key constraints aren't part of the reflection + results; these have to be specified explicitly if desired. + + .. change:: + :tags: reflection/inspection + :tickets: + + The existing autoload=True system now uses Inspector underneath + so that each dialect need only return "raw" data about tables + and other objects - Inspector is the single place that information + is compiled into Table objects so that consistency is at a maximum. + + .. change:: + :tags: ddl + :tickets: + + the DDL system has been greatly expanded. the DDL() class + now extends the more generic DDLElement(), which forms the basis + of many new constructs: + + - CreateTable() + - DropTable() + - AddConstraint() + - DropConstraint() + - CreateIndex() + - DropIndex() + - CreateSequence() + - DropSequence() + + These support "on" and "execute-at()" just like plain DDL() + does. User-defined DDLElement subclasses can be created and + linked to a compiler using the sqlalchemy.ext.compiler extension. + + .. change:: + :tags: ddl + :tickets: + + The signature of the "on" callable passed to DDL() and + DDLElement() is revised as follows: + + "ddl" - the DDLElement object itself. + "event" - the string event name. + "target" - previously "schema_item", the Table or + MetaData object triggering the event. + "connection" - the Connection object in use for the operation. + **kw - keyword arguments. In the case of MetaData before/after + create/drop, the list of Table objects for which + CREATE/DROP DDL is to be issued is passed as the kw + argument "tables". This is necessary for metadata-level + DDL that is dependent on the presence of specific tables. + + - the "schema_item" attribute of DDL has been renamed to + "target". + + .. change:: + :tags: dialect, refactor + :tickets: + + Dialect modules are now broken into database dialects + plus DBAPI implementations. Connect URLs are now + preferred to be specified using dialect+driver://..., + i.e. "mysql+mysqldb://scott:tiger@localhost/test". See + the 0.6 documentation for examples. + + .. change:: + :tags: dialect, refactor + :tickets: + + the setuptools entrypoint for external dialects is now + called "sqlalchemy.dialects". + + .. change:: + :tags: dialect, refactor + :tickets: + + the "owner" keyword argument is removed from Table. Use + "schema" to represent any namespaces to be prepended to + the table name. + + .. change:: + :tags: dialect, refactor + :tickets: + + server_version_info becomes a static attribute. + + .. change:: + :tags: dialect, refactor + :tickets: + + dialects receive an initialize() event on initial + connection to determine connection properties. + + .. change:: + :tags: dialect, refactor + :tickets: + + dialects receive a visit_pool event have an opportunity + to establish pool listeners. + + .. change:: + :tags: dialect, refactor + :tickets: + + cached TypeEngine classes are cached per-dialect class + instead of per-dialect. + + .. change:: + :tags: dialect, refactor + :tickets: + + new UserDefinedType should be used as a base class for + new types, which preserves the 0.5 behavior of + get_col_spec(). + + .. change:: + :tags: dialect, refactor + :tickets: + + The result_processor() method of all type classes now + accepts a second argument "coltype", which is the DBAPI + type argument from cursor.description. This argument + can help some types decide on the most efficient processing + of result values. + + .. change:: + :tags: dialect, refactor + :tickets: + + Deprecated Dialect.get_params() removed. + + .. change:: + :tags: dialect, refactor + :tickets: + + Dialect.get_rowcount() has been renamed to a descriptor + "rowcount", and calls cursor.rowcount directly. Dialects + which need to hardwire a rowcount in for certain calls + should override the method to provide different behavior. + + .. change:: + :tags: dialect, refactor + :tickets: 1566 + + DefaultRunner and subclasses have been removed. The job + of this object has been simplified and moved into + ExecutionContext. Dialects which support sequences should + add a `fire_sequence()` method to their execution context + implementation. + + .. change:: + :tags: dialect, refactor + :tickets: + + Functions and operators generated by the compiler now use + (almost) regular dispatch functions of the form + "visit_" and "visit__fn" to provide + customed processing. This replaces the need to copy the + "functions" and "operators" dictionaries in compiler + subclasses with straightforward visitor methods, and also + allows compiler subclasses complete control over + rendering, as the full _Function or _BinaryExpression + object is passed in. + + .. change:: + :tags: postgresql + :tickets: + + New dialects: pg8000, zxjdbc, and pypostgresql + on py3k. + + .. change:: + :tags: postgresql + :tickets: + + The "postgres" dialect is now named "postgresql" ! + Connection strings look like: + + postgresql://scott:tiger@localhost/test + postgresql+pg8000://scott:tiger@localhost/test + + The "postgres" name remains for backwards compatiblity + in the following ways: + + - There is a "postgres.py" dummy dialect which + allows old URLs to work, i.e. + postgres://scott:tiger@localhost/test + + - The "postgres" name can be imported from the old + "databases" module, i.e. "from + sqlalchemy.databases import postgres" as well as + "dialects", "from sqlalchemy.dialects.postgres + import base as pg", will send a deprecation + warning. + + - Special expression arguments are now named + "postgresql_returning" and "postgresql_where", but + the older "postgres_returning" and + "postgres_where" names still work with a + deprecation warning. + + .. change:: + :tags: postgresql + :tickets: + + "postgresql_where" now accepts SQL expressions which + can also include literals, which will be quoted as needed. + + .. change:: + :tags: postgresql + :tickets: + + The psycopg2 dialect now uses psycopg2's "unicode extension" + on all new connections, which allows all String/Text/etc. + types to skip the need to post-process bytestrings into + unicode (an expensive step due to its volume). Other + dialects which return unicode natively (pg8000, zxjdbc) + also skip unicode post-processing. + + .. change:: + :tags: postgresql + :tickets: 1511 + + Added new ENUM type, which exists as a schema-level + construct and extends the generic Enum type. Automatically + associates itself with tables and their parent metadata + to issue the appropriate CREATE TYPE/DROP TYPE + commands as needed, supports unicode labels, supports + reflection. + + .. change:: + :tags: postgresql + :tickets: + + INTERVAL supports an optional "precision" argument + corresponding to the argument that PG accepts. + + .. change:: + :tags: postgresql + :tickets: + + using new dialect.initialize() feature to set up + version-dependent behavior. + + .. change:: + :tags: postgresql + :tickets: 1279 + + somewhat better support for % signs in table/column names; + psycopg2 can't handle a bind parameter name of + %(foobar)s however and SQLA doesn't want to add overhead + just to treat that one non-existent use case. + + .. change:: + :tags: postgresql + :tickets: 1516 + + Inserting NULL into a primary key + foreign key column + will allow the "not null constraint" error to raise, + not an attempt to execute a nonexistent "col_id_seq" + sequence. + + .. change:: + :tags: postgresql + :tickets: + + autoincrement SELECT statements, i.e. those which + select from a procedure that modifies rows, now work + with server-side cursor mode (the named cursor isn't + used for such statements.) + + .. change:: + :tags: postgresql + :tickets: 1636 + + postgresql dialect can properly detect pg "devel" version + strings, i.e. "8.5devel" + + .. change:: + :tags: postgresql + :tickets: 1619 + + The psycopg2 now respects the statement option + "stream_results". This option overrides the connection setting + "server_side_cursors". If true, server side cursors will be + used for the statement. If false, they will not be used, even + if "server_side_cursors" is true on the + connection. + + .. change:: + :tags: mysql + :tickets: + + New dialects: oursql, a new native dialect, + MySQL Connector/Python, a native Python port of MySQLdb, + and of course zxjdbc on Jython. + + .. change:: + :tags: mysql + :tickets: + + VARCHAR/NVARCHAR will not render without a length, raises + an error before passing to MySQL. Doesn't impact + CAST since VARCHAR is not allowed in MySQL CAST anyway, + the dialect renders CHAR/NCHAR in those cases. + + .. change:: + :tags: mysql + :tickets: + + all the _detect_XXX() functions now run once underneath + dialect.initialize() + + .. change:: + :tags: mysql + :tickets: 1279 + + somewhat better support for % signs in table/column names; + MySQLdb can't handle % signs in SQL when executemany() is used, + and SQLA doesn't want to add overhead just to treat that one + non-existent use case. + + .. change:: + :tags: mysql + :tickets: + + the BINARY and MSBinary types now generate "BINARY" in all + cases. Omitting the "length" parameter will generate + "BINARY" with no length. Use BLOB to generate an unlengthed + binary column. + + .. change:: + :tags: mysql + :tickets: + + the "quoting='quoted'" argument to MSEnum/ENUM is deprecated. + It's best to rely upon the automatic quoting. + + .. change:: + :tags: mysql + :tickets: + + ENUM now subclasses the new generic Enum type, and also handles + unicode values implicitly, if the given labelnames are unicode + objects. + + .. change:: + :tags: mysql + :tickets: 1539 + + a column of type TIMESTAMP now defaults to NULL if + "nullable=False" is not passed to Column(), and no default + is present. This is now consistent with all other types, + and in the case of TIMESTAMP explictly renders "NULL" + due to MySQL's "switching" of default nullability + for TIMESTAMP columns. + + .. change:: + :tags: oracle + :tickets: + + unit tests pass 100% with cx_oracle ! + + .. change:: + :tags: oracle + :tickets: + + support for cx_Oracle's "native unicode" mode which does + not require NLS_LANG to be set. Use the latest 5.0.2 or + later of cx_oracle. + + .. change:: + :tags: oracle + :tickets: + + an NCLOB type is added to the base types. + + .. change:: + :tags: oracle + :tickets: + + use_ansi=False won't leak into the FROM/WHERE clause of + a statement that's selecting from a subquery that also + uses JOIN/OUTERJOIN. + + .. change:: + :tags: oracle + :tickets: 1467 + + added native INTERVAL type to the dialect. This supports + only the DAY TO SECOND interval type so far due to lack + of support in cx_oracle for YEAR TO MONTH. + + .. change:: + :tags: oracle + :tickets: + + usage of the CHAR type results in cx_oracle's + FIXED_CHAR dbapi type being bound to statements. + + .. change:: + :tags: oracle + :tickets: 885 + + the Oracle dialect now features NUMBER which intends + to act justlike Oracle's NUMBER type. It is the primary + numeric type returned by table reflection and attempts + to return Decimal()/float/int based on the precision/scale + parameters. + + .. change:: + :tags: oracle + :tickets: + + func.char_length is a generic function for LENGTH + + .. change:: + :tags: oracle + :tickets: + + ForeignKey() which includes onupdate= will emit a + warning, not emit ON UPDATE CASCADE which is unsupported + by oracle + + .. change:: + :tags: oracle + :tickets: + + the keys() method of RowProxy() now returns the result + column names *normalized* to be SQLAlchemy case + insensitive names. This means they will be lower case for + case insensitive names, whereas the DBAPI would normally + return them as UPPERCASE names. This allows row keys() to + be compatible with further SQLAlchemy operations. + + .. change:: + :tags: oracle + :tickets: + + using new dialect.initialize() feature to set up + version-dependent behavior. + + .. change:: + :tags: oracle + :tickets: 1125 + + using types.BigInteger with Oracle will generate + NUMBER(19) + + .. change:: + :tags: oracle + :tickets: + + "case sensitivity" feature will detect an all-lowercase + case-sensitive column name during reflect and add + "quote=True" to the generated Column, so that proper + quoting is maintained. + + .. change:: + :tags: firebird + :tickets: + + the keys() method of RowProxy() now returns the result + column names *normalized* to be SQLAlchemy case + insensitive names. This means they will be lower case for + case insensitive names, whereas the DBAPI would normally + return them as UPPERCASE names. This allows row keys() to + be compatible with further SQLAlchemy operations. + + .. change:: + :tags: firebird + :tickets: + + using new dialect.initialize() feature to set up + version-dependent behavior. + + .. change:: + :tags: firebird + :tickets: + + "case sensitivity" feature will detect an all-lowercase + case-sensitive column name during reflect and add + "quote=True" to the generated Column, so that proper + quoting is maintained. + + .. change:: + :tags: mssql + :tickets: + + MSSQL + Pyodbc + FreeTDS now works for the most part, + with possible exceptions regarding binary data as well as + unicode schema identifiers. + + .. change:: + :tags: mssql + :tickets: + + the "has_window_funcs" flag is removed. LIMIT/OFFSET + usage will use ROW NUMBER as always, and if on an older + version of SQL Server, the operation fails. The behavior + is exactly the same except the error is raised by SQL + server instead of the dialect, and no flag setting is + required to enable it. + + .. change:: + :tags: mssql + :tickets: + + the "auto_identity_insert" flag is removed. This feature + always takes effect when an INSERT statement overrides a + column that is known to have a sequence on it. As with + "has_window_funcs", if the underlying driver doesn't + support this, then you can't do this operation in any + case, so there's no point in having a flag. + + .. change:: + :tags: mssql + :tickets: + + using new dialect.initialize() feature to set up + version-dependent behavior. + + .. change:: + :tags: mssql + :tickets: + + removed references to sequence which is no longer used. + implicit identities in mssql work the same as implicit + sequences on any other dialects. Explicit sequences are + enabled through the use of "default=Sequence()". See + the MSSQL dialect documentation for more information. + + .. change:: + :tags: sqlite + :tickets: + + DATE, TIME and DATETIME types can now take optional storage_format + and regexp argument. storage_format can be used to store those types + using a custom string format. regexp allows to use a custom regular + expression to match string values from the database. + + .. change:: + :tags: sqlite + :tickets: + + Time and DateTime types now use by a default a stricter regular + expression to match strings from the database. Use the regexp + argument if you are using data stored in a legacy format. + + .. change:: + :tags: sqlite + :tickets: + + __legacy_microseconds__ on SQLite Time and DateTime types is not + supported anymore. You should use the storage_format argument + instead. + + .. change:: + :tags: sqlite + :tickets: + + Date, Time and DateTime types are now stricter in what they accept as + bind parameters: Date type only accepts date objects (and datetime + ones, because they inherit from date), Time only accepts time + objects, and DateTime only accepts date and datetime objects. + + .. change:: + :tags: sqlite + :tickets: 1016 + + Table() supports a keyword argument "sqlite_autoincrement", which + applies the SQLite keyword "AUTOINCREMENT" to the single integer + primary key column when generating DDL. Will prevent generation of + a separate PRIMARY KEY constraint. + + .. change:: + :tags: types + :tickets: + + The construction of types within dialects has been totally + overhauled. Dialects now define publically available types + as UPPERCASE names exclusively, and internal implementation + types using underscore identifiers (i.e. are private). + The system by which types are expressed in SQL and DDL + has been moved to the compiler system. This has the + effect that there are much fewer type objects within + most dialects. A detailed document on this architecture + for dialect authors is in + lib/sqlalchemy/dialects/type_migration_guidelines.txt . + + .. change:: + :tags: types + :tickets: + + Types no longer make any guesses as to default + parameters. In particular, Numeric, Float, NUMERIC, + FLOAT, DECIMAL don't generate any length or scale unless + specified. + + .. change:: + :tags: types + :tickets: 1664 + + types.Binary is renamed to types.LargeBinary, it only + produces BLOB, BYTEA, or a similar "long binary" type. + New base BINARY and VARBINARY + types have been added to access these MySQL/MS-SQL specific + types in an agnostic way. + + .. change:: + :tags: types + :tickets: + + String/Text/Unicode types now skip the unicode() check + on each result column value if the dialect has + detected the DBAPI as returning Python unicode objects + natively. This check is issued on first connect + using "SELECT CAST 'some text' AS VARCHAR(10)" or + equivalent, then checking if the returned object + is a Python unicode. This allows vast performance + increases for native-unicode DBAPIs, including + pysqlite/sqlite3, psycopg2, and pg8000. + + .. change:: + :tags: types + :tickets: + + Most types result processors have been checked for possible speed + improvements. Specifically, the following generic types have been + optimized, resulting in varying speed improvements: + Unicode, PickleType, Interval, TypeDecorator, Binary. + Also the following dbapi-specific implementations have been improved: + Time, Date and DateTime on Sqlite, ARRAY on Postgresql, + Time on MySQL, Numeric(as_decimal=False) on MySQL, oursql and + pypostgresql, DateTime on cx_oracle and LOB-based types on cx_oracle. + + .. change:: + :tags: types + :tickets: + + Reflection of types now returns the exact UPPERCASE + type within types.py, or the UPPERCASE type within + the dialect itself if the type is not a standard SQL + type. This means reflection now returns more accurate + information about reflected types. + + .. change:: + :tags: types + :tickets: 1511, 1109 + + Added a new Enum generic type. Enum is a schema-aware object + to support databases which require specific DDL in order to + use enum or equivalent; in the case of PG it handles the + details of `CREATE TYPE`, and on other databases without + native enum support will by generate VARCHAR + an inline CHECK + constraint to enforce the enum. + + .. change:: + :tags: types + :tickets: 1467 + + The Interval type includes a "native" flag which controls + if native INTERVAL types (postgresql + oracle) are selected + if available, or not. "day_precision" and "second_precision" + arguments are also added which propagate as appropriately + to these native types. Related to. + + .. change:: + :tags: types + :tickets: 1589 + + The Boolean type, when used on a backend that doesn't + have native boolean support, will generate a CHECK + constraint "col IN (0, 1)" along with the int/smallint- + based column type. This can be switched off if + desired with create_constraint=False. + Note that MySQL has no native boolean *or* CHECK constraint + support so this feature isn't available on that platform. + + .. change:: + :tags: types + :tickets: + + PickleType now uses == for comparison of values when + mutable=True, unless the "comparator" argument with a + comparsion function is specified to the type. Objects + being pickled will be compared based on identity (which + defeats the purpose of mutable=True) if __eq__() is not + overridden or a comparison function is not provided. + + .. change:: + :tags: types + :tickets: + + The default "precision" and "scale" arguments of Numeric + and Float have been removed and now default to None. + NUMERIC and FLOAT will be rendered with no numeric + arguments by default unless these values are provided. + + .. change:: + :tags: types + :tickets: + + AbstractType.get_search_list() is removed - the games + that was used for are no longer necessary. + + .. change:: + :tags: types + :tickets: 1125 + + Added a generic BigInteger type, compiles to + BIGINT or NUMBER(19). + + .. change:: + :tags: types + :tickets: + + sqlsoup has been overhauled to explicitly support an 0.5 style + session, using autocommit=False, autoflush=True. Default + behavior of SQLSoup now requires the usual usage of commit() + and rollback(), which have been added to its interface. An + explcit Session or scoped_session can be passed to the + constructor, allowing these arguments to be overridden. + + .. change:: + :tags: types + :tickets: + + sqlsoup db..update() and delete() now call + query(cls).update() and delete(), respectively. + + .. change:: + :tags: types + :tickets: + + sqlsoup now has execute() and connection(), which call upon + the Session methods of those names, ensuring that the bind is + in terms of the SqlSoup object's bind. + + .. change:: + :tags: types + :tickets: + + sqlsoup objects no longer have the 'query' attribute - it's + not needed for sqlsoup's usage paradigm and it gets in the + way of a column that is actually named 'query'. + + .. change:: + :tags: types + :tickets: 1259 + + The signature of the proxy_factory callable passed to + association_proxy is now (lazy_collection, creator, + value_attr, association_proxy), adding a fourth argument + that is the parent AssociationProxy argument. Allows + serializability and subclassing of the built in collections. + + .. change:: + :tags: types + :tickets: 1372 + + association_proxy now has basic comparator methods .any(), + .has(), .contains(), ==, !=, thanks to Scott Torborg. diff --git a/doc/build/changelog/changelog_07.rst b/doc/build/changelog/changelog_07.rst new file mode 100644 index 0000000000..7b28f5f230 --- /dev/null +++ b/doc/build/changelog/changelog_07.rst @@ -0,0 +1,4436 @@ + +============== +0.7 Changelog +============== + + +.. changelog:: + :version: 0.7.10 + :released: + + .. change:: + :tags: orm, bug + :tickets: 2583 + + Fixed Session accounting bug whereby replacing + a deleted object in the identity map with another + object of the same primary key would raise a + "conflicting state" error on rollback(), + if the replaced primary key were established either + via non-unitofwork-established INSERT statement + or by primary key switch of another instance. + + .. change:: + :tags: oracle, bug + :tickets: 2561 + + changed the list of cx_oracle types that are + excluded from the setinputsizes() step to only include + STRING and UNICODE; CLOB and NCLOB are removed. This + is to work around cx_oracle behavior which is broken + for the executemany() call. In 0.8, this same change + is applied however it is also configurable via the + exclude_setinputsizes argument. + + .. change:: + :tags: feature, mysql + :tickets: 2523 + + Added "raise_on_warnings" flag to OurSQL + dialect. + + .. change:: + :tags: feature, mysql + :tickets: 2554 + + Added "read_timeout" flag to MySQLdb + dialect. + +.. changelog:: + :version: 0.7.9 + :released: Mon Oct 01 2012 + + .. change:: + :tags: orm, bug + :tickets: + + Fixed bug mostly local to new + AbstractConcreteBase helper where the "type" + attribute from the superclass would not + be overridden on the subclass to produce the + "reserved for base" error message, instead placing + a do-nothing attribute there. This was inconsistent + vs. using ConcreteBase as well as all the behavior + of classical concrete mappings, where the "type" + column from the polymorphic base would be explicitly + disabled on subclasses, unless overridden + explicitly. + + .. change:: + :tags: orm, bug + :tickets: + + A warning is emitted when lazy='dynamic' + is combined with uselist=False. This is an + exception raise in 0.8. + + .. change:: + :tags: orm, bug + :tickets: + + Fixed bug whereby user error in related-object + assignment could cause recursion overflow if the + assignment triggered a backref of the same name + as a bi-directional attribute on the incorrect + class to the same target. An informative + error is raised now. + + .. change:: + :tags: orm, bug + :tickets: 2539 + + Fixed bug where incorrect type information + would be passed when the ORM would bind the + "version" column, when using the "version" feature. + Tests courtesy Daniel Miller. + + .. change:: + :tags: orm, bug + :tickets: 2566 + + Extra logic has been added to the "flush" + that occurs within Session.commit(), such that the + extra state added by an after_flush() or + after_flush_postexec() hook is also flushed in a + subsequent flush, before the "commit" completes. + Subsequent calls to flush() will continue until + the after_flush hooks stop adding new state. + An "overflow" counter of 100 is also in place, + in the event of a broken after_flush() hook + adding new content each time. + + .. change:: + :tags: bug, sql + :tickets: 2571 + + Fixed the DropIndex construct to support + an Index associated with a Table in a remote + schema. + + .. change:: + :tags: bug, sql + :tickets: 2574 + + Fixed bug in over() construct whereby + passing an empty list for either partition_by + or order_by, as opposed to None, would fail + to generate correctly. + Courtesy Gunnlaugur Þór Briem. + + .. change:: + :tags: bug, sql + :tickets: 2521 + + Fixed CTE bug whereby positional + bound parameters present in the CTEs themselves + would corrupt the overall ordering of + bound parameters. This primarily + affected SQL Server as the platform with + positional binds + CTE support. + + .. change:: + :tags: bug, sql + :tickets: + + Fixed more un-intuitivenesses in CTEs + which prevented referring to a CTE in a union + of itself without it being aliased. + CTEs now render uniquely + on name, rendering the outermost CTE of a given + name only - all other references are rendered + just as the name. This even includes other + CTE/SELECTs that refer to different versions + of the same CTE object, such as a SELECT + or a UNION ALL of that SELECT. We are + somewhat loosening the usual link between object + identity and lexical identity in this case. + A true name conflict between two unrelated + CTEs now raises an error. + + .. change:: + :tags: bug, sql + :tickets: 2512 + + quoting is applied to the column names + inside the WITH RECURSIVE clause of a + common table expression according to the + quoting rules for the originating Column. + + .. change:: + :tags: bug, sql + :tickets: 2518 + + Fixed regression introduced in 0.7.6 + whereby the FROM list of a SELECT statement + could be incorrect in certain "clone+replace" + scenarios. + + .. change:: + :tags: bug, sql + :tickets: 2552 + + Fixed bug whereby usage of a UNION + or similar inside of an embedded subquery + would interfere with result-column targeting, + in the case that a result-column had the same + ultimate name as a name inside the embedded + UNION. + + .. change:: + :tags: bug, sql + :tickets: 2558 + + Fixed a regression since 0.6 regarding + result-row targeting. It should be possible + to use a select() statement with string + based columns in it, that is + select(['id', 'name']).select_from('mytable'), + and have this statement be targetable by + Column objects with those names; this is the + mechanism by which + query(MyClass).from_statement(some_statement) + works. At some point the specific case of + using select(['id']), which is equivalent to + select([literal_column('id')]), stopped working + here, so this has been re-instated and of + course tested. + + .. change:: + :tags: bug, sql + :tickets: 2544 + + Added missing operators is_(), isnot() + to the ColumnOperators base, so that these long-available + operators are present as methods like all + the other operators. + + .. change:: + :tags: engine, bug + :tickets: 2522 + + Fixed bug whereby + a disconnect detect + dispose that occurs + when the QueuePool has threads waiting + for connections would leave those + threads waiting for the duration of + the timeout on the old pool (or indefinitely + if timeout was disabled). The fix + now notifies those waiters with a special + exception case and has them move onto + the new pool. + + .. change:: + :tags: engine, feature + :tickets: 2516 + + Dramatic improvement in memory + usage of the event system; instance-level + collections are no longer created for a + particular type of event until + instance-level listeners are established + for that event. + + .. change:: + :tags: engine, bug + :tickets: 2529 + + Added gaerdbms import to mysql/__init__.py, + the absense of which was preventing the new + GAE dialect from being loaded. + + .. change:: + :tags: engine, bug + :tickets: 2553 + + Fixed cextension bug whereby the + "ambiguous column error" would fail to + function properly if the given index were + a Column object and not a string. + Note there are still some column-targeting + issues here which are fixed in 0.8. + + .. change:: + :tags: engine, bug + :tickets: + + Fixed the repr() of Enum to include + the "name" and "native_enum" flags. Helps + Alembic autogenerate. + + .. change:: + :tags: sqlite, bug + :tickets: 2568 + + Adjusted a very old bugfix which attempted + to work around a SQLite issue that itself was + "fixed" as of sqlite 3.6.14, regarding quotes + surrounding a table name when using + the "foreign_key_list" pragma. The fix has been + adjusted to not interfere with quotes that + are *actually in the name* of a column or table, + to as much a degree as possible; sqlite still + doesn't return the correct result for foreign_key_list() + if the target table actually has quotes surrounding + its name, as *part* of its name (i.e. """mytable"""). + + .. change:: + :tags: sqlite, bug + :tickets: 2265 + + Adjusted column default reflection code to + convert non-string values to string, to accommodate + old SQLite versions that don't deliver + default info as a string. + + .. change:: + :tags: sqlite, feature + :tickets: + + Added support for the localtimestamp() + SQL function implemented in SQLite, courtesy + Richard Mitchell. + + .. change:: + :tags: postgresql, bug + :tickets: 2531 + + Columns in reflected primary key constraint + are now returned in the order in which the constraint + itself defines them, rather than how the table + orders them. Courtesy Gunnlaugur Þór Briem.. + + .. change:: + :tags: postgresql, bug + :tickets: 2570 + + Added 'terminating connection' to the list + of messages we use to detect a disconnect with PG, which + appears to be present in some versions when the server + is restarted. + + .. change:: + :tags: bug, mysql + :tickets: + + Updated mysqlconnector interface to use + updated "client flag" and "charset" APIs, + courtesy David McNelis. + + .. change:: + :tags: mssql, bug + :tickets: 2538 + + Fixed compiler bug whereby using a correlated + subquery within an ORDER BY would fail to render correctly + if the stament also used LIMIT/OFFSET, due to mis-rendering + within the ROW_NUMBER() OVER clause. Fix courtesy + sayap + + .. change:: + :tags: mssql, bug + :tickets: 2545 + + Fixed compiler bug whereby a given + select() would be modified if it had an "offset" + attribute, causing the construct to not compile + correctly a second time. + + .. change:: + :tags: mssql, bug + :tickets: + + Fixed bug where reflection of primary key constraint + would double up columns if the same constraint/table + existed in multiple schemas. + +.. changelog:: + :version: 0.7.8 + :released: Sat Jun 16 2012 + + .. change:: + :tags: orm, bug + :tickets: 2480 + + Fixed bug whereby subqueryload() from + a polymorphic mapping to a target would incur + a new invocation of the query for each + distinct class encountered in the polymorphic + result. + + .. change:: + :tags: orm, bug + :tickets: 2491, 1892 + + Fixed bug in declarative + whereby the precedence of columns + in a joined-table, composite + column (typically for id) would fail to + be correct if the columns contained + names distinct from their attribute + names. This would cause things like + primaryjoin conditions made against the + entity attributes to be incorrect. Related + to as this was supposed + to be part of that, this is. + + .. change:: + :tags: orm, feature + :tickets: + + The 'objects' argument to + flush() is no longer deprecated, as some + valid use cases have been identified. + + .. change:: + :tags: orm, bug + :tickets: 2508 + + Fixed identity_key() function which + was not accepting a scalar argument + for the identity. . + + .. change:: + :tags: orm, bug + :tickets: 2497 + + Fixed bug whereby populate_existing + option would not propagate to subquery + eager loaders. . + + .. change:: + :tags: bug, sql + :tickets: 2499 + + added BIGINT to types.__all__, + BIGINT, BINARY, VARBINARY to sqlalchemy + module namespace, plus test to ensure + this breakage doesn't occur again. + + .. change:: + :tags: bug, sql + :tickets: 2490 + + Repaired common table expression + rendering to function correctly when the + SELECT statement contains UNION or other + compound expressions, courtesy btbuilder. + + .. change:: + :tags: bug, sql + :tickets: 2482 + + Fixed bug whereby append_column() + wouldn't function correctly on a cloned + select() construct, courtesy + Gunnlaugur Þór Briem. + + .. change:: + :tags: engine, bug + :tickets: 2489 + + Fixed memory leak in C version of + result proxy whereby DBAPIs which don't deliver + pure Python tuples for result rows would + fail to decrement refcounts correctly. + The most prominently affected DBAPI + is pyodbc. + + .. change:: + :tags: engine, bug + :tickets: 2503 + + Fixed bug affecting Py3K whereby + string positional parameters passed to + engine/connection execute() would fail to be + interpreted correctly, due to __iter__ + being present on Py3K string.. + + .. change:: + :tags: postgresql, bug + :tickets: 2510 + + removed unnecessary table clause when + reflecting enums,. Courtesy + Gunnlaugur Þór Briem. + + .. change:: + :tags: oracle, bug + :tickets: 2483 + + Added ROWID to oracle.*. + + .. change:: + :tags: feature, mysql + :tickets: 2484 + + Added a new dialect for Google App + Engine. Courtesy Richie Foreman. + +.. changelog:: + :version: 0.7.7 + :released: Sat May 05 2012 + + .. change:: + :tags: orm, bug + :tickets: 2477 + + Fixed issue in unit of work + whereby setting a non-None self-referential + many-to-one relationship to None + would fail to persist the change if the + former value was not already loaded.. + + .. change:: + :tags: orm, feature + :tickets: 2443 + + Added prefix_with() method + to Query, calls upon select().prefix_with() + to allow placement of MySQL SELECT + directives in statements. Courtesy + Diana Clarke + + .. change:: + :tags: orm, bug + :tickets: 2409 + + Fixed bug in 0.7.6 introduced by whereby column_mapped_collection + used against columns that were mapped as + joins or other indirect selectables + would fail to function. + + .. change:: + :tags: orm, feature + :tickets: + + Added new flag to @validates + include_removes. When True, collection + remove and attribute del events + will also be sent to the validation function, + which accepts an additional argument + "is_remove" when this flag is used. + + .. change:: + :tags: orm, bug + :tickets: 2449 + + Fixed bug whereby polymorphic_on + column that's not otherwise mapped on the + class would be incorrectly included + in a merge() operation, raising an error. + + .. change:: + :tags: orm, bug + :tickets: 2453 + + Fixed bug in expression annotation + mechanics which could lead to incorrect + rendering of SELECT statements with aliases + and joins, particularly when using + column_property(). + + .. change:: + :tags: orm, bug + :tickets: 2454 + + Fixed bug which would prevent + OrderingList from being pickleable. Courtesy Jeff Dairiki + + .. change:: + :tags: orm, bug + :tickets: + + Fixed bug in relationship comparisons + whereby calling unimplemented methods like + SomeClass.somerelationship.like() would + produce a recursion overflow, instead + of NotImplementedError. + + .. change:: + :tags: bug, sql + :tickets: + + Removed warning when Index is created + with no columns; while this might not be what + the user intended, it is a valid use case + as an Index could be a placeholder for just an + index of a certain name. + + .. change:: + :tags: feature, sql + :tickets: + + Added new connection event + dbapi_error(). Is called for all DBAPI-level + errors passing the original DBAPI exception + before SQLAlchemy modifies the state + of the cursor. + + .. change:: + :tags: bug, sql + :tickets: + + If conn.begin() fails when calling + "with engine.begin()", the newly acquired + Connection is closed explicitly before + propagating the exception onward normally. + + .. change:: + :tags: bug, sql + :tickets: 2474 + + Add BINARY, VARBINARY to types.__all__. + + .. change:: + :tags: mssql, feature + :tickets: + + Added interim create_engine flag + supports_unicode_binds to PyODBC dialect, + to force whether or not the dialect + passes Python unicode literals to PyODBC + or not. + + .. change:: + :tags: mssql, bug + :tickets: + + Repaired the use_scope_identity + create_engine() flag when using the pyodbc + dialect. Previously this flag would be + ignored if set to False. When set to False, + you'll get "SELECT @@identity" after each + INSERT to get at the last inserted ID, + for those tables which have "implicit_returning" + set to False. + + .. change:: + :tags: mssql, bug + :tickets: 2468 + + UPDATE..FROM syntax with SQL Server + requires that the updated table be present + in the FROM clause when an alias of that + table is also present in the FROM clause. + The updated table is now always present + in the FROM, when FROM is present + in the first place. Courtesy sayap. + + .. change:: + :tags: postgresql, feature + :tickets: 2445 + + Added new for_update/with_lockmode() + options for Postgresql: for_update="read"/ + with_lockmode("read"), + for_update="read_nowait"/ + with_lockmode("read_nowait"). + These emit "FOR SHARE" and "FOR SHARE NOWAIT", + respectively. Courtesy Diana Clarke + + .. change:: + :tags: postgresql, bug + :tickets: 2473 + + removed unnecessary table clause + when reflecting domains. + + .. change:: + :tags: bug, mysql + :tickets: 2460 + + Fixed bug whereby column name inside + of "KEY" clause for autoincrement composite + column with InnoDB would double quote a + name that's a reserved word. Courtesy Jeff + Dairiki. + + .. change:: + :tags: bug, mysql + :tickets: + + Fixed bug whereby get_view_names() for + "information_schema" schema would fail + to retrieve views marked as "SYSTEM VIEW". + courtesy Matthew Turland. + + .. change:: + :tags: bug, mysql + :tickets: 2467 + + Fixed bug whereby if cast() is used + on a SQL expression whose type is not supported + by cast() and therefore CAST isn't rendered by + the dialect, the order of evaluation could change + if the casted expression required that it be + grouped; grouping is now applied to those + expressions. + + .. change:: + :tags: sqlite, feature + :tickets: 2475 + + Added SQLite execution option + "sqlite_raw_colnames=True", will bypass + attempts to remove "." from column names + returned by SQLite cursor.description. + + .. change:: + :tags: sqlite, bug + :tickets: 2525 + + When the primary key column of a Table + is replaced, such as via extend_existing, + the "auto increment" column used by insert() + constructs is reset. Previously it would + remain referring to the previous primary + key column. + +.. changelog:: + :version: 0.7.6 + :released: Wed Mar 14 2012 + + .. change:: + :tags: orm, bug + :tickets: 2424 + + Fixed event registration bug + which would primarily show up as + events not being registered with + sessionmaker() instances created + after the event was associated + with the Session class. + + .. change:: + :tags: orm, bug + :tickets: 2425 + + Fixed bug whereby a primaryjoin + condition with a "literal" in it would + raise an error on compile with certain + kinds of deeply nested expressions + which also needed to render the same + bound parameter name more than once. + + .. change:: + :tags: orm, feature + :tickets: + + Added "no_autoflush" context + manager to Session, used with with: + will temporarily disable autoflush. + + .. change:: + :tags: orm, feature + :tickets: 1859 + + Added cte() method to Query, + invokes common table expression support + from the Core (see below). + + .. change:: + :tags: orm, bug + :tickets: 2403 + + Removed the check for number of + rows affected when doing a multi-delete + against mapped objects. If an ON DELETE + CASCADE exists between two rows, we can't + get an accurate rowcount from the DBAPI; + this particular count is not supported + on most DBAPIs in any case, MySQLdb + is the notable case where it is. + + .. change:: + :tags: orm, bug + :tickets: 2409 + + Fixed bug whereby objects using + attribute_mapped_collection or + column_mapped_collection could not be + pickled. + + .. change:: + :tags: orm, bug + :tickets: 2406 + + Fixed bug whereby MappedCollection + would not get the appropriate collection + instrumentation if it were only used + in a custom subclass that used + @collection.internally_instrumented. + + .. change:: + :tags: orm, bug + :tickets: 2419 + + Fixed bug whereby SQL adaption mechanics + would fail in a very nested scenario involving + joined-inheritance, joinedload(), limit(), and a + derived function in the columns clause. + + .. change:: + :tags: orm, bug + :tickets: 2417 + + Fixed the repr() for CascadeOptions to + include refresh-expire. Also reworked + CascadeOptions to be a . + + .. change:: + :tags: orm, feature + :tickets: 2400 + + Added the ability to query for + Table-bound column names when using + query(sometable).filter_by(colname=value). + + .. change:: + :tags: orm, bug + :tickets: + + Improved the "declarative reflection" + example to support single-table inheritance, + multiple calls to prepare(), tables that + are present in alternate schemas, + establishing only a subset of classes + as reflected. + + .. change:: + :tags: orm, bug + :tickets: 2390 + + Scaled back the test applied within + flush() to check for UPDATE against partially + NULL PK within one table to only actually + happen if there's really an UPDATE to occur. + + .. change:: + :tags: orm, bug + :tickets: 2352 + + Fixed bug whereby if a method name + conflicted with a column name, a + TypeError would be raised when the mapper + tried to inspect the __get__() method + on the method object. + + .. change:: + :tags: bug, sql + :tickets: 2427 + + Fixed memory leak in core which would + occur when C extensions were used with + particular types of result fetches, + in particular when orm query.count() + were called. + + .. change:: + :tags: bug, sql + :tickets: 2398 + + Fixed issue whereby attribute-based + column access on a row would raise + AttributeError with non-C version, + NoSuchColumnError with C version. Now + raises AttributeError in both cases. + + .. change:: + :tags: feature, sql + :tickets: 1859 + + Added support for SQL standard + common table expressions (CTE), allowing + SELECT objects as the CTE source (DML + not yet supported). This is invoked via + the cte() method on any select() construct. + + .. change:: + :tags: bug, sql + :tickets: 2392 + + Added support for using the .key + of a Column as a string identifier in a + result set row. The .key is currently + listed as an "alternate" name for a column, + and is superseded by the name of a column + which has that key value as its regular name. + For the next major release + of SQLAlchemy we may reverse this precedence + so that .key takes precedence, but this + is not decided on yet. + + .. change:: + :tags: bug, sql + :tickets: 2413 + + A warning is emitted when a not-present + column is stated in the values() clause + of an insert() or update() construct. + Will move to an exception in 0.8. + + .. change:: + :tags: bug, sql + :tickets: 2396 + + A significant change to how labeling + is applied to columns in SELECT statements + allows "truncated" labels, that is label names + that are generated in Python which exceed + the maximum identifier length (note this is + configurable via label_length on create_engine()), + to be properly referenced when rendered inside + of a subquery, as well as to be present + in a result set row using their original + in-Python names. + + .. change:: + :tags: bug, sql + :tickets: 2402 + + Fixed bug in new "autoload_replace" flag + which would fail to preserve the primary + key constraint of the reflected table. + + .. change:: + :tags: bug, sql + :tickets: 2380 + + Index will raise when arguments passed + cannot be interpreted as columns or expressions. + Will warn when Index is created + with no columns at all. + + .. change:: + :tags: engine, feature + :tickets: 2407 + + Added "no_parameters=True" execution + option for connections. If no parameters + are present, will pass the statement + as cursor.execute(statement), thereby invoking + the DBAPIs behavior when no parameter collection + is present; for psycopg2 and mysql-python, this + means not interpreting % signs in the string. + This only occurs with this option, and not + just if the param list is blank, as otherwise + this would produce inconsistent behavior + of SQL expressions that normally escape percent + signs (and while compiling, can't know ahead of + time if parameters will be present in + some cases). + + .. change:: + :tags: engine, bug + :tickets: + + Added execution_options() call to + MockConnection (i.e., that used with + strategy="mock") which acts as a pass through + for arguments. + + .. change:: + :tags: engine, feature + :tickets: 2378 + + Added pool_reset_on_return argument + to create_engine, allows control over + "connection return" behavior. Also added + new arguments 'rollback', 'commit', None + to pool.reset_on_return to allow more control + over connection return activity. + + .. change:: + :tags: engine, feature + :tickets: + + Added some decent context managers + to Engine, Connection: + + with engine.begin() as conn: + + + and: + + with engine.connect() as conn: + + + Both close out the connection when done, + commit or rollback transaction with errors + on engine.begin(). + + .. change:: + :tags: sqlite, bug + :tickets: 2432 + + Fixed bug in C extensions whereby + string format would not be applied to a + Numeric value returned as integer; this + affected primarily SQLite which does + not maintain numeric scale settings. + + .. change:: + :tags: mssql, feature + :tickets: 2430 + + Added support for MSSQL INSERT, + UPDATE, and DELETE table hints, using + new with_hint() method on UpdateBase. + + .. change:: + :tags: feature, mysql + :tickets: 2386 + + Added support for MySQL index and + primary key constraint types + (i.e. USING) via new mysql_using parameter + to Index and PrimaryKeyConstraint, + courtesy Diana Clarke. + + .. change:: + :tags: feature, mysql + :tickets: 2394 + + Added support for the "isolation_level" + parameter to all MySQL dialects. Thanks + to mu_mind for the patch here. + + .. change:: + :tags: oracle, feature + :tickets: 2399 + + Added a new create_engine() flag + coerce_to_decimal=False, disables the precision + numeric handling which can add lots of overhead + by converting all numeric values to + Decimal. + + .. change:: + :tags: oracle, bug + :tickets: 2401 + + Added missing compilation support for + LONG + + .. change:: + :tags: oracle, bug + :tickets: 2435 + + Added 'LEVEL' to the list of reserved + words for Oracle. + + .. change:: + :tags: examples, bug + :tickets: + + Altered _params_from_query() function + in Beaker example to pull bindparams from the + fully compiled statement, as a quick means + to get everything including subqueries in the + columns clause, etc. + +.. changelog:: + :version: 0.7.5 + :released: Sat Jan 28 2012 + + .. change:: + :tags: orm, bug + :tickets: 2389 + + Fixed issue where modified session state + established after a failed flush would be committed + as part of the subsequent transaction that + begins automatically after manual call + to rollback(). The state of the session is + checked within rollback(), and if new state + is present, a warning is emitted and + restore_snapshot() is called a second time, + discarding those changes. + + .. change:: + :tags: orm, bug + :tickets: 2345 + + Fixed regression from 0.7.4 whereby + using an already instrumented column from a + superclass as "polymorphic_on" failed to resolve + the underlying Column. + + .. change:: + :tags: orm, bug + :tickets: 2370 + + Raise an exception if xyzload_all() is + used inappropriately with two non-connected + relationships. + + .. change:: + :tags: orm, feature + :tickets: + + Added "class_registry" argument to + declarative_base(). Allows two or more declarative + bases to share the same registry of class names. + + .. change:: + :tags: orm, feature + :tickets: + + query.filter() accepts multiple + criteria which will join via AND, i.e. + query.filter(x==y, z>q, ...) + + .. change:: + :tags: orm, feature + :tickets: 2351 + + Added new capability to relationship + loader options to allow "default" loader strategies. + Pass '*' to any of joinedload(), lazyload(), + subqueryload(), or noload() and that becomes the + loader strategy used for all relationships, + except for those explicitly stated in the + Query. Thanks to up-and-coming contributor + Kent Bower for an exhaustive and well + written test suite ! + + .. change:: + :tags: orm, bug + :tickets: 2367 + + Fixed bug whereby event.listen(SomeClass) + forced an entirely unnecessary compile of the + mapper, making events very hard to set up + at module import time (nobody noticed this ??) + + .. change:: + :tags: orm, bug + :tickets: + + Fixed bug whereby hybrid_property didn't + work as a kw arg in any(), has(). + + .. change:: + :tags: orm + :tickets: + + Fixed regression from 0.6 whereby if + "load_on_pending" relationship() flag were used + where a non-"get()" lazy clause needed to be + emitted on a pending object, it would fail + to load. + + .. change:: + :tags: orm, bug + :tickets: 2371 + + ensure pickleability of all ORM exceptions + for multiprocessing compatibility. + + .. change:: + :tags: orm, bug + :tickets: 2353 + + implemented standard "can't set attribute" / + "can't delete attribute" AttributeError when + setattr/delattr used on a hybrid that doesn't + define fset or fdel. + + .. change:: + :tags: orm, bug + :tickets: 2362 + + Fixed bug where unpickled object didn't + have enough of its state set up to work + correctly within the unpickle() event established + by the mutable object extension, if the object + needed ORM attribute access within + __eq__() or similar. + + .. change:: + :tags: orm, bug + :tickets: 2374 + + Fixed bug where "merge" cascade could + mis-interpret an unloaded attribute, if the + load_on_pending flag were used with + relationship(). Thanks to Kent Bower + for tests. + + .. change:: + :tags: orm, feature + :tickets: 2356 + + New declarative reflection example + added, illustrates how best to mix table reflection + with declarative as well as uses some new features + from. + + .. change:: + :tags: feature, sql + :tickets: 2356 + + New reflection feature "autoload_replace"; + when set to False on Table, the Table can be autoloaded + without existing columns being replaced. Allows + more flexible chains of Table construction/reflection + to be constructed, including that it helps with + combining Declarative with table reflection. + See the new example on the wiki. + + .. change:: + :tags: bug, sql + :tickets: 2356 + + Improved the API for add_column() such that + if the same column is added to its own table, + an error is not raised and the constraints + don't get doubled up. Also helps with some + reflection/declarative patterns. + + .. change:: + :tags: feature, sql + :tickets: + + Added "false()" and "true()" expression + constructs to sqlalchemy.sql namespace, though + not part of __all__ as of yet. + + .. change:: + :tags: feature, sql + :tickets: 2361 + + Dialect-specific compilers now raise + CompileException for all type/statement compilation + issues, instead of InvalidRequestError or ArgumentError. + The DDL for CREATE TABLE will re-raise + CompileExceptions to include table/column information + for the problematic column. + + .. change:: + :tags: bug, sql + :tickets: 2381 + + Fixed issue where the "required" exception + would not be raised for bindparam() with required=True, + if the statement were given no parameters at all. + + .. change:: + :tags: engine, bug + :tickets: 2371 + + Added __reduce__ to StatementError, + DBAPIError, column errors so that exceptions + are pickleable, as when using multiprocessing. + However, not + all DBAPIs support this yet, such as + psycopg2. + + .. change:: + :tags: engine, bug + :tickets: 2382 + + Improved error messages when a non-string + or invalid string is passed to any of the + date/time processors used by SQLite, including + C and Python versions. + + .. change:: + :tags: engine, bug + :tickets: 2377 + + Fixed bug whereby a table-bound Column + object named "_" which matched a column + labeled as "_" could match + inappropriately when targeting in a result + set row. + + .. change:: + :tags: engine, bug + :tickets: 2384 + + Fixed bug in "mock" strategy whereby + correct DDL visit method wasn't called, resulting + in "CREATE/DROP SEQUENCE" statements being + duplicated + + .. change:: + :tags: sqlite, bug + :tickets: 2364 + + the "name" of an FK constraint in SQLite + is reflected as "None", not "0" or other + integer value. + SQLite does not appear to support constraint + naming in any case. + + .. change:: + :tags: sqlite, bug + :tickets: 2368 + + sql.false() and sql.true() compile to + 0 and 1, respectively in sqlite + + .. change:: + :tags: sqlite, bug + :tickets: + + removed an erroneous "raise" in the + SQLite dialect when getting table names + and view names, where logic is in place + to fall back to an older version of + SQLite that doesn't have the + "sqlite_temp_master" table. + + .. change:: + :tags: bug, mysql + :tickets: 2376 + + fixed regexp that filters out warnings + for non-reflected "PARTITION" directives, + thanks to George Reilly + + .. change:: + :tags: mssql, bug + :tickets: 2340 + + Adjusted the regexp used in the + mssql.TIME type to ensure only six digits + are received for the "microseconds" portion + of the value, which is expected by + Python's datetime.time(). Note that + support for sending microseconds doesn't + seem to be possible yet with pyodbc + at least. + + .. change:: + :tags: mssql, bug + :tickets: 2347 + + Dropped the "30 char" limit on pymssql, + based on reports that it's doing things + better these days. pymssql hasn't been + well tested and as the DBAPI is in flux + it's still not clear what the status + is on this driver and how SQLAlchemy's + implementation should adapt. + + .. change:: + :tags: oracle, bug + :tickets: 2388 + + Added ORA-03135 to the never ending + list of oracle "connection lost" errors + + .. change:: + :tags: core, bug + :tickets: 2379 + + Changed LRUCache, used by the mapper + to cache INSERT/UPDATE/DELETE statements, + to use an incrementing counter instead + of a timestamp to track entries, for greater + reliability versus using time.time(), which + can cause test failures on some platforms. + + .. change:: + :tags: core, bug + :tickets: 2383 + + Added a boolean check for the "finalize" + function within the pool connection proxy's + weakref callback before calling it, so that a + warning isn't emitted that this function is None + when the application is exiting and gc has + removed the function from the module before the + weakref callback was invoked. + + .. change:: + :tags: bug, py3k + :tickets: 2348 + + Fixed inappropriate usage of util.py3k + flag and renamed it to util.py3k_warning, since + this flag is intended to detect the -3 flag + series of import restrictions only. + + .. change:: + :tags: examples, feature + :tickets: 2313 + + Simplified the versioning example + a bit to use a declarative mixin as well + as an event listener, instead of a metaclass + + SessionExtension. + + .. change:: + :tags: examples, bug + :tickets: 2346 + + Fixed large_collection.py to close the + session before dropping tables. + +.. changelog:: + :version: 0.7.4 + :released: Fri Dec 09 2011 + + .. change:: + :tags: orm, bug + :tickets: 2315 + + Fixed backref behavior when "popping" the + value off of a many-to-one in response to + a removal from a stale one-to-many - the operation + is skipped, since the many-to-one has since + been updated. + + .. change:: + :tags: orm, bug + :tickets: 2264 + + After some years of not doing this, added + more granularity to the "is X a parent of Y" + functionality, which is used when determining + if the FK on "Y" needs to be "nulled out" as well + as if "Y" should be deleted with delete-orphan + cascade. The test now takes into account the + Python identity of the parent as well its identity + key, to see if the last known parent of Y is + definitely X. If a decision + can't be made, a StaleDataError is raised. The + conditions where this error is raised are fairly + rare, requiring that the previous parent was + garbage collected, and previously + could very well inappropriately update/delete + a record that's since moved onto a new parent, + though there may be some cases where + "silent success" occurred previously that will now + raise in the face of ambiguity. + Expiring "Y" resets the "parent" tracker, meaning + X.remove(Y) could then end up deleting Y even + if X is stale, but this is the same behavior + as before; it's advised to expire X also in that + case. + + .. change:: + :tags: orm, bug + :tickets: 2310 + + fixed inappropriate evaluation of user-mapped + object in a boolean context within query.get(). Also in 0.6.9. + + .. change:: + :tags: orm, bug + :tickets: 2304 + + Added missing comma to PASSIVE_RETURN_NEVER_SET + symbol + + .. change:: + :tags: orm, bug + :tickets: 1776 + + Cls.column.collate("some collation") now + works. Also in 0.6.9 + + .. change:: + :tags: orm, bug + :tickets: 2309 + + the value of a composite attribute is now + expired after an insert or update operation, instead + of regenerated in place. This ensures that a + column value which is expired within a flush + will be loaded first, before the composite + is regenerated using that value. + + .. change:: + :tags: orm, bug + :tickets: 2309, 2308 + + The fix in also emits the + "refresh" event when the composite value is + loaded on access, even if all column + values were already present, as is appropriate. + This fixes the "mutable" extension which relies + upon the "load" event to ensure the _parents + dictionary is up to date, fixes. + Thanks to Scott Torborg for the test case here. + + .. change:: + :tags: orm, bug + :tickets: 2312 + + Fixed bug whereby a subclass of a subclass + using concrete inheritance in conjunction with + the new ConcreteBase or AbstractConcreteBase + would fail to apply the subclasses deeper than + one level to the "polymorphic loader" of each + base + + .. change:: + :tags: orm, bug + :tickets: 2312 + + Fixed bug whereby a subclass of a subclass + using the new AbstractConcreteBase would fail + to acquire the correct "base_mapper" attribute + when the "base" mapper was generated, thereby + causing failures later on. + + .. change:: + :tags: orm, bug + :tickets: 2316 + + Fixed bug whereby column_property() created + against ORM-level column could be treated as + a distinct entity when producing certain + kinds of joined-inh joins. + + .. change:: + :tags: orm, bug + :tickets: 2297 + + Fixed the error formatting raised when + a tuple is inadvertently passed to session.query(). Also in 0.6.9. + + .. change:: + :tags: orm, bug + :tickets: 2328 + + Calls to query.join() to a single-table + inheritance subclass are now tracked, and + are used to eliminate the additional WHERE.. + IN criterion normally tacked on with single + table inheritance, since the join should + accommodate it. This allows OUTER JOIN + to a single table subclass to produce + the correct results, and overall will produce + fewer WHERE criterion when dealing with + single table inheritance joins. + + .. change:: + :tags: orm, bug + :tickets: 2339 + + __table_args__ can now be passed as + an empty tuple as well as an empty dict.. Thanks to Fayaz Yusuf Khan + for the patch. + + .. change:: + :tags: orm, bug + :tickets: 2325 + + Updated warning message when setting + delete-orphan without delete to no longer + refer to 0.6, as we never got around to + upgrading this to an exception. Ideally + this might be better as an exception but + it's not critical either way. + + .. change:: + :tags: orm, feature + :tickets: 2345, 2238 + + polymorphic_on now accepts many + new kinds of values: + + - standalone expressions that aren't + otherwise mapped + - column_property() objects + - string names of any column_property() + or attribute name of a mapped Column + + The docs include an example using + the case() construct, which is likely to be + a common constructed used here. and part of + + Standalone expressions in polymorphic_on + propagate to single-table inheritance + subclasses so that they are used in the + WHERE /JOIN clause to limit rows to that + subclass as is the usual behavior. + + .. change:: + :tags: orm, feature + :tickets: 2301 + + IdentitySet supports the - operator + as the same as difference(), handy when dealing + with Session.dirty etc. + + .. change:: + :tags: orm, feature + :tickets: + + Added new value for Column autoincrement + called "ignore_fk", can be used to force autoincrement + on a column that's still part of a ForeignKeyConstraint. + New example in the relationship docs illustrates + its use. + + .. change:: + :tags: orm, bug + :tickets: + + Fixed bug in get_history() when referring + to a composite attribute that has no value; + added coverage for get_history() regarding + composites which is otherwise just a userland + function. + + .. change:: + :tags: bug, sql + :tickets: 2316, 2261 + + related to, made some + adjustments to the change from + regarding the "from" list on a select(). The + _froms collection is no longer memoized, as this + simplifies various use cases and removes the + need for a "warning" if a column is attached + to a table after it was already used in an + expression - the select() construct will now + always produce the correct expression. + There's probably no real-world + performance hit here; select() objects are + almost always made ad-hoc, and systems that + wish to optimize the re-use of a select() + would be using the "compiled_cache" feature. + A hit which would occur when calling select.bind + has been reduced, but the vast majority + of users shouldn't be using "bound metadata" + anyway :). + + .. change:: + :tags: feature, sql + :tickets: 2166, 1944 + + The update() construct can now accommodate + multiple tables in the WHERE clause, which will + render an "UPDATE..FROM" construct, recognized by + Postgresql and MSSQL. When compiled on MySQL, + will instead generate "UPDATE t1, t2, ..". MySQL + additionally can render against multiple tables in the + SET clause, if Column objects are used as keys + in the "values" parameter or generative method. + + .. change:: + :tags: feature, sql + :tickets: 77 + + Added accessor to types called "python_type", + returns the rudimentary Python type object + for a particular TypeEngine instance, if known, + else raises NotImplementedError. + + .. change:: + :tags: bug, sql + :tickets: 2261, 2319 + + further tweak to the fix from, + so that generative methods work a bit better + off of cloned (this is almost a non-use case though). + In particular this allows with_only_columns() + to behave more consistently. Added additional + documentation to with_only_columns() to clarify + expected behavior, which changed as a result + of. + + .. change:: + :tags: engine, bug + :tickets: 2317 + + Fixed bug whereby transaction.rollback() + would throw an error on an invalidated + connection if the transaction were a + two-phase or savepoint transaction. + For plain transactions, rollback() is a no-op + if the connection is invalidated, so while + it wasn't 100% clear if it should be a no-op, + at least now the interface is consistent. + + .. change:: + :tags: feature, schema + :tickets: + + Added new support for remote "schemas": + + .. change:: + :tags: schema + :tickets: + + MetaData() accepts "schema" and "quote_schema" + arguments, which will be applied to the same-named + arguments of a Table + or Sequence which leaves these at their default + of ``None``. + + .. change:: + :tags: schema + :tickets: + + Sequence accepts "quote_schema" argument + + .. change:: + :tags: schema + :tickets: + + tometadata() for Table will use the "schema" + of the incoming MetaData for the new Table + if the schema argument is explicitly "None" + + .. change:: + :tags: schema + :tickets: + + Added CreateSchema and DropSchema DDL + constructs - these accept just the string + name of a schema and a "quote" flag. + + .. change:: + :tags: schema + :tickets: + + When using default "schema" with MetaData, + ForeignKey will also assume the "default" schema + when locating remote table. This allows the "schema" + argument on MetaData to be applied to any + set of Table objects that otherwise don't have + a "schema". + + .. change:: + :tags: schema + :tickets: 1679 + + a "has_schema" method has been implemented + on dialect, but only works on Postgresql so far. + Courtesy Manlio Perillo. + + .. change:: + :tags: feature, schema + :tickets: 1410 + + The "extend_existing" flag on Table + now allows for the reflection process to take + effect for a Table object that's already been + defined; when autoload=True and extend_existing=True + are both set, the full set of columns will be + reflected from the Table which will then + *overwrite* those columns already present, + rather than no activity occurring. Columns that + are present directly in the autoload run + will be used as always, however. + + .. change:: + :tags: bug, schema + :tickets: + + Fixed bug whereby TypeDecorator would + return a stale value for _type_affinity, when + using a TypeDecorator that "switches" types, + like the CHAR/UUID type. + + .. change:: + :tags: bug, schema + :tickets: + + Fixed bug whereby "order_by='foreign_key'" + option to Inspector.get_table_names + wasn't implementing the sort properly, replaced + with the existing sort algorithm + + .. change:: + :tags: bug, schema + :tickets: 2305 + + the "name" of a column-level CHECK constraint, + if present, is now rendered in the CREATE TABLE + statement using "CONSTRAINT CHECK ". + + .. change:: + :tags: pyodbc, bug + :tickets: 2318 + + pyodbc-based dialects now parse the + pyodbc accurately as far as observed + pyodbc strings, including such gems + as "py3-3.0.1-beta4" + + .. change:: + :tags: postgresql, bug + :tickets: 2311 + + Postgresql dialect memoizes that an ENUM of a + particular name was processed + during a create/drop sequence. This allows + a create/drop sequence to work without any + calls to "checkfirst", and also means with + "checkfirst" turned on it only needs to + check for the ENUM once. + + .. change:: + :tags: postgresql, feature + :tickets: + + Added create_type constructor argument + to pg.ENUM. When False, no CREATE/DROP or + checking for the type will be performed as part + of a table create/drop event; only the + create()/drop)() methods called directly + will do this. Helps with Alembic "offline" + scripts. + + .. change:: + :tags: mssql, feature + :tickets: 822 + + lifted the restriction on SAVEPOINT + for SQL Server. All tests pass using it, + it's not known if there are deeper issues + however. + + .. change:: + :tags: mssql, bug + :tickets: 2336 + + repaired the with_hint() feature which + wasn't implemented correctly on MSSQL - + usually used for the "WITH (NOLOCK)" hint + (which you shouldn't be using anyway ! + use snapshot isolation instead :) ) + + .. change:: + :tags: mssql, bug + :tickets: 2318 + + use new pyodbc version detection for + _need_decimal_fix option. + + .. change:: + :tags: mssql, bug + :tickets: 2343 + + don't cast "table name" as NVARCHAR + on SQL Server 2000. Still mostly in the dark + what incantations are needed to make PyODBC + work fully with FreeTDS 0.91 here, however. + + .. change:: + :tags: mssql, bug + :tickets: 2269 + + Decode incoming values when retrieving + list of index names and the names of columns + within those indexes. + + .. change:: + :tags: bug, mysql + :tickets: + + Unicode adjustments allow latest pymysql + (post 0.4) to pass 100% on Python 2. + + .. change:: + :tags: ext, feature + :tickets: + + Added an example to the hybrid docs + of a "transformer" - a hybrid that returns a + query-transforming callable in combination + with a custom comparator. Uses a new method + on Query called with_transformation(). The use + case here is fairly experimental, but only + adds one line of code to Query. + + .. change:: + :tags: ext, bug + :tickets: + + the @compiles decorator raises an + informative error message when no "default" + compilation handler is present, rather + than KeyError. + + .. change:: + :tags: examples, bug + :tickets: + + Fixed bug in history_meta.py example where + the "unique" flag was not removed from a + single-table-inheritance subclass which + generates columns to put up onto the base. + +.. changelog:: + :version: 0.7.3 + :released: Sun Oct 16 2011 + + .. change:: + :tags: general + :tickets: 2279 + + Adjusted the "importlater" mechanism, which is + used internally to resolve import cycles, + such that the usage of __import__ is completed + when the import of sqlalchemy or sqlalchemy.orm + is done, thereby avoiding any usage of __import__ + after the application starts new threads, + fixes. Also in 0.6.9. + + .. change:: + :tags: orm + :tickets: 2298 + + Improved query.join() such that the "left" side + can more flexibly be a non-ORM selectable, + such as a subquery. A selectable placed + in select_from() will now be used as the left + side, favored over implicit usage + of a mapped entity. + If the join still fails based on lack of + foreign keys, the error message includes + this detail. Thanks to brianrhude + on IRC for the test case. + + .. change:: + :tags: orm + :tickets: 2241 + + Added after_soft_rollback() Session event. This + event fires unconditionally whenever rollback() + is called, regardless of if an actual DBAPI + level rollback occurred. This event + is specifically designed to allow operations + with the Session to proceed after a rollback + when the Session.is_active is True. + + .. change:: + :tags: orm + :tickets: + + added "adapt_on_names" boolean flag to orm.aliased() + construct. Allows an aliased() construct + to link the ORM entity to a selectable that contains + aggregates or other derived forms of a particular + attribute, provided the name is the same as that + of the entity mapped column. + + .. change:: + :tags: orm + :tickets: + + Added new flag expire_on_flush=False to column_property(), + marks those properties that would otherwise be considered + to be "readonly", i.e. derived from SQL expressions, + to retain their value after a flush has occurred, including + if the parent object itself was involved in an update. + + .. change:: + :tags: orm + :tickets: 2237 + + Enhanced the instrumentation in the ORM to support + Py3K's new argument style of "required kw arguments", + i.e. fn(a, b, *, c, d), fn(a, b, *args, c, d). + Argument signatures of mapped object's __init__ + method will be preserved, including required kw rules. + + .. change:: + :tags: orm + :tickets: 2282 + + Fixed bug in unit of work whereby detection of + "cycles" among classes in highly interlinked patterns + would not produce a deterministic + result; thereby sometimes missing some nodes that + should be considered cycles and causing further + issues down the road. Note this bug is in 0.6 + also; not backported at the moment. + + .. change:: + :tags: orm + :tickets: + + Fixed a variety of synonym()-related regressions + from 0.6: + - making a synonym against a synonym now works. + - synonyms made against a relationship() can + be passed to query.join(), options sent + to query.options(), passed by name + to query.with_parent(). + + .. change:: + :tags: orm + :tickets: 2287 + + Fixed bug whereby mapper.order_by attribute would + be ignored in the "inner" query within a + subquery eager load. . + Also in 0.6.9. + + .. change:: + :tags: orm + :tickets: 2267 + + Identity map .discard() uses dict.pop(,None) + internally instead of "del" to avoid KeyError/warning + during a non-determinate gc teardown + + .. change:: + :tags: orm + :tickets: 2253 + + Fixed regression in new composite rewrite where + deferred=True option failed due to missing + import + + .. change:: + :tags: orm + :tickets: 2248 + + Reinstated "comparator_factory" argument to + composite(), removed when 0.7 was released. + + .. change:: + :tags: orm + :tickets: 2247 + + Fixed bug in query.join() which would occur + in a complex multiple-overlapping path scenario, + where the same table could be joined to + twice. Thanks *much* to Dave Vitek + for the excellent fix here. + + .. change:: + :tags: orm + :tickets: + + Query will convert an OFFSET of zero when + slicing into None, so that needless OFFSET + clauses are not invoked. + + .. change:: + :tags: orm + :tickets: + + Repaired edge case where mapper would fail + to fully update internal state when a relationship + on a new mapper would establish a backref on the + first mapper. + + .. change:: + :tags: orm + :tickets: 2260 + + Fixed bug whereby if __eq__() was + redefined, a relationship many-to-one lazyload + would hit the __eq__() and fail. + Does not apply to 0.6.9. + + .. change:: + :tags: orm + :tickets: 2196 + + Calling class_mapper() and passing in an object + that is not a "type" (i.e. a class that could + potentially be mapped) now raises an informative + ArgumentError, rather than UnmappedClassError. + + .. change:: + :tags: orm + :tickets: + + New event hook, MapperEvents.after_configured(). + Called after a configure() step has completed and + mappers were in fact affected. Theoretically this + event is called once per application, unless new mappings + are constructed after existing ones have been used + already. + + .. change:: + :tags: orm + :tickets: 2281 + + When an open Session is garbage collected, the objects + within it which remain are considered detached again + when they are add()-ed to a new Session. + This is accomplished by an extra check that the previous + "session_key" doesn't actually exist among the pool + of Sessions. + + .. change:: + :tags: orm + :tickets: 2239 + + New declarative features: + - __declare_last__() method, establishes an event + listener for the class method that will be called + when mappers are completed with the final "configure" + step. + - __abstract__ flag. The class will not be mapped + at all when this flag is present on the class. + - New helper classes ConcreteBase, AbstractConcreteBase. + Allow concrete mappings using declarative which automatically + set up the "polymorphic_union" when the "configure" + mapper step is invoked. + - The mapper itself has semi-private methods that allow + the "with_polymorphic" selectable to be assigned + to the mapper after it has already been configured. + + .. change:: + :tags: orm + :tickets: 2283 + + Declarative will warn when a subclass' base uses + @declared_attr for a regular column - this attribute + does not propagate to subclasses. + + .. change:: + :tags: orm + :tickets: 2280 + + The integer "id" used to link a mapped instance with + its owning Session is now generated by a sequence + generation function rather than id(Session), to + eliminate the possibility of recycled id() values + causing an incorrect result, no need to check that + object actually in the session. + + .. change:: + :tags: orm + :tickets: 2257 + + Behavioral improvement: empty + conjunctions such as and_() and or_() will be + flattened in the context of an enclosing conjunction, + i.e. and_(x, or_()) will produce 'X' and not 'X AND + ()'.. + + .. change:: + :tags: orm + :tickets: 2261 + + Fixed bug regarding calculation of "from" list + for a select() element. The "from" calc is now + delayed, so that if the construct uses a Column + object that is not yet attached to a Table, + but is later associated with a Table, it generates + SQL using the table as a FROM. This change + impacted fairly deeply the mechanics of how + the FROM list as well as the "correlates" collection + is calculated, as some "clause adaption" schemes + (these are used very heavily in the ORM) + were relying upon the fact that the "froms" + collection would typically be cached before the + adaption completed. The rework allows it + such that the "froms" collection can be cleared + and re-generated at any time. + + .. change:: + :tags: orm + :tickets: 2270 + + Fixed bug whereby with_only_columns() method of + Select would fail if a selectable were passed.. Also in 0.6.9. + + .. change:: + :tags: schema + :tickets: 2284 + + Modified Column.copy() to use _constructor(), + which defaults to self.__class__, in order to + create the new object. This allows easier support + of subclassing Column. + + .. change:: + :tags: schema + :tickets: 2223 + + Added a slightly nicer __repr__() to SchemaItem + classes. Note the repr here can't fully support + the "repr is the constructor" idea since schema + items can be very deeply nested/cyclical, have + late initialization of some things, etc. + + .. change:: + :tags: engine + :tickets: 2254 + + The recreate() method in all pool classes uses + self.__class__ to get at the type of pool + to produce, in the case of subclassing. Note + there's no usual need to subclass pools. + + .. change:: + :tags: engine + :tickets: 2243 + + Improvement to multi-param statement logging, + long lists of bound parameter sets will be + compressed with an informative indicator + of the compression taking place. Exception + messages use the same improved formatting. + + .. change:: + :tags: engine + :tickets: + + Added optional "sa_pool_key" argument to + pool.manage(dbapi).connect() so that serialization + of args is not necessary. + + .. change:: + :tags: engine + :tickets: 2286 + + The entry point resolution supported by + create_engine() now supports resolution of + individual DBAPI drivers on top of a built-in + or entry point-resolved dialect, using the + standard '+' notation - it's converted to + a '.' before being resolved as an entry + point. + + .. change:: + :tags: engine + :tickets: 2299 + + Added an exception catch + warning for the + "return unicode detection" step within connect, + allows databases that crash on NVARCHAR to + continue initializing, assuming no NVARCHAR + type implemented. + + .. change:: + :tags: types + :tickets: 2258 + + Extra keyword arguments to the base Float + type beyond "precision" and "asdecimal" are ignored; + added a deprecation warning here and additional + docs, related to + + .. change:: + :tags: sqlite + :tickets: + + Ensured that the same ValueError is raised for + illegal date/time/datetime string parsed from + the database regardless of whether C + extensions are in use or not. + + .. change:: + :tags: postgresql + :tickets: 2290 + + Added "postgresql_using" argument to Index(), produces + USING clause to specify index implementation for + PG. . Thanks to Ryan P. Kelly for + the patch. + + .. change:: + :tags: postgresql + :tickets: 1839 + + Added client_encoding parameter to create_engine() + when the postgresql+psycopg2 dialect is used; + calls the psycopg2 set_client_encoding() method + with the value upon connect. + + .. change:: + :tags: postgresql + :tickets: 2291, 2141 + + Fixed bug related to whereby the + same modified index behavior in PG 9 affected + primary key reflection on a renamed column.. Also in 0.6.9. + + .. change:: + :tags: postgresql + :tickets: 2256 + + Reflection functions for Table, Sequence no longer + case insensitive. Names can be differ only in case + and will be correctly distinguished. + + .. change:: + :tags: postgresql + :tickets: + + Use an atomic counter as the "random number" + source for server side cursor names; + conflicts have been reported in rare cases. + + .. change:: + :tags: postgresql + :tickets: 2249 + + Narrowed the assumption made when reflecting + a foreign-key referenced table with schema in + the current search path; an explicit schema will + be applied to the referenced table only if + it actually matches that of the referencing table, + which also has an explicit schema. Previously + it was assumed that "current" schema was synonymous + with the full search_path. + + .. change:: + :tags: mysql + :tickets: 2225 + + a CREATE TABLE will put the COLLATE option + after CHARSET, which appears to be part of + MySQL's arbitrary rules regarding if it will actually + work or not. Also in 0.6.9. + + .. change:: + :tags: mysql + :tickets: 2293 + + Added mysql_length parameter to Index construct, + specifies "length" for indexes. + + .. change:: + :tags: mssql + :tickets: 2273 + + Changes to attempt support of FreeTDS 0.91 with + Pyodbc. This includes that string binds are sent as + Python unicode objects when FreeTDS 0.91 is detected, + and a CAST(? AS NVARCHAR) is used when we detect + for a table. However, I'd continue + to characterize Pyodbc + FreeTDS 0.91 behavior as + pretty crappy, there are still many queries such + as used in reflection which cause a core dump on + Linux, and it is not really usable at all + on OSX, MemoryErrors abound and just plain broken + unicode support. + + .. change:: + :tags: mssql + :tickets: 2277 + + The behavior of =/!= when comparing a scalar select + to a value will no longer produce IN/NOT IN as of 0.8; + this behavior is a little too heavy handed (use in_() if + you want to emit IN) and now emits a deprecation warning. + To get the 0.8 behavior immediately and remove the warning, + a compiler recipe is given at + http://www.sqlalchemy.org/docs/07/dialects/mssql.html#scalar-select-comparisons + to override the behavior of visit_binary(). + + .. change:: + :tags: mssql + :tickets: 2222 + + "0" is accepted as an argument for limit() which + will produce "TOP 0". + + .. change:: + :tags: oracle + :tickets: 2272 + + Fixed ReturningResultProxy for zxjdbc dialect.. Regression from 0.6. + + .. change:: + :tags: oracle + :tickets: 2252 + + The String type now generates VARCHAR2 on Oracle + which is recommended as the default VARCHAR. + Added an explicit VARCHAR2 and NVARCHAR2 to the Oracle + dialect as well. Using NVARCHAR still generates + "NVARCHAR2" - there is no "NVARCHAR" on Oracle - + this remains a slight breakage of the "uppercase types + always give exactly that" policy. VARCHAR still + generates "VARCHAR", keeping with the policy. If + Oracle were to ever define "VARCHAR" as something + different as they claim (IMHO this will never happen), + the type would be available. + + .. change:: + :tags: ext + :tickets: 2262 + + SQLSoup will not be included in version 0.8 + of SQLAlchemy; while useful, we would like to + keep SQLAlchemy itself focused on one ORM + usage paradigm. SQLSoup will hopefully + soon be superseded by a third party + project. + + .. change:: + :tags: ext + :tickets: 2236 + + Added local_attr, remote_attr, attr accessors + to AssociationProxy, providing quick access + to the proxied attributes at the class + level. + + .. change:: + :tags: ext + :tickets: 2275 + + Changed the update() method on association proxy + dictionary to use a duck typing approach, i.e. + checks for "keys", to discern between update({}) + and update((a, b)). Previously, passing a + dictionary that had tuples as keys would be misinterpreted + as a sequence. + + .. change:: + :tags: examples + :tickets: 2266 + + Adjusted dictlike-polymorphic.py example + to apply the CAST such that it works on + PG, other databases. + Also in 0.6.9. + +.. changelog:: + :version: 0.7.2 + :released: Sun Jul 31 2011 + + .. change:: + :tags: orm + :tickets: 2213 + + Feature enhancement: joined and subquery + loading will now traverse already-present related + objects and collections in search of unpopulated + attributes throughout the scope of the eager load + being defined, so that the eager loading that is + specified via mappings or query options + unconditionally takes place for the full depth, + populating whatever is not already populated. + Previously, this traversal would stop if a related + object or collection were already present leading + to inconsistent behavior (though would save on + loads/cycles for an already-loaded graph). For a + subqueryload, this means that the additional + SELECT statements emitted by subqueryload will + invoke unconditionally, no matter how much of the + existing graph is already present (hence the + controversy). The previous behavior of "stopping" + is still in effect when a query is the result of + an attribute-initiated lazyload, as otherwise an + "N+1" style of collection iteration can become + needlessly expensive when the same related object + is encountered repeatedly. There's also an + as-yet-not-public generative Query method + _with_invoke_all_eagers() + which selects old/new behavior + + .. change:: + :tags: orm + :tickets: 2195 + + A rework of "replacement traversal" within + the ORM as it alters selectables to be against + aliases of things (i.e. clause adaption) includes + a fix for multiply-nested any()/has() constructs + against a joined table structure. + + .. change:: + :tags: orm + :tickets: 2234 + + Fixed bug where query.join() + aliased=True + from a joined-inh structure to itself on + relationship() with join condition on the child + table would convert the lead entity into the + joined one inappropriately. + Also in 0.6.9. + + .. change:: + :tags: orm + :tickets: 2205 + + Fixed regression from 0.6 where Session.add() + against an object which contained None in a + collection would raise an internal exception. + Reverted this to 0.6's behavior which is to + accept the None but obviously nothing is + persisted. Ideally, collections with None + present or on append() should at least emit a + warning, which is being considered for 0.8. + + .. change:: + :tags: orm + :tickets: 2191 + + Load of a deferred() attribute on an object + where row can't be located raises + ObjectDeletedError instead of failing later + on; improved the message in ObjectDeletedError + to include other conditions besides a simple + "delete". + + .. change:: + :tags: orm + :tickets: 2224 + + Fixed regression from 0.6 where a get history + operation on some relationship() based attributes + would fail when a lazyload would emit; this could + trigger within a flush() under certain conditions. Thanks to the user who submitted + the great test for this. + + .. change:: + :tags: orm + :tickets: 2228 + + Fixed bug apparent only in Python 3 whereby + sorting of persistent + pending objects during + flush would produce an illegal comparison, + if the persistent object primary key + is not a single integer. + Also in 0.6.9 + + .. change:: + :tags: orm + :tickets: 2197 + + Fixed bug whereby the source clause + used by query.join() would be inconsistent + if against a column expression that combined + multiple entities together. + Also in 0.6.9 + + .. change:: + :tags: orm + :tickets: 2215 + + Fixed bug whereby if a mapped class + redefined __hash__() or __eq__() to something + non-standard, which is a supported use case + as SQLA should never consult these, + the methods would be consulted if the class + was part of a "composite" (i.e. non-single-entity) + result set. + Also in 0.6.9. + + .. change:: + :tags: orm + :tickets: 2240 + + Added public attribute ".validators" to + Mapper, an immutable dictionary view of + all attributes that have been decorated + with the @validates decorator. courtesy Stefano Fontanelli + + .. change:: + :tags: orm + :tickets: 2188 + + Fixed subtle bug that caused SQL to blow + up if: column_property() against subquery + + joinedload + LIMIT + order by the column + property() occurred. . + Also in 0.6.9 + + .. change:: + :tags: orm + :tickets: 2207 + + The join condition produced by with_parent + as well as when using a "dynamic" relationship + against a parent will generate unique + bindparams, rather than incorrectly repeating + the same bindparam. . + Also in 0.6.9. + + .. change:: + :tags: orm + :tickets: + + Added the same "columns-only" check to + mapper.polymorphic_on as used when + receiving user arguments to + relationship.order_by, foreign_keys, + remote_side, etc. + + .. change:: + :tags: orm + :tickets: 2190 + + Fixed bug whereby comparison of column + expression to a Query() would not call + as_scalar() on the underlying SELECT + statement to produce a scalar subquery, + in the way that occurs if you called + it on Query().subquery(). + + .. change:: + :tags: orm + :tickets: 2194 + + Fixed declarative bug where a class inheriting + from a superclass of the same name would fail + due to an unnecessary lookup of the name + in the _decl_class_registry. + + .. change:: + :tags: orm + :tickets: 2199 + + Repaired the "no statement condition" + assertion in Query which would attempt + to raise if a generative method were called + after from_statement() were called.. Also in 0.6.9. + + .. change:: + :tags: sql + :tickets: 2188 + + Fixed two subtle bugs involving column + correspondence in a selectable, + one with the same labeled subquery repeated, the other + when the label has been "grouped" and + loses itself. Affects. + + .. change:: + :tags: schema + :tickets: 2187 + + New feature: with_variant() method on + all types. Produces an instance of Variant(), + a special TypeDecorator which will select + the usage of a different type based on the + dialect in use. + + .. change:: + :tags: schema + :tickets: + + Added an informative error message when + ForeignKeyConstraint refers to a column name in + the parent that is not found. Also in 0.6.9. + + .. change:: + :tags: schema + :tickets: 2206 + + Fixed bug whereby adaptation of old append_ddl_listener() + function was passing unexpected **kw through + to the Table event. Table gets no kws, the MetaData + event in 0.6 would get "tables=somecollection", + this behavior is preserved. + + .. change:: + :tags: schema + :tickets: + + Fixed bug where "autoincrement" detection on + Table would fail if the type had no "affinity" + value, in particular this would occur when using + the UUID example on the site that uses TypeEngine + as the "impl". + + .. change:: + :tags: schema + :tickets: 2209 + + Added an improved repr() to TypeEngine objects + that will only display constructor args which + are positional or kwargs that deviate + from the default. + + .. change:: + :tags: engine + :tickets: + + Context manager provided by Connection.begin() + will issue rollback() if the commit() fails, + not just if an exception occurs. + + .. change:: + :tags: engine + :tickets: 1682 + + Use urllib.parse_qsl() in Python 2.6 and above, + no deprecation warning about cgi.parse_qsl() + + .. change:: + :tags: engine + :tickets: + + Added mixin class sqlalchemy.ext.DontWrapMixin. + User-defined exceptions of this type are never + wrapped in StatementException when they + occur in the context of a statement + execution. + + .. change:: + :tags: engine + :tickets: + + StatementException wrapping will display the + original exception class in the message. + + .. change:: + :tags: engine + :tickets: 2201 + + Failures on connect which raise dbapi.Error + will forward the error to dialect.is_disconnect() + and set the "connection_invalidated" flag if + the dialect knows this to be a potentially + "retryable" condition. Only Oracle ORA-01033 + implemented for now. + + .. change:: + :tags: sqlite + :tickets: 2189 + + SQLite dialect no longer strips quotes + off of reflected default value, allowing + a round trip CREATE TABLE to work. + This is consistent with other dialects + that also maintain the exact form of + the default. + + .. change:: + :tags: postgresql + :tickets: 2198 + + Added new "postgresql_ops" argument to + Index, allows specification of PostgreSQL + operator classes for indexed columns. Courtesy Filip Zyzniewski. + + .. change:: + :tags: mysql + :tickets: 2186 + + Fixed OurSQL dialect to use ansi-neutral + quote symbol "'" for XA commands instead + of '"'. . Also in 0.6.9. + + .. change:: + :tags: mssql + :tickets: + + Adjusted the pyodbc dialect such that bound + values are passed as bytes and not unicode + if the "Easysoft" unix drivers are detected. + This is the same behavior as occurs with + FreeTDS. Easysoft appears to segfault + if Python unicodes are passed under + certain circumstances. + + .. change:: + :tags: oracle + :tickets: 2200 + + Added ORA-00028 to disconnect codes, use + cx_oracle _Error.code to get at the code,. Also in 0.6.9. + + .. change:: + :tags: oracle + :tickets: 2201 + + Added ORA-01033 to disconnect codes, which + can be caught during a connection + event. + + .. change:: + :tags: oracle + :tickets: 2220 + + repaired the oracle.RAW type which did not + generate the correct DDL. + Also in 0.6.9. + + .. change:: + :tags: oracle + :tickets: 2212 + + added CURRENT to reserved word list. Also in 0.6.9. + + .. change:: + :tags: oracle + :tickets: + + Fixed bug in the mutable extension whereby + if the same type were used twice in one + mapping, the attributes beyond the first + would not get instrumented. + + .. change:: + :tags: oracle + :tickets: + + Fixed bug in the mutable extension whereby + if None or a non-corresponding type were set, + an error would be raised. None is now accepted + which assigns None to all attributes, + illegal values raise ValueError. + + .. change:: + :tags: examples + :tickets: + + Repaired the examples/versioning test runner + to not rely upon SQLAlchemy test libs, + nosetests must be run from within + examples/versioning to get around setup.cfg + breaking it. + + .. change:: + :tags: examples + :tickets: + + Tweak to examples/versioning to pick the + correct foreign key in a multi-level + inheritance situation. + + .. change:: + :tags: examples + :tickets: + + Fixed the attribute shard example to check + for bind param callable correctly in 0.7 + style. + +.. changelog:: + :version: 0.7.1 + :released: Sun Jun 05 2011 + + .. change:: + :tags: general + :tickets: 2184 + + Added a workaround for Python bug 7511 where + failure of C extension build does not + raise an appropriate exception on Windows 64 + bit + VC express + + .. change:: + :tags: orm + :tickets: 1912 + + "delete-orphan" cascade is now allowed on + self-referential relationships - this since + SQLA 0.7 no longer enforces "parent with no + child" at the ORM level; this check is left + up to foreign key nullability. + Related to + + .. change:: + :tags: orm + :tickets: 2180 + + Repaired new "mutable" extension to propagate + events to subclasses correctly; don't + create multiple event listeners for + subclasses either. + + .. change:: + :tags: orm + :tickets: 2170 + + Modify the text of the message which occurs + when the "identity" key isn't detected on + flush, to include the common cause that + the Column isn't set up to detect + auto-increment correctly;. + Also in 0.6.8. + + .. change:: + :tags: orm + :tickets: 2182 + + Fixed bug where transaction-level "deleted" + collection wouldn't be cleared of expunged + states, raising an error if they later + became transient. + Also in 0.6.8. + + .. change:: + :tags: sql + :tickets: + + Fixed bug whereby metadata.reflect(bind) + would close a Connection passed as a + bind argument. Regression from 0.6. + + .. change:: + :tags: sql + :tickets: + + Streamlined the process by which a Select + determines what's in it's '.c' collection. + Behaves identically, except that a + raw ClauseList() passed to select([]) + (which is not a documented case anyway) will + now be expanded into its individual column + elements instead of being ignored. + + .. change:: + :tags: engine + :tickets: + + Deprecate schema/SQL-oriented methods on + Connection/Engine that were never well known + and are redundant: reflecttable(), create(), + drop(), text(), engine.func + + .. change:: + :tags: engine + :tickets: 2178 + + Adjusted the __contains__() method of + a RowProxy result row such that no exception + throw is generated internally; + NoSuchColumnError() also will generate its + message regardless of whether or not the column + construct can be coerced to a string.. Also in 0.6.8. + + .. change:: + :tags: sqlite + :tickets: 2173 + + Accept None from cursor.fetchone() when + "PRAGMA read_uncommitted" is called to determine + current isolation mode at connect time and + default to SERIALIZABLE; this to support SQLite + versions pre-3.3.0 that did not have this + feature. + + .. change:: + :tags: postgresql + :tickets: 2175 + + Some unit test fixes regarding numeric arrays, + MATCH operator. A potential floating-point + inaccuracy issue was fixed, and certain tests + of the MATCH operator only execute within an + EN-oriented locale for now. . + Also in 0.6.8. + + .. change:: + :tags: mysql + :tickets: + + Unit tests pass 100% on MySQL installed + on windows. + + .. change:: + :tags: mysql + :tickets: 2181 + + Removed the "adjust casing" step that would + fail when reflecting a table on MySQL + on windows with a mixed case name. After some + experimenting with a windows MySQL server, it's + been determined that this step wasn't really + helping the situation much; MySQL does not return + FK names with proper casing on non-windows + platforms either, and removing the step at + least allows the reflection to act more like + it does on other OSes. A warning here + has been considered but its difficult to + determine under what conditions such a warning + can be raised, so punted on that for now - + added some docs instead. + + .. change:: + :tags: mysql + :tickets: + + supports_sane_rowcount will be set to False + if using MySQLdb and the DBAPI doesn't provide + the constants.CLIENT module. + +.. changelog:: + :version: 0.7.0 + :released: Fri May 20 2011 + + .. change:: + :tags: + :tickets: + + This section documents those changes from 0.7b4 + to 0.7.0. For an overview of what's new in + SQLAlchemy 0.7, see + http://www.sqlalchemy.org/trac/wiki/07Migration + + .. change:: + :tags: orm + :tickets: 2069 + + Fixed regression introduced in 0.7b4 (!) whereby + query.options(someoption("nonexistent name")) would + fail to raise an error. Also added additional + error catching for cases where the option would + try to build off a column-based element, further + fixed up some of the error messages tailored + in + + .. change:: + :tags: orm + :tickets: 2162 + + query.count() emits "count(*)" instead of + "count(1)". + + .. change:: + :tags: orm + :tickets: 2155 + + Fine tuning of Query clause adaptation when + from_self(), union(), or other "select from + myself" operation, such that plain SQL expression + elements added to filter(), order_by() etc. + which are present in the nested "from myself" + query *will* be adapted in the same way an ORM + expression element will, since these + elements are otherwise not easily accessible. + + .. change:: + :tags: orm + :tickets: 2149 + + Fixed bug where determination of "self referential" + relationship would fail with no workaround + for joined-inh subclass related to itself, + or joined-inh subclass related to a subclass + of that with no cols in the sub-sub class + in the join condition. + Also in 0.6.8. + + .. change:: + :tags: orm + :tickets: 2153 + + mapper() will ignore non-configured foreign keys + to unrelated tables when determining inherit + condition between parent and child class, + but will raise as usual for unresolved + columns and table names regarding the inherited + table. This is an enhanced generalization of + behavior that was already applied to declarative + previously. 0.6.8 has a more + conservative version of this which doesn't + fundamentally alter how join conditions + are determined. + + .. change:: + :tags: orm + :tickets: 2144 + + It is an error to call query.get() when the + given entity is not a single, full class + entity or mapper (i.e. a column). This is + a deprecation warning in 0.6.8. + + .. change:: + :tags: orm + :tickets: 2148 + + Fixed a potential KeyError which under some + circumstances could occur with the identity + map, part of + + .. change:: + :tags: orm + :tickets: + + added Query.with_session() method, switches + Query to use a different session. + + .. change:: + :tags: orm + :tickets: 2131 + + horizontal shard query should use execution + options per connection as per + + .. change:: + :tags: orm + :tickets: 2151 + + a non_primary mapper will inherit the _identity_class + of the primary mapper. This so that a non_primary + established against a class that's normally in an + inheritance mapping will produce results that are + identity-map compatible with that of the primary + mapper (also in 0.6.8) + + .. change:: + :tags: orm + :tickets: 2163 + + Fixed the error message emitted for "can't + execute syncrule for destination column 'q'; + mapper 'X' does not map this column" to + reference the correct mapper. . + Also in 0.6.8. + + .. change:: + :tags: orm + :tickets: 1502 + + polymorphic_union() gets a "cast_nulls" option, + disables the usage of CAST when it renders + the labeled NULL columns. + + .. change:: + :tags: orm + :tickets: + + polymorphic_union() renders the columns in their + original table order, as according to the first + table/selectable in the list of polymorphic + unions in which they appear. (which is itself + an unordered mapping unless you pass an OrderedDict). + + .. change:: + :tags: orm + :tickets: 2171 + + Fixed bug whereby mapper mapped to an anonymous + alias would fail if logging were used, due to + unescaped % sign in the alias name. + Also in 0.6.8. + + .. change:: + :tags: sql + :tickets: 2167 + + Fixed bug whereby nesting a label of a select() + with another label in it would produce incorrect + exported columns. Among other things this would + break an ORM column_property() mapping against + another column_property(). . + Also in 0.6.8 + + .. change:: + :tags: sql + :tickets: + + Changed the handling in determination of join + conditions such that foreign key errors are + only considered between the two given tables. + That is, t1.join(t2) will report FK errors + that involve 't1' or 't2', but anything + involving 't3' will be skipped. This affects + join(), as well as ORM relationship and + inherit condition logic. + + .. change:: + :tags: sql + :tickets: + + Some improvements to error handling inside + of the execute procedure to ensure auto-close + connections are really closed when very + unusual DBAPI errors occur. + + .. change:: + :tags: sql + :tickets: + + metadata.reflect() and reflection.Inspector() + had some reliance on GC to close connections + which were internally procured, fixed this. + + .. change:: + :tags: sql + :tickets: 2140 + + Added explicit check for when Column .name + is assigned as blank string + + .. change:: + :tags: sql + :tickets: 2147 + + Fixed bug whereby if FetchedValue was passed + to column server_onupdate, it would not + have its parent "column" assigned, added + test coverage for all column default assignment + patterns. also in 0.6.8 + + .. change:: + :tags: postgresql + :tickets: + + Fixed the psycopg2_version parsing in the + psycopg2 dialect. + + .. change:: + :tags: postgresql + :tickets: 2141 + + Fixed bug affecting PG 9 whereby index reflection + would fail if against a column whose name + had changed. . Also in 0.6.8. + + .. change:: + :tags: mssql + :tickets: 2169 + + Fixed bug in MSSQL dialect whereby the aliasing + applied to a schema-qualified table would leak + into enclosing select statements. + Also in 0.6.8. + + .. change:: + :tags: documentation + :tickets: 2152 + + Removed the usage of the "collections.MutableMapping" + abc from the ext.mutable docs as it was being used + incorrectly and makes the example more difficult + to understand in any case. + + .. change:: + :tags: examples + :tickets: + + removed the ancient "polymorphic association" + examples and replaced with an updated set of + examples that use declarative mixins, + "generic_associations". Each presents an alternative + table layout. + + .. change:: + :tags: ext + :tickets: 2143 + + Fixed bugs in sqlalchemy.ext.mutable extension where + `None` was not appropriately handled, replacement + events were not appropriately handled. + +.. changelog:: + :version: 0.7.0b4 + :released: Sun Apr 17 2011 + + .. change:: + :tags: general + :tickets: + + Changes to the format of CHANGES, this file. + The format changes have been applied to + the 0.7 releases. + + .. change:: + :tags: general + :tickets: + + The "-declarative" changes will now be listed + directly under the "-orm" section, as these + are closely related. + + .. change:: + :tags: general + :tickets: + + The 0.5 series changes have been moved to + the file CHANGES_PRE_06 which replaces + CHANGES_PRE_05. + + .. change:: + :tags: general + :tickets: + + The changelog for 0.6.7 and subsequent within + the 0.6 series is now listed only in the + CHANGES file within the 0.6 branch. + In the 0.7 CHANGES file (i.e. this file), all the + 0.6 changes are listed inline within the 0.7 + section in which they were also applied + (since all 0.6 changes are in 0.7 as well). + Changes that apply to an 0.6 version here + are noted as are if any differences in + implementation/behavior are present. + + .. change:: + :tags: orm + :tickets: 2122 + + Some fixes to "evaulate" and "fetch" evaluation + when query.update(), query.delete() are called. + The retrieval of records is done after autoflush + in all cases, and before update/delete is + emitted, guarding against unflushed data present + as well as expired objects failing during + the evaluation. + + .. change:: + :tags: orm + :tickets: 2063 + + Reworded the exception raised when a flush + is attempted of a subclass that is not polymorphic + against the supertype. + + .. change:: + :tags: orm + :tickets: + + Still more wording adjustments when a query option + can't find the target entity. Explain that the + path must be from one of the root entities. + + .. change:: + :tags: orm + :tickets: 2123 + + Some fixes to the state handling regarding + backrefs, typically when autoflush=False, where + the back-referenced collection wouldn't + properly handle add/removes with no net + change. Thanks to Richard Murri for the + test case + patch. + (also in 0.6.7). + + .. change:: + :tags: orm + :tickets: 2127 + + Added checks inside the UOW to detect the unusual + condition of being asked to UPDATE or DELETE + on a primary key value that contains NULL + in it. + + .. change:: + :tags: orm + :tickets: 2127 + + Some refinements to attribute history. More + changes are pending possibly in 0.8, but + for now history has been modified such that + scalar history doesn't have a "side effect" + of populating None for a non-present value. + This allows a slightly better ability to + distinguish between a None set and no actual + change, affects as well. + + .. change:: + :tags: orm + :tickets: 2130 + + a "having" clause would be copied from the + inside to the outside query if from_self() + were used; in particular this would break + an 0.7 style count() query. + (also in 0.6.7) + + .. change:: + :tags: orm + :tickets: 2131 + + the Query.execution_options() method now passes + those options to the Connection rather than + the SELECT statement, so that all available + options including isolation level and + compiled cache may be used. + + .. change:: + :tags: sql + :tickets: 2131 + + The "compiled_cache" execution option now raises + an error when passed to a SELECT statement + rather than a Connection. Previously it was + being ignored entirely. We may look into + having this option work on a per-statement + level at some point. + + .. change:: + :tags: sql + :tickets: + + Restored the "catchall" constructor on the base + TypeEngine class, with a deprecation warning. + This so that code which does something like + Integer(11) still succeeds. + + .. change:: + :tags: sql + :tickets: 2104 + + Fixed regression whereby MetaData() coming + back from unpickling did not keep track of + new things it keeps track of now, i.e. + collection of Sequence objects, list + of schema names. + + .. change:: + :tags: sql + :tickets: 2116 + + The limit/offset keywords to select() as well + as the value passed to select.limit()/offset() + will be coerced to integer. + (also in 0.6.7) + + .. change:: + :tags: sql + :tickets: + + fixed bug where "from" clause gathering from an + over() clause would be an itertools.chain() and + not a list, causing "can only concatenate list" + TypeError when combined with other clauses. + + .. change:: + :tags: sql + :tickets: 2134 + + Fixed incorrect usage of "," in over() clause + being placed between the "partition" and "order by" + clauses. + + .. change:: + :tags: sql + :tickets: 2105 + + Before/after attach events for PrimaryKeyConstraint + now function, tests added for before/after events + on all constraint types. + + .. change:: + :tags: sql + :tickets: 2117 + + Added explicit true()/false() constructs to expression + lib - coercion rules will intercept "False"/"True" + into these constructs. In 0.6, the constructs were + typically converted straight to string, which was + no longer accepted in 0.7. + + .. change:: + :tags: engine + :tickets: 2129 + + The C extension is now enabled by default on CPython + 2.x with a fallback to pure python if it fails to + compile. + + .. change:: + :tags: schema + :tickets: 2109 + + The 'useexisting' flag on Table has been superceded + by a new pair of flags 'keep_existing' and + 'extend_existing'. 'extend_existing' is equivalent + to 'useexisting' - the existing Table is returned, + and additional constructor elements are added. + With 'keep_existing', the existing Table is returned, + but additional constructor elements are not added - + these elements are only applied when the Table + is newly created. + + .. change:: + :tags: types + :tickets: 2081 + + REAL has been added to the core types. Supported + by Postgresql, SQL Server, MySQL, SQLite. Note + that the SQL Server and MySQL versions, which + add extra arguments, are also still available + from those dialects. + + .. change:: + :tags: types + :tickets: 2106 + + Added @event.listens_for() decorator, given + target + event name, applies the decorated + function as a listener. + + .. change:: + :tags: pool + :tickets: 2103 + + AssertionPool now stores the traceback indicating + where the currently checked out connection was + acquired; this traceback is reported within + the assertion raised upon a second concurrent + checkout; courtesy Gunnlaugur Briem + + .. change:: + :tags: pool + :tickets: + + The "pool.manage" feature doesn't use pickle + anymore to hash the arguments for each pool. + + .. change:: + :tags: sqlite + :tickets: 2115 + + Fixed bug where reflection of foreign key + created as "REFERENCES " without + col name would fail. + (also in 0.6.7) + + .. change:: + :tags: postgresql + :tickets: + + Psycopg2 for Python 3 is now supported. + + .. change:: + :tags: postgresql + :tickets: 2132 + + Fixed support for precision numerics when using + pg8000. + + .. change:: + :tags: oracle + :tickets: 2100 + + Using column names that would require quotes + for the column itself or for a name-generated + bind parameter, such as names with special + characters, underscores, non-ascii characters, + now properly translate bind parameter keys when + talking to cx_oracle. (Also + in 0.6.7) + + .. change:: + :tags: oracle + :tickets: 2116 + + Oracle dialect adds use_binds_for_limits=False + create_engine() flag, will render the LIMIT/OFFSET + values inline instead of as binds, reported to + modify the execution plan used by Oracle. (Also in 0.6.7) + + .. change:: + :tags: documentation + :tickets: 2029 + + Documented SQLite DATE/TIME/DATETIME types. (also in 0.6.7) + + .. change:: + :tags: documentation + :tickets: 2118 + + Fixed mutable extension docs to show the + correct type-association methods. + +.. changelog:: + :version: 0.7.0b3 + :released: Sun Mar 20 2011 + + .. change:: + :tags: general + :tickets: + + Lots of fixes to unit tests when run under Pypy + (courtesy Alex Gaynor). + + .. change:: + :tags: orm + :tickets: 2093 + + Changed the underlying approach to query.count(). + query.count() is now in all cases exactly: + + query. + from_self(func.count(literal_column('1'))). + scalar() + + That is, "select count(1) from ()". + This produces a subquery in all cases, but + vastly simplifies all the guessing count() + tried to do previously, which would still + fail in many scenarios particularly when + joined table inheritance and other joins + were involved. If the subquery produced + for an otherwise very simple count is really + an issue, use query(func.count()) as an + optimization. + + .. change:: + :tags: orm + :tickets: 2087 + + some changes to the identity map regarding + rare weakref callbacks during iterations. + The mutex has been removed as it apparently + can cause a reentrant (i.e. in one thread) deadlock, + perhaps when gc collects objects at the point of + iteration in order to gain more memory. It is hoped + that "dictionary changed during iteration" will + be exceedingly rare as iteration methods internally + acquire the full list of objects in a single values() + call. Note 0.6.7 has a more conservative fix here + which still keeps the mutex in place. + + .. change:: + :tags: orm + :tickets: 2082 + + A tweak to the unit of work causes it to order + the flush along relationship() dependencies even if + the given objects don't have any inter-attribute + references in memory, which was the behavior in + 0.5 and earlier, so a flush of Parent/Child with + only foreign key/primary key set will succeed. + This while still maintaining 0.6 and above's not + generating a ton of useless internal dependency + structures within the flush that don't correspond + to state actually within the current flush. + + .. change:: + :tags: orm + :tickets: 2069 + + Improvements to the error messages emitted when + querying against column-only entities in conjunction + with (typically incorrectly) using loader options, + where the parent entity is not fully present. + + .. change:: + :tags: orm + :tickets: 2098 + + Fixed bug in query.options() whereby a path + applied to a lazyload using string keys could + overlap a same named attribute on the wrong + entity. Note 0.6.7 has a more conservative fix + to this. + + .. change:: + :tags: declarative + :tickets: 2091 + + Arguments in __mapper_args__ that aren't "hashable" + aren't mistaken for always-hashable, possibly-column + arguments. (also in 0.6.7) + + .. change:: + :tags: sql + :tickets: + + Added a fully descriptive error message for the + case where Column is subclassed and _make_proxy() + fails to make a copy due to TypeError on the + constructor. The method _constructor should + be implemented in this case. + + .. change:: + :tags: sql + :tickets: 2095 + + Added new event "column_reflect" for Table objects. + Receives the info dictionary about a Column before + the object is generated within reflection, and allows + modification to the dictionary for control over + most aspects of the resulting Column including + key, name, type, info dictionary. + + .. change:: + :tags: sql + :tickets: + + To help with the "column_reflect" event being used + with specific Table objects instead of all instances + of Table, listeners can be added to a Table object + inline with its construction using a new argument + "listeners", a list of tuples of the form + (, ), which are applied to the Table + before the reflection process begins. + + .. change:: + :tags: sql + :tickets: 2085 + + Added new generic function "next_value()", accepts + a Sequence object as its argument and renders the + appropriate "next value" generation string on the + target platform, if supported. Also provides + ".next_value()" method on Sequence itself. + + .. change:: + :tags: sql + :tickets: 2084 + + func.next_value() or other SQL expression can + be embedded directly into an insert() construct, + and if implicit or explicit "returning" is used + in conjunction with a primary key column, + the newly generated value will be present in + result.inserted_primary_key. + + .. change:: + :tags: sql + :tickets: 2089 + + Added accessors to ResultProxy "returns_rows", + "is_insert" (also in 0.6.7) + + .. change:: + :tags: engine + :tickets: 2097 + + Fixed AssertionPool regression bug. + + .. change:: + :tags: engine + :tickets: 2060 + + Changed exception raised to ArgumentError when an + invalid dialect is specified. + + .. change:: + :tags: postgresql + :tickets: 2092 + + Added RESERVED_WORDS for postgresql dialect. + (also in 0.6.7) + + .. change:: + :tags: postgresql + :tickets: 2073 + + Fixed the BIT type to allow a "length" parameter, "varying" + parameter. Reflection also fixed. + (also in 0.6.7) + + .. change:: + :tags: mssql + :tickets: 2071 + + Rewrote the query used to get the definition of a view, + typically when using the Inspector interface, to + use sys.sql_modules instead of the information schema, + thereby allowing views definitions longer than 4000 + characters to be fully returned. + (also in 0.6.7) + + .. change:: + :tags: firebird + :tickets: 2083 + + The "implicit_returning" flag on create_engine() is + honored if set to False. (also in 0.6.7) + + .. change:: + :tags: informix + :tickets: 2092 + + Added RESERVED_WORDS informix dialect. + (also in 0.6.7) + + .. change:: + :tags: ext + :tickets: 2090 + + The horizontal_shard ShardedSession class accepts the common + Session argument "query_cls" as a constructor argument, + to enable further subclassing of ShardedQuery. (also in 0.6.7) + + .. change:: + :tags: examples + :tickets: + + Updated the association, association proxy examples + to use declarative, added a new example + dict_of_sets_with_default.py, a "pushing the envelope" + example of association proxy. + + .. change:: + :tags: examples + :tickets: 2090 + + The Beaker caching example allows a "query_cls" argument + to the query_callable() function. + (also in 0.6.7) + +.. changelog:: + :version: 0.7.0b2 + :released: Sat Feb 19 2011 + + .. change:: + :tags: orm + :tickets: 2053 + + Fixed bug whereby Session.merge() would call the + load() event with one too few arguments. + + .. change:: + :tags: orm + :tickets: 2052 + + Added logic which prevents the generation of + events from a MapperExtension or SessionExtension + from generating do-nothing events for all the methods + not overridden. + + .. change:: + :tags: declarative + :tickets: 2058 + + Fixed regression whereby composite() with + Column objects placed inline would fail + to initialize. The Column objects can now + be inline with the composite() or external + and pulled in via name or object ref. + + .. change:: + :tags: declarative + :tickets: 2061 + + Fix error message referencing old @classproperty + name to reference @declared_attr + (also in 0.6.7) + + .. change:: + :tags: declarative + :tickets: 1468 + + the dictionary at the end of the __table_args__ + tuple is now optional. + + .. change:: + :tags: sql + :tickets: 2059 + + Renamed the EngineEvents event class to + ConnectionEvents. As these classes are never + accessed directly by end-user code, this strictly + is a documentation change for end users. Also + simplified how events get linked to engines + and connections internally. + + .. change:: + :tags: sql + :tickets: 2055 + + The Sequence() construct, when passed a MetaData() + object via its 'metadata' argument, will be + included in CREATE/DROP statements within + metadata.create_all() and metadata.drop_all(), + including "checkfirst" logic. + + .. change:: + :tags: sql + :tickets: 2064 + + The Column.references() method now returns True + if it has a foreign key referencing the + given column exactly, not just it's parent + table. + + .. change:: + :tags: postgresql + :tickets: 2065 + + Fixed regression from 0.6 where SMALLINT and + BIGINT types would both generate SERIAL + on an integer PK column, instead of + SMALLINT and BIGSERIAL + + .. change:: + :tags: ext + :tickets: 2054 + + Association proxy now has correct behavior for + any(), has(), and contains() when proxying + a many-to-one scalar attribute to a one-to-many + collection (i.e. the reverse of the 'typical' + association proxy use case) + + .. change:: + :tags: examples + :tickets: + + Beaker example now takes into account 'limit' + and 'offset', bind params within embedded + FROM clauses (like when you use union() or + from_self()) when generating a cache key. + +.. changelog:: + :version: 0.7.0b1 + :released: Sat Feb 12 2011 + + .. change:: + :tags: + :tickets: + + Detailed descriptions of each change below are + described at: + http://www.sqlalchemy.org/trac/wiki/07Migration + + .. change:: + :tags: general + :tickets: 1902 + + New event system, supercedes all extensions, listeners, + etc. + + .. change:: + :tags: general + :tickets: 1926 + + Logging enhancements + + .. change:: + :tags: general + :tickets: 1949 + + Setup no longer installs a Nose plugin + + .. change:: + :tags: general + :tickets: + + The "sqlalchemy.exceptions" alias in sys.modules + has been removed. Base SQLA exceptions are + available via "from sqlalchemy import exc". + The "exceptions" alias for "exc" remains in + "sqlalchemy" for now, it's just not patched into + sys.modules. + + .. change:: + :tags: orm + :tickets: 1923 + + More succinct form of query.join(target, onclause) + + .. change:: + :tags: orm + :tickets: 1903 + + Hybrid Attributes, implements/supercedes synonym() + + .. change:: + :tags: orm + :tickets: 2008 + + Rewrite of composites + + .. change:: + :tags: orm + :tickets: + + Mutation Event Extension, supercedes "mutable=True" + + .. change:: + :tags: orm + :tickets: 1980 + + PickleType and ARRAY mutability turned off by default + + .. change:: + :tags: orm + :tickets: 1895 + + Simplified polymorphic_on assignment + + .. change:: + :tags: orm + :tickets: 1912 + + Flushing of Orphans that have no parent is allowed + + .. change:: + :tags: orm + :tickets: 2041 + + Adjusted flush accounting step to occur before + the commit in the case of autocommit=True. This allows + autocommit=True to work appropriately with + expire_on_commit=True, and also allows post-flush session + hooks to operate in the same transactional context + as when autocommit=False. + + .. change:: + :tags: orm + :tickets: 1973 + + Warnings generated when collection members, scalar referents + not part of the flush + + .. change:: + :tags: orm + :tickets: 1876 + + Non-`Table`-derived constructs can be mapped + + .. change:: + :tags: orm + :tickets: 1942 + + Tuple label names in Query Improved + + .. change:: + :tags: orm + :tickets: 1892 + + Mapped column attributes reference the most specific + column first + + .. change:: + :tags: orm + :tickets: 1896 + + Mapping to joins with two or more same-named columns + requires explicit declaration + + .. change:: + :tags: orm + :tickets: 1875 + + Mapper requires that polymorphic_on column be present + in the mapped selectable + + .. change:: + :tags: orm + :tickets: 1966 + + compile_mappers() renamed configure_mappers(), simplified + configuration internals + + .. change:: + :tags: orm + :tickets: 2018 + + the aliased() function, if passed a SQL FromClause element + (i.e. not a mapped class), will return element.alias() + instead of raising an error on AliasedClass. + + .. change:: + :tags: orm + :tickets: 2027 + + Session.merge() will check the version id of the incoming + state against that of the database, assuming the mapping + uses version ids and incoming state has a version_id + assigned, and raise StaleDataError if they don't + match. + + .. change:: + :tags: orm + :tickets: 1996 + + Session.connection(), Session.execute() accept 'bind', + to allow execute/connection operations to participate + in the open transaction of an engine explicitly. + + .. change:: + :tags: orm + :tickets: + + Query.join(), Query.outerjoin(), eagerload(), + eagerload_all(), others no longer allow lists + of attributes as arguments (i.e. option([x, y, z]) + form, deprecated since 0.5) + + .. change:: + :tags: orm + :tickets: + + ScopedSession.mapper is removed (deprecated since 0.5). + + .. change:: + :tags: orm + :tickets: 2031 + + Horizontal shard query places 'shard_id' in + context.attributes where it's accessible by the + "load()" event. + + .. change:: + :tags: orm + :tickets: 2032 + + A single contains_eager() call across + multiple entities will indicate all collections + along that path should load, instead of requiring + distinct contains_eager() calls for each endpoint + (which was never correctly documented). + + .. change:: + :tags: orm + :tickets: + + The "name" field used in orm.aliased() now renders + in the resulting SQL statement. + + .. change:: + :tags: orm + :tickets: 1473 + + Session weak_instance_dict=False is deprecated. + + .. change:: + :tags: orm + :tickets: 2046 + + An exception is raised in the unusual case that an + append or similar event on a collection occurs after + the parent object has been dereferenced, which + prevents the parent from being marked as "dirty" + in the session. Was a warning in 0.6.6. + + .. change:: + :tags: orm + :tickets: 1069 + + Query.distinct() now accepts column expressions + as *args, interpreted by the Postgresql dialect + as DISTINCT ON (). + + .. change:: + :tags: orm + :tickets: 2049 + + Additional tuning to "many-to-one" relationship + loads during a flush(). A change in version 0.6.6 + ([ticket:2002]) required that more "unnecessary" m2o + loads during a flush could occur. Extra loading modes have + been added so that the SQL emitted in this + specific use case is trimmed back, while still + retrieving the information the flush needs in order + to not miss anything. + + .. change:: + :tags: orm + :tickets: + + the value of "passive" as passed to + attributes.get_history() should be one of the + constants defined in the attributes package. Sending + True or False is deprecated. + + .. change:: + :tags: orm + :tickets: 2030 + + Added a `name` argument to `Query.subquery()`, to allow + a fixed name to be assigned to the alias object. (also in 0.6.7) + + .. change:: + :tags: orm + :tickets: 2019 + + A warning is emitted when a joined-table inheriting mapper + has no primary keys on the locally mapped table + (but has pks on the superclass table). + (also in 0.6.7) + + .. change:: + :tags: orm + :tickets: 2038 + + Fixed bug where "middle" class in a polymorphic hierarchy + would have no 'polymorphic_on' column if it didn't also + specify a 'polymorphic_identity', leading to strange + errors upon refresh, wrong class loaded when querying + from that target. Also emits the correct WHERE criterion + when using single table inheritance. + (also in 0.6.7) + + .. change:: + :tags: orm + :tickets: 1995 + + Fixed bug where a column with a SQL or server side default + that was excluded from a mapping with include_properties + or exclude_properties would result in UnmappedColumnError. (also in 0.6.7) + + .. change:: + :tags: orm + :tickets: 2046 + + A warning is emitted in the unusual case that an + append or similar event on a collection occurs after + the parent object has been dereferenced, which + prevents the parent from being marked as "dirty" + in the session. This will be an exception in 0.7. (also in 0.6.7) + + .. change:: + :tags: declarative + :tickets: 2050 + + Added an explicit check for the case that the name + 'metadata' is used for a column attribute on a + declarative class. (also in 0.6.7) + + .. change:: + :tags: sql + :tickets: 1844 + + Added over() function, method to FunctionElement + classes, produces the _Over() construct which + in turn generates "window functions", i.e. + " OVER (PARTITION BY , + ORDER BY )". + + .. change:: + :tags: sql + :tickets: 805 + + LIMIT/OFFSET clauses now use bind parameters + + .. change:: + :tags: sql + :tickets: 1069 + + select.distinct() now accepts column expressions + as *args, interpreted by the Postgresql dialect + as DISTINCT ON (). Note this was already + available via passing a list to the `distinct` + keyword argument to select(). + + .. change:: + :tags: sql + :tickets: + + select.prefix_with() accepts multiple expressions + (i.e. *expr), 'prefix' keyword argument to select() + accepts a list or tuple. + + .. change:: + :tags: sql + :tickets: + + Passing a string to the `distinct` keyword argument + of `select()` for the purpose of emitting special + MySQL keywords (DISTINCTROW etc.) is deprecated - + use `prefix_with()` for this. + + .. change:: + :tags: sql + :tickets: 2006, 2005 + + TypeDecorator works with primary key columns + + .. change:: + :tags: sql + :tickets: 1897 + + DDL() constructs now escape percent signs + + .. change:: + :tags: sql + :tickets: 1917, 1893 + + Table.c / MetaData.tables refined a bit, don't allow direct + mutation + + .. change:: + :tags: sql + :tickets: 1950 + + Callables passed to `bindparam()` don't get evaluated + + .. change:: + :tags: sql + :tickets: 1870 + + types.type_map is now private, types._type_map + + .. change:: + :tags: sql + :tickets: 1982 + + Non-public Pool methods underscored + + .. change:: + :tags: sql + :tickets: 723 + + Added NULLS FIRST and NULLS LAST support. It's implemented + as an extension to the asc() and desc() operators, called + nullsfirst() and nullslast(). + + .. change:: + :tags: sql + :tickets: + + The Index() construct can be created inline with a Table + definition, using strings as column names, as an alternative + to the creation of the index outside of the Table. + + .. change:: + :tags: sql + :tickets: 2001 + + execution_options() on Connection accepts + "isolation_level" argument, sets transaction isolation + level for that connection only until returned to the + connection pool, for thsoe backends which support it + (SQLite, Postgresql) + + .. change:: + :tags: sql + :tickets: 2005 + + A TypeDecorator of Integer can be used with a primary key + column, and the "autoincrement" feature of various dialects + as well as the "sqlite_autoincrement" flag will honor + the underlying database type as being Integer-based. + + .. change:: + :tags: sql + :tickets: 2020, 2021 + + Established consistency when server_default is present + on an Integer PK column. SQLA doesn't pre-fetch these, + nor do they come back in cursor.lastrowid (DBAPI). + Ensured all backends consistently return None + in result.inserted_primary_key for these. Regarding + reflection for this case, reflection of an int PK col + with a server_default sets the "autoincrement" flag to False, + except in the case of a PG SERIAL col where we detected a + sequence default. + + .. change:: + :tags: sql + :tickets: 2006 + + Result-row processors are applied to pre-executed SQL + defaults, as well as cursor.lastrowid, when determining + the contents of result.inserted_primary_key. + + .. change:: + :tags: sql + :tickets: + + Bind parameters present in the "columns clause" of a select + are now auto-labeled like other "anonymous" clauses, + which among other things allows their "type" to be meaningful + when the row is fetched, as in result row processors. + + .. change:: + :tags: sql + :tickets: + + TypeDecorator is present in the "sqlalchemy" import space. + + .. change:: + :tags: sql + :tickets: 2015 + + Non-DBAPI errors which occur in the scope of an `execute()` + call are now wrapped in sqlalchemy.exc.StatementError, + and the text of the SQL statement and repr() of params + is included. This makes it easier to identify statement + executions which fail before the DBAPI becomes + involved. + + .. change:: + :tags: sql + :tickets: 2048 + + The concept of associating a ".bind" directly with a + ClauseElement has been explicitly moved to Executable, + i.e. the mixin that describes ClauseElements which represent + engine-executable constructs. This change is an improvement + to internal organization and is unlikely to affect any + real-world usage. + + .. change:: + :tags: sql + :tickets: 2028 + + Column.copy(), as used in table.tometadata(), copies the + 'doc' attribute. (also in 0.6.7) + + .. change:: + :tags: sql + :tickets: 2023 + + Added some defs to the resultproxy.c extension so that + the extension compiles and runs on Python 2.4. (also in 0.6.7) + + .. change:: + :tags: sql + :tickets: 2042 + + The compiler extension now supports overriding the default + compilation of expression._BindParamClause including that + the auto-generated binds within the VALUES/SET clause + of an insert()/update() statement will also use the new + compilation rules. (also in 0.6.7) + + .. change:: + :tags: sql + :tickets: 1921 + + SQLite dialect now uses `NullPool` for file-based databases + + .. change:: + :tags: sql + :tickets: 2036 + + The path given as the location of a sqlite database is now + normalized via os.path.abspath(), so that directory changes + within the process don't affect the ultimate location + of a relative file path. + + .. change:: + :tags: postgresql + :tickets: 1083 + + When explicit sequence execution derives the name + of the auto-generated sequence of a SERIAL column, + which currently only occurs if implicit_returning=False, + now accommodates if the table + column name is greater + than 63 characters using the same logic Postgresql uses. (also in 0.6.7) + + .. change:: + :tags: postgresql + :tickets: 2044 + + Added an additional libpq message to the list of "disconnect" + exceptions, "could not receive data from server" (also in 0.6.7) + + .. change:: + :tags: mssql + :tickets: 1833 + + the String/Unicode types, and their counterparts VARCHAR/ + NVARCHAR, emit "max" as the length when no length is + specified, so that the default length, normally '1' + as per SQL server documentation, is instead + 'unbounded'. This also occurs for the VARBINARY type.. + + This behavior makes these types more closely compatible + with Postgresql's VARCHAR type which is similarly unbounded + when no length is specified. + + .. change:: + :tags: mysql + :tickets: 1991 + + New DBAPI support for pymysql, a pure Python port + of MySQL-python. + + .. change:: + :tags: mysql + :tickets: 2047 + + oursql dialect accepts the same "ssl" arguments in + create_engine() as that of MySQLdb. + (also in 0.6.7) + + .. change:: + :tags: firebird + :tickets: 1885 + + Some adjustments so that Interbase is supported as well. + FB/Interbase version idents are parsed into a structure + such as (8, 1, 1, 'interbase') or (2, 1, 588, 'firebird') + so they can be distinguished. diff --git a/doc/build/changelog/index.rst b/doc/build/changelog/index.rst new file mode 100644 index 0000000000..7460214127 --- /dev/null +++ b/doc/build/changelog/index.rst @@ -0,0 +1,34 @@ +.. _changelog_toplevel: + +Changes and Migration +===================== + +Migration Guides +---------------- + +SQLAlchemy migration guides are now available within the main documentation. + +.. toctree:: + :maxdepth: 1 + + migration_07 + migration_06 + migration_05 + migration_04 + +Change logs +----------- + +SQLAlchemy changelogs are now available within the main documentation. + +.. toctree:: + :maxdepth: 2 + + changelog_07 + changelog_06 + changelog_05 + changelog_04 + changelog_03 + changelog_02 + changelog_01 + diff --git a/doc/build/changelog/migration_04.rst b/doc/build/changelog/migration_04.rst new file mode 100644 index 0000000000..236bfc3ce1 --- /dev/null +++ b/doc/build/changelog/migration_04.rst @@ -0,0 +1,868 @@ +============================= +What's new in SQLAlchemy 0.4? +============================= + +.. admonition:: About this Document + + This document describes changes between SQLAlchemy version 0.3, + last released October 14, 2007, and SQLAlchemy version 0.4, + last released October 12, 2008. + + Document date: March 21, 2008 + +First Things First +================== + +If you're using any ORM features, make sure you import from +``sqlalchemy.orm``: + +:: + + from sqlalchemy import * + from sqlalchemy.orm import * + +Secondly, anywhere you used to say ``engine=``, +``connectable=``, ``bind_to=``, ``something.engine``, +``metadata.connect()``, use ``bind``: + +:: + + myengine = create_engine('sqlite://') + + meta = MetaData(myengine) + + meta2 = MetaData() + meta2.bind = myengine + + session = create_session(bind=myengine) + + statement = select([table], bind=myengine) + +Got those ? Good! You're now (95%) 0.4 compatible. If +you're using 0.3.10, you can make these changes immediately; +they'll work there too. + +Module Imports +============== + +In 0.3, "``from sqlachemy import *``" would import all of +sqlachemy's sub-modules into your namespace. Version 0.4 no +longer imports sub-modules into the namespace. This may mean +you need to add extra imports into your code. + +In 0.3, this code worked: + +:: + + from sqlalchemy import * + + class UTCDateTime(types.TypeDecorator): + pass + +In 0.4, one must do: + +:: + + from sqlalchemy import * + from sqlalchemy import types + + class UTCDateTime(types.TypeDecorator): + pass + +Object Relational Mapping +========================= + +Querying +-------- + +New Query API +^^^^^^^^^^^^^ + +Query is standardized on the generative interface (old +interface is still there, just deprecated). While most of +the generative interface is available in 0.3, the 0.4 Query +has the inner guts to match the generative outside, and has +a lot more tricks. All result narrowing is via ``filter()`` +and ``filter_by()``, limiting/offset is either through array +slices or ``limit()``/``offset()``, joining is via +``join()`` and ``outerjoin()`` (or more manually, through +``select_from()`` as well as manually-formed criteria). + +To avoid deprecation warnings, you must make some changes to +your 03 code + +User.query.get_by( \**kwargs ) + +:: + + User.query.filter_by(**kwargs).first() + +User.query.select_by( \**kwargs ) + +:: + + User.query.filter_by(**kwargs).all() + +User.query.select() + +:: + + User.query.filter(xxx).all() + +New Property-Based Expression Constructs +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +By far the most palpable difference within the ORM is that +you can now construct your query criterion using class-based +attributes directly. The ".c." prefix is no longer needed +when working with mapped classes: + +:: + + session.query(User).filter(and_(User.name == 'fred', User.id > 17)) + +While simple column-based comparisons are no big deal, the +class attributes have some new "higher level" constructs +available, including what was previously only available in +``filter_by()``: + +:: + + # comparison of scalar relations to an instance + filter(Address.user == user) + + # return all users who contain a particular address + filter(User.addresses.contains(address)) + + # return all users who *dont* contain the address + filter(~User.address.contains(address)) + + # return all users who contain a particular address with + # the email_address like '%foo%' + filter(User.addresses.any(Address.email_address.like('%foo%'))) + + # same, email address equals 'foo@bar.com'. can fall back to keyword + # args for simple comparisons + filter(User.addresses.any(email_address = 'foo@bar.com')) + + # return all Addresses whose user attribute has the username 'ed' + filter(Address.user.has(name='ed')) + + # return all Addresses whose user attribute has the username 'ed' + # and an id > 5 (mixing clauses with kwargs) + filter(Address.user.has(User.id > 5, name='ed')) + +The ``Column`` collection remains available on mapped +classes in the ``.c`` attribute. Note that property-based +expressions are only available with mapped properties of +mapped classes. ``.c`` is still used to access columns in +regular tables and selectable objects produced from SQL +Expressions. + +Automatic Join Aliasing +^^^^^^^^^^^^^^^^^^^^^^^ + +We've had join() and outerjoin() for a while now: + +:: + + session.query(Order).join('items')... + +Now you can alias them: + +:: + + session.query(Order).join('items', aliased=True). + filter(Item.name='item 1').join('items', aliased=True).filter(Item.name=='item 3') + +The above will create two joins from orders->items using +aliases. the ``filter()`` call subsequent to each will +adjust its table criterion to that of the alias. To get at +the ``Item`` objects, use ``add_entity()`` and target each +join with an ``id``: + +:: + + session.query(Order).join('items', id='j1', aliased=True). + filter(Item.name == 'item 1').join('items', aliased=True, id='j2'). + filter(Item.name == 'item 3').add_entity(Item, id='j1').add_entity(Item, id='j2') + +Returns tuples in the form: ``(Order, Item, Item)``. + +Self-referential Queries +^^^^^^^^^^^^^^^^^^^^^^^^ + +So query.join() can make aliases now. What does that give +us ? Self-referential queries ! Joins can be done without +any ``Alias`` objects: + +:: + + # standard self-referential TreeNode mapper with backref + mapper(TreeNode, tree_nodes, properties={ + 'children':relation(TreeNode, backref=backref('parent', remote_side=tree_nodes.id)) + }) + + # query for node with child containing "bar" two levels deep + session.query(TreeNode).join(["children", "children"], aliased=True).filter_by(name='bar') + +To add criterion for each table along the way in an aliased +join, you can use ``from_joinpoint`` to keep joining against +the same line of aliases: + +:: + + # search for the treenode along the path "n1/n12/n122" + + # first find a Node with name="n122" + q = sess.query(Node).filter_by(name='n122') + + # then join to parent with "n12" + q = q.join('parent', aliased=True).filter_by(name='n12') + + # join again to the next parent with 'n1'. use 'from_joinpoint' + # so we join from the previous point, instead of joining off the + # root table + q = q.join('parent', aliased=True, from_joinpoint=True).filter_by(name='n1') + + node = q.first() + +``query.populate_existing()`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The eager version of ``query.load()`` (or +``session.refresh()``). Every instance loaded from the +query, including all eagerly loaded items, get refreshed +immediately if already present in the session: + +:: + + session.query(Blah).populate_existing().all() + +Relations +--------- + +SQL Clauses Embedded in Updates/Inserts +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +For inline execution of SQL clauses, embedded right in the +UPDATE or INSERT, during a ``flush()``: + +:: + + + myobject.foo = mytable.c.value + 1 + + user.pwhash = func.md5(password) + + order.hash = text("select hash from hashing_table") + +The column-attribute is set up with a deferred loader after +the operation, so that it issues the SQL to load the new +value when you next access. + +Self-referential and Cyclical Eager Loading +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Since our alias-fu has improved, ``relation()`` can join +along the same table \*any number of times*; you tell it how +deep you want to go. Lets show the self-referential +``TreeNode`` more clearly: + +:: + + nodes = Table('nodes', metadata, + Column('id', Integer, primary_key=True), + Column('parent_id', Integer, ForeignKey('nodes.id')), + Column('name', String(30))) + + class TreeNode(object): + pass + + mapper(TreeNode, nodes, properties={ + 'children':relation(TreeNode, lazy=False, join_depth=3) + }) + +So what happens when we say: + +:: + + create_session().query(TreeNode).all() + +? A join along aliases, three levels deep off the parent: + +:: + + SELECT + nodes_3.id AS nodes_3_id, nodes_3.parent_id AS nodes_3_parent_id, nodes_3.name AS nodes_3_name, + nodes_2.id AS nodes_2_id, nodes_2.parent_id AS nodes_2_parent_id, nodes_2.name AS nodes_2_name, + nodes_1.id AS nodes_1_id, nodes_1.parent_id AS nodes_1_parent_id, nodes_1.name AS nodes_1_name, + nodes.id AS nodes_id, nodes.parent_id AS nodes_parent_id, nodes.name AS nodes_name + FROM nodes LEFT OUTER JOIN nodes AS nodes_1 ON nodes.id = nodes_1.parent_id + LEFT OUTER JOIN nodes AS nodes_2 ON nodes_1.id = nodes_2.parent_id + LEFT OUTER JOIN nodes AS nodes_3 ON nodes_2.id = nodes_3.parent_id + ORDER BY nodes.oid, nodes_1.oid, nodes_2.oid, nodes_3.oid + +Notice the nice clean alias names too. The joining doesn't +care if it's against the same immediate table or some other +object which then cycles back to the beginining. Any kind +of chain of eager loads can cycle back onto itself when +``join_depth`` is specified. When not present, eager +loading automatically stops when it hits a cycle. + +Composite Types +^^^^^^^^^^^^^^^ + +This is one from the Hibernate camp. Composite Types let +you define a custom datatype that is composed of more than +one column (or one column, if you wanted). Lets define a +new type, ``Point``. Stores an x/y coordinate: + +:: + + class Point(object): + def __init__(self, x, y): + self.x = x + self.y = y + def __composite_values__(self): + return self.x, self.y + def __eq__(self, other): + return other.x == self.x and other.y == self.y + def __ne__(self, other): + return not self.__eq__(other) + +The way the ``Point`` object is defined is specific to a +custom type; constructor takes a list of arguments, and the +``__composite_values__()`` method produces a sequence of +those arguments. The order will match up to our mapper, as +we'll see in a moment. + +Let's create a table of vertices storing two points per row: + +:: + + vertices = Table('vertices', metadata, + Column('id', Integer, primary_key=True), + Column('x1', Integer), + Column('y1', Integer), + Column('x2', Integer), + Column('y2', Integer), + ) + +Then, map it ! We'll create a ``Vertex`` object which +stores two ``Point`` objects: + +:: + + class Vertex(object): + def __init__(self, start, end): + self.start = start + self.end = end + + mapper(Vertex, vertices, properties={ + 'start':composite(Point, vertices.c.x1, vertices.c.y1), + 'end':composite(Point, vertices.c.x2, vertices.c.y2) + }) + +Once you've set up your composite type, it's usable just +like any other type: + +:: + + + v = Vertex(Point(3, 4), Point(26,15)) + session.save(v) + session.flush() + + # works in queries too + q = session.query(Vertex).filter(Vertex.start == Point(3, 4)) + +If you'd like to define the way the mapped attributes +generate SQL clauses when used in expressions, create your +own ``sqlalchemy.orm.PropComparator`` subclass, defining any +of the common operators (like ``__eq__()``, ``__le__()``, +etc.), and send it in to ``composite()``. Composite types +work as primary keys too, and are usable in ``query.get()``: + +:: + + # a Document class which uses a composite Version + # object as primary key + document = query.get(Version(1, 'a')) + +``dynamic_loader()`` relations +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A ``relation()`` that returns a live ``Query`` object for +all read operations. Write operations are limited to just +``append()`` and ``remove()``, changes to the collection are +not visible until the session is flushed. This feature is +particularly handy with an "autoflushing" session which will +flush before each query. + +:: + + mapper(Foo, foo_table, properties={ + 'bars':dynamic_loader(Bar, backref='foo', ) + }) + + session = create_session(autoflush=True) + foo = session.query(Foo).first() + + foo.bars.append(Bar(name='lala')) + + for bar in foo.bars.filter(Bar.name=='lala'): + print bar + + session.commit() + +New Options: ``undefer_group()``, ``eagerload_all()`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A couple of query options which are handy. +``undefer_group()`` marks a whole group of "deferred" +columns as undeferred: + +:: + + mapper(Class, table, properties={ + 'foo' : deferred(table.c.foo, group='group1'), + 'bar' : deferred(table.c.bar, group='group1'), + 'bat' : deferred(table.c.bat, group='group1'), + ) + + session.query(Class).options(undefer_group('group1')).filter(...).all() + +and ``eagerload_all()`` sets a chain of attributes to be +eager in one pass: + +:: + + mapper(Foo, foo_table, properties={ + 'bar':relation(Bar) + }) + mapper(Bar, bar_table, properties={ + 'bat':relation(Bat) + }) + mapper(Bat, bat_table) + + # eager load bar and bat + session.query(Foo).options(eagerload_all('bar.bat')).filter(...).all() + +New Collection API +^^^^^^^^^^^^^^^^^^ + +Collections are no longer proxied by an +{{{InstrumentedList}}} proxy, and access to members, methods +and attributes is direct. Decorators now intercept objects +entering and leaving the collection, and it is now possible +to easily write a custom collection class that manages its +own membership. Flexible decorators also replace the named +method interface of custom collections in 0.3, allowing any +class to be easily adapted to use as a collection container. + +Dictionary-based collections are now much easier to use and +fully ``dict``-like. Changing ``__iter__`` is no longer +needed for ``dict``s, and new built-in ``dict`` types cover +many needs: + +:: + + # use a dictionary relation keyed by a column + relation(Item, collection_class=column_mapped_collection(items.c.keyword)) + # or named attribute + relation(Item, collection_class=attribute_mapped_collection('keyword')) + # or any function you like + relation(Item, collection_class=mapped_collection(lambda entity: entity.a + entity.b)) + +Existing 0.3 ``dict``-like and freeform object derived +collection classes will need to be updated for the new API. +In most cases this is simply a matter of adding a couple +decorators to the class definition. + +Mapped Relations from External Tables/Subqueries +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This feature quietly appeared in 0.3 but has been improved +in 0.4 thanks to better ability to convert subqueries +against a table into subqueries against an alias of that +table; this is key for eager loading, aliased joins in +queries, etc. It reduces the need to create mappers against +select statements when you just need to add some extra +columns or subqueries: + +:: + + mapper(User, users, properties={ + 'fullname': column_property((users.c.firstname + users.c.lastname).label('fullname')), + 'numposts': column_property( + select([func.count(1)], users.c.id==posts.c.user_id).correlate(users).label('posts') + ) + }) + +a typical query looks like: + +:: + + SELECT (SELECT count(1) FROM posts WHERE users.id = posts.user_id) AS count, + users.firstname || users.lastname AS fullname, + users.id AS users_id, users.firstname AS users_firstname, users.lastname AS users_lastname + FROM users ORDER BY users.oid + +Horizontal Scaling (Sharding) API +--------------------------------- + +[browser:/sqlalchemy/trunk/examples/sharding/attribute_shard +.py] + +Sessions +-------- + +New Session Create Paradigm; SessionContext, assignmapper Deprecated +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +That's right, the whole shebang is being replaced with two +configurational functions. Using both will produce the most +0.1-ish feel we've had since 0.1 (i.e., the least amount of +typing). + +Configure your own ``Session`` class right where you define +your ``engine`` (or anywhere): + +:: + + from sqlalchemy import create_engine + from sqlalchemy.orm import sessionmaker + + engine = create_engine('myengine://') + Session = sessionmaker(bind=engine, autoflush=True, transactional=True) + + # use the new Session() freely + sess = Session() + sess.save(someobject) + sess.flush() + + +If you need to post-configure your Session, say with an +engine, add it later with ``configure()``: + +:: + + Session.configure(bind=create_engine(...)) + +All the behaviors of ``SessionContext`` and the ``query`` +and ``__init__`` methods of ``assignmapper`` are moved into +the new ``scoped_session()`` function, which is compatible +with both ``sessionmaker`` as well as ``create_session()``: + +:: + + from sqlalchemy.orm import scoped_session, sessionmaker + + Session = scoped_session(sessionmaker(autoflush=True, transactional=True)) + Session.configure(bind=engine) + + u = User(name='wendy') + + sess = Session() + sess.save(u) + sess.commit() + + # Session constructor is thread-locally scoped. Everyone gets the same + # Session in the thread when scope="thread". + sess2 = Session() + assert sess is sess2 + + +When using a thread-local ``Session``, the returned class +has all of ``Session's`` interface implemented as +classmethods, and "assignmapper"'s functionality is +available using the ``mapper`` classmethod. Just like the +old ``objectstore`` days.... + +:: + + + # "assignmapper"-like functionality available via ScopedSession.mapper + Session.mapper(User, users_table) + + u = User(name='wendy') + + Session.commit() + + +Sessions are again Weak Referencing By Default +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The weak_identity_map flag is now set to ``True`` by default +on Session. Instances which are externally deferenced and +fall out of scope are removed from the session +automatically. However, items which have "dirty" changes +present will remain strongly referenced until those changes +are flushed at which case the object reverts to being weakly +referenced (this works for 'mutable' types, like picklable +attributes, as well). Setting weak_identity_map to +``False`` restores the old strong-referencing behavior for +those of you using the session like a cache. + +Auto-Transactional Sessions +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As you might have noticed above, we are calling ``commit()`` +on ``Session``. The flag ``transactional=True`` means the +``Session`` is always in a transaction, ``commit()`` +persists permanently. + +Auto-Flushing Sessions +^^^^^^^^^^^^^^^^^^^^^^ + +Also, ``autoflush=True`` means the ``Session`` will +``flush()`` before each ``query`` as well as when you call +``flush()`` or ``commit()``. So now this will work: + +:: + + Session = sessionmaker(bind=engine, autoflush=True, transactional=True) + + u = User(name='wendy') + + sess = Session() + sess.save(u) + + # wendy is flushed, comes right back from a query + wendy = sess.query(User).filter_by(name='wendy').one() + +Transactional methods moved onto sessions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``commit()`` and ``rollback()``, as well as ``begin()`` are +now directly on ``Session``. No more need to use +``SessionTransaction`` for anything (it remains in the +background). + +:: + + Session = sessionmaker(autoflush=True, transactional=False) + + sess = Session() + sess.begin() + + # use the session + + sess.commit() # commit transaction + +Sharing a ``Session`` with an enclosing engine-level (i.e. +non-ORM) transaction is easy: + +:: + + Session = sessionmaker(autoflush=True, transactional=False) + + conn = engine.connect() + trans = conn.begin() + sess = Session(bind=conn) + + # ... session is transactional + + # commit the outermost transaction + trans.commit() + +Nested Session Transactions with SAVEPOINT +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Available at the Engine and ORM level. ORM docs so far: + +http://www.sqlalchemy.org/docs/04/session.html#unitofwork_ma +naging + +Two-Phase Commit Sessions +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Available at the Engine and ORM level. ORM docs so far: + +http://www.sqlalchemy.org/docs/04/session.html#unitofwork_ma +naging + +Inheritance +----------- + +Polymorphic Inheritance with No Joins or Unions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +New docs for inheritance: http://www.sqlalchemy.org/docs/04 +/mappers.html#advdatamapping_mapper_inheritance_joined + +Better Polymorphic Behavior with ``get()`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +All classes within a joined-table inheritance hierarchy get +an ``_instance_key`` using the base class, i.e. +``(BaseClass, (1, ), None)``. That way when you call +``get()`` a ``Query`` against the base class, it can locate +subclass instances in the current identity map without +querying the database. + +Types +----- + +Custom Subclasses of ``sqlalchemy.types.TypeDecorator`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +There is a `New API `_ for subclassing a TypeDecorator. +Using the 0.3 API causes compilation errors in some cases. + +SQL Expressions +=============== + +All New, Deterministic Label/Alias Generation +--------------------------------------------- + +All the "anonymous" labels and aliases use a simple +_ format now. SQL is much easier to read and +is compatible with plan optimizer caches. Just check out +some of the examples in the tutorials: +http://www.sqlalchemy.org/docs/04/ormtutorial.html +http://www.sqlalchemy.org/docs/04/sqlexpression.html + +Generative select() Constructs +------------------------------ + +This is definitely the way to go with ``select()``. See htt +p://www.sqlalchemy.org/docs/04/sqlexpression.html#sql_transf +orm . + +New Operator System +------------------- + +SQL operators and more or less every SQL keyword there is +are now abstracted into the compiler layer. They now act +intelligently and are type/backend aware, see: http://www.sq +lalchemy.org/docs/04/sqlexpression.html#sql_operators + +All ``type`` Keyword Arguments Renamed to ``type_`` +--------------------------------------------------- + +Just like it says: + +:: + + b = bindparam('foo', type_=String) + +in_ Function Changed to Accept Sequence or Selectable +----------------------------------------------------- + +The in_ function now takes a sequence of values or a +selectable as its sole argument. The previous API of passing +in values as positional arguments still works, but is now +deprecated. This means that + +:: + + my_table.select(my_table.c.id.in_(1,2,3) + my_table.select(my_table.c.id.in_(*listOfIds) + +should be changed to + +:: + + my_table.select(my_table.c.id.in_([1,2,3]) + my_table.select(my_table.c.id.in_(listOfIds) + +Schema and Reflection +===================== + +``MetaData``, ``BoundMetaData``, ``DynamicMetaData``... +------------------------------------------------------- + +In the 0.3.x series, ``BoundMetaData`` and +``DynamicMetaData`` were deprecated in favor of ``MetaData`` +and ``ThreadLocalMetaData``. The older names have been +removed in 0.4. Updating is simple: + +:: + + +-------------------------------------+-------------------------+ + |If You Had | Now Use | + +=====================================+=========================+ + | ``MetaData`` | ``MetaData`` | + +-------------------------------------+-------------------------+ + | ``BoundMetaData`` | ``MetaData`` | + +-------------------------------------+-------------------------+ + | ``DynamicMetaData`` (with one | ``MetaData`` | + | engine or threadlocal=False) | | + +-------------------------------------+-------------------------+ + | ``DynamicMetaData`` | ``ThreadLocalMetaData`` | + | (with different engines per thread) | | + +-------------------------------------+-------------------------+ + +The seldom-used ``name`` parameter to ``MetaData`` types has +been removed. The ``ThreadLocalMetaData`` constructor now +takes no arguments. Both types can now be bound to an +``Engine`` or a single ``Connection``. + +One Step Multi-Table Reflection +------------------------------- + +You can now load table definitions and automatically create +``Table`` objects from an entire database or schema in one +pass: + +:: + + >>> metadata = MetaData(myengine, reflect=True) + >>> metadata.tables.keys() + ['table_a', 'table_b', 'table_c', '...'] + +``MetaData`` also gains a ``.reflect()`` method enabling +finer control over the loading process, including +specification of a subset of available tables to load. + +SQL Execution +============= + +``engine``, ``connectable``, and ``bind_to`` are all now ``bind`` +----------------------------------------------------------------- + +``Transactions``, ``NestedTransactions`` and ``TwoPhaseTransactions`` +--------------------------------------------------------------------- + +Connection Pool Events +---------------------- + +The connection pool now fires events when new DB-API +connections are created, checked out and checked back into +the pool. You can use these to execute session-scoped SQL +setup statements on fresh connections, for example. + +Oracle Engine Fixed +------------------- + +In 0.3.11, there were bugs in the Oracle Engine on how +Primary Keys are handled. These bugs could cause programs +that worked fine with other engines, such as sqlite, to fail +when using the Oracle Engine. In 0.4, the Oracle Engine has +been reworked, fixing these Primary Key problems. + +Out Parameters for Oracle +------------------------- + +:: + + result = engine.execute(text("begin foo(:x, :y, :z); end;", bindparams=[bindparam('x', Numeric), outparam('y', Numeric), outparam('z', Numeric)]), x=5) + assert result.out_parameters == {'y':10, 'z':75} + +Connection-bound ``MetaData``, ``Sessions`` +------------------------------------------- + +``MetaData`` and ``Session`` can be explicitly bound to a +connection: + +:: + + conn = engine.connect() + sess = create_session(bind=conn) + +Faster, More Foolproof ``ResultProxy`` Objects +---------------------------------------------- + diff --git a/doc/build/changelog/migration_05.rst b/doc/build/changelog/migration_05.rst new file mode 100644 index 0000000000..c79f8b0f62 --- /dev/null +++ b/doc/build/changelog/migration_05.rst @@ -0,0 +1,746 @@ +============================= +What's new in SQLAlchemy 0.5? +============================= + +.. admonition:: About this Document + + This document describes changes between SQLAlchemy version 0.4, + last released October 12, 2008, and SQLAlchemy version 0.5, + last released January 16, 2010. + + Document date: August 4, 2009 + + +This guide documents API changes which affect users +migrating their applications from the 0.4 series of +SQLAlchemy to 0.5. It's also recommended for those working +from `Essential SQLAlchemy +`_, which only +covers 0.4 and seems to even have some old 0.3isms in it. +Note that SQLAlchemy 0.5 removes many behaviors which were +deprecated throughout the span of the 0.4 series, and also +deprecates more behaviors specific to 0.4. + +Major Documentation Changes +=========================== + +Some sections of the documentation have been completely +rewritten and can serve as an introduction to new ORM +features. The ``Query`` and ``Session`` objects in +particular have some distinct differences in API and +behavior which fundamentally change many of the basic ways +things are done, particularly with regards to constructing +highly customized ORM queries and dealing with stale session +state, commits and rollbacks. + +* `ORM Tutorial + `_ + +* `Session Documentation + `_ + +Deprecations Source +=================== + +Another source of information is documented within a series +of unit tests illustrating up to date usages of some common +``Query`` patterns; this file can be viewed at +[source:sqlalchemy/trunk/test/orm/test_deprecations.py]. + +Requirements Changes +==================== + +* Python 2.4 or higher is required. The SQLAlchemy 0.4 line + is the last version with Python 2.3 support. + +Object Relational Mapping +========================= + +* **Column level expressions within Query.** - as detailed + in the `tutorial + `_, + ``Query`` has the capability to create specific SELECT + statements, not just those against full rows: + + :: + + session.query(User.name, func.count(Address.id).label("numaddresses")).join(Address).group_by(User.name) + + The tuples returned by any multi-column/entity query are + *named*' tuples: + + :: + + for row in session.query(User.name, func.count(Address.id).label('numaddresses')).join(Address).group_by(User.name): + print "name", row.name, "number", row.numaddresses + + ``Query`` has a ``statement`` accessor, as well as a + ``subquery()`` method which allow ``Query`` to be used to + create more complex combinations: + + :: + + subq = session.query(Keyword.id.label('keyword_id')).filter(Keyword.name.in_(['beans', 'carrots'])).subquery() + recipes = session.query(Recipe).filter(exists(). + where(Recipe.id==recipe_keywords.c.recipe_id). + where(recipe_keywords.c.keyword_id==subq.c.keyword_id) + ) + +* **Explicit ORM aliases are recommended for aliased joins** + - The ``aliased()`` function produces an "alias" of a + class, which allows fine-grained control of aliases in + conjunction with ORM queries. While a table-level alias + (i.e. ``table.alias()``) is still usable, an ORM level + alias retains the semantics of the ORM mapped object which + is significant for inheritance mappings, options, and + other scenarios. E.g.: + + :: + + Friend = aliased(Person) + session.query(Person, Friend).join((Friend, Person.friends)).all() + +* **query.join() greatly enhanced.** - You can now specify + the target and ON clause for a join in multiple ways. A + target class alone can be provided where SQLA will attempt + to form a join to it via foreign key in the same way as + ``table.join(someothertable)``. A target and an explicit + ON condition can be provided, where the ON condition can + be a ``relation()`` name, an actual class descriptor, or a + SQL expression. Or the old way of just a ``relation()`` + name or class descriptor works too. See the ORM tutorial + which has several examples. + +* **Declarative is recommended for applications which don't + require (and don't prefer) abstraction between tables and + mappers** - The [/docs/05/reference/ext/declarative.html + Declarative] module, which is used to combine the + expression of ``Table``, ``mapper()``, and user defined + class objects together, is highly recommended as it + simplifies application configuration, ensures the "one + mapper per class" pattern, and allows the full range of + configuration available to distinct ``mapper()`` calls. + Separate ``mapper()`` and ``Table`` usage is now referred + to as "classical SQLAlchemy usage" and of course is freely + mixable with declarative. + +* **The .c. attribute has been removed** from classes (i.e. + ``MyClass.c.somecolumn``). As is the case in 0.4, class- + level properties are usable as query elements, i.e. + ``Class.c.propname`` is now superseded by + ``Class.propname``, and the ``c`` attribute continues to + remain on ``Table`` objects where they indicate the + namespace of ``Column`` objects present on the table. + + To get at the Table for a mapped class (if you didn't keep + it around already): + + :: + + table = class_mapper(someclass).mapped_table + + Iterate through columns: + + :: + + for col in table.c: + print col + + Work with a specific column: + + :: + + table.c.somecolumn + + The class-bound descriptors support the full set of Column + operators as well as the documented relation-oriented + operators like ``has()``, ``any()``, ``contains()``, etc. + + The reason for the hard removal of ``.c.`` is that in 0.5, + class-bound descriptors carry potentially different + meaning, as well as information regarding class mappings, + versus plain ``Column`` objects - and there are use cases + where you'd specifically want to use one or the other. + Generally, using class-bound descriptors invokes a set of + mapping/polymorphic aware translations, and using table- + bound columns does not. In 0.4, these translations were + applied across the board to all expressions, but 0.5 + differentiates completely between columns and mapped + descriptors, only applying translations to the latter. So + in many cases, particularly when dealing with joined table + inheritance configurations as well as when using + ``query()``, ``Class.propname`` and + ``table.c.colname`` are not interchangeable. + + For example, ``session.query(users.c.id, users.c.name)`` + is different versus ``session.query(User.id, User.name)``; + in the latter case, the ``Query`` is aware of the mapper + in use and further mapper-specific operations like + ``query.join()``, ``query.with_parent()`` etc. + may be used, but in the former case cannot. Additionally, + in polymorphic inheritance scenarios, the class-bound + descriptors refer to the columns present in the + polymorphic selectable in use, not necessarily the table + column which directly corresponds to the descriptor. For + example, a set of classes related by joined-table + inheritance to the ``person`` table along the + ``person_id`` column of each table will all have their + ``Class.person_id`` attribute mapped to the ``person_id`` + column in ``person``, and not their subclass table. + Version 0.4 would map this behavior onto table-bound + ``Column`` objects automatically. In 0.5, this automatic + conversion has been removed, so that you in fact *can* use + table-bound columns as a means to override the + translations which occur with polymorphic querying; this + allows ``Query`` to be able to create optimized selects + among joined-table or concrete-table inheritance setups, + as well as portable subqueries, etc. + +* **Session Now Synchronizes Automatically with + Transactions.** Session now synchronizes against the + transaction automatically by default, including autoflush + and autoexpire. A transaction is present at all times + unless disabled using the ``autocommit`` option. When all + three flags are set to their default, the Session recovers + gracefully after rollbacks and it's very difficult to get + stale data into the session. See the new Session + documentation for details. + +* **Implicit Order By Is Removed**. This will impact ORM + users who rely upon SA's "implicit ordering" behavior, + which states that all Query objects which don't have an + ``order_by()`` will ORDER BY the "id" or "oid" column of + the primary mapped table, and all lazy/eagerly loaded + collections apply a similar ordering. In 0.5, automatic + ordering must be explicitly configured on ``mapper()`` and + ``relation()`` objects (if desired), or otherwise when + using ``Query``. + + To convert an 0.4 mapping to 0.5, such that its ordering + behavior will be extremely similar to 0.4 or previous, use + the ``order_by`` setting on ``mapper()`` and + ``relation()``: + + :: + + mapper(User, users, properties={ + 'addresses':relation(Address, order_by=addresses.c.id) + }, order_by=users.c.id) + + To set ordering on a backref, use the ``backref()`` + function: + + :: + + 'keywords':relation(Keyword, secondary=item_keywords, + order_by=keywords.c.name, backref=backref('items', order_by=items.c.id)) + + Using declarative ? To help with the new ``order_by`` + requirement, ``order_by`` and friends can now be set using + strings which are evaluated in Python later on (this works + **only** with declarative, not plain mappers): + + :: + + class MyClass(MyDeclarativeBase): + ... + 'addresses':relation("Address", order_by="Address.id") + + It's generally a good idea to set ``order_by`` on + ``relation()s`` which load list-based collections of + items, since that ordering cannot otherwise be affected. + Other than that, the best practice is to use + ``Query.order_by()`` to control ordering of the primary + entities being loaded. + +* **Session is now + autoflush=True/autoexpire=True/autocommit=False.** - To + set it up, just call ``sessionmaker()`` with no arguments. + The name ``transactional=True`` is now + ``autocommit=False``. Flushes occur upon each query + issued (disable with ``autoflush=False``), within each + ``commit()`` (as always), and before each + ``begin_nested()`` (so rolling back to the SAVEPOINT is + meaningful). All objects are expired after each + ``commit()`` and after each ``rollback()``. After + rollback, pending objects are expunged, deleted objects + move back to persistent. These defaults work together + very nicely and there's really no more need for old + techniques like ``clear()`` (which is renamed to + ``expunge_all()`` as well). + + P.S.: sessions are now reusable after a ``rollback()``. + Scalar and collection attribute changes, adds and deletes + are all rolled back. + +* **session.add() replaces session.save(), session.update(), + session.save_or_update().** - the + ``session.add(someitem)`` and ``session.add_all([list of + items])`` methods replace ``save()``, ``update()``, and + ``save_or_update()``. Those methods will remain + deprecated throughout 0.5. + +* **backref configuration made less verbose.** - The + ``backref()`` function now uses the ``primaryjoin`` and + ``secondaryjoin`` arguments of the forwards-facing + ``relation()`` when they are not explicitly stated. It's + no longer necessary to specify + ``primaryjoin``/``secondaryjoin`` in both directions + separately. + +* **Simplified polymorphic options.** - The ORM's + "polymorphic load" behavior has been simplified. In 0.4, + mapper() had an argument called ``polymorphic_fetch`` + which could be configured as ``select`` or ``deferred``. + This option is removed; the mapper will now just defer any + columns which were not present in the SELECT statement. + The actual SELECT statement used is controlled by the + ``with_polymorphic`` mapper argument (which is also in 0.4 + and replaces ``select_table``), as well as the + ``with_polymorphic()`` method on ``Query`` (also in 0.4). + + An improvement to the deferred loading of inheriting + classes is that the mapper now produces the "optimized" + version of the SELECT statement in all cases; that is, if + class B inherits from A, and several attributes only + present on class B have been expired, the refresh + operation will only include B's table in the SELECT + statement and will not JOIN to A. + +* The ``execute()`` method on ``Session`` converts plain + strings into ``text()`` constructs, so that bind + parameters may all be specified as ":bindname" without + needing to call ``text()`` explicitly. If "raw" SQL is + desired here, use ``session.connection().execute("raw + text")``. + +* ``session.Query().iterate_instances()`` has been renamed + to just ``instances()``. The old ``instances()`` method + returning a list instead of an iterator no longer exists. + If you were relying on that behavior, you should use + ``list(your_query.instances())``. + +Extending the ORM +================= + +In 0.5 we're moving forward with more ways to modify and +extend the ORM. Heres a summary: + +* **MapperExtension.** - This is the classic extension + class, which remains. Methods which should rarely be + needed are ``create_instance()`` and + ``populate_instance()``. To control the initialization of + an object when it's loaded from the database, use the + ``reconstruct_instance()`` method, or more easily the + ``@reconstructor`` decorator described in the + documentation. + +* **SessionExtension.** - This is an easy to use extension + class for session events. In particular, it provides + ``before_flush()``, ``after_flush()`` and + ``after_flush_postexec()`` methods. It's usage is + recommended over ``MapperExtension.before_XXX`` in many + cases since within ``before_flush()`` you can modify the + flush plan of the session freely, something which cannot + be done from within ``MapperExtension``. + +* **AttributeExtension.** - This class is now part of the + public API, and allows the interception of userland events + on attributes, including attribute set and delete + operations, and collection appends and removes. It also + allows the value to be set or appended to be modified. + The ``@validates`` decorator, described in the + documentation, provides a quick way to mark any mapped + attributes as being "validated" by a particular class + method. + +* **Attribute Instrumentation Customization.** - An API is + provided for ambitious efforts to entirely replace + SQLAlchemy's attribute instrumentation, or just to augment + it in some cases. This API was produced for the purposes + of the Trellis toolkit, but is available as a public API. + Some examples are provided in the distribution in the + ``/examples/custom_attributes`` directory. + +Schema/Types +============ + +* **String with no length no longer generates TEXT, it + generates VARCHAR** - The ``String`` type no longer + magically converts into a ``Text`` type when specified + with no length. This only has an effect when CREATE TABLE + is issued, as it will issue ``VARCHAR`` with no length + parameter, which is not valid on many (but not all) + databases. To create a TEXT (or CLOB, i.e. unbounded + string) column, use the ``Text`` type. + +* **PickleType() with mutable=True requires an __eq__() + method** - The ``PickleType`` type needs to compare values + when mutable=True. The method of comparing + ``pickle.dumps()`` is inefficient and unreliable. If an + incoming object does not implement ``__eq__()`` and is + also not ``None``, the ``dumps()`` comparison is used but + a warning is raised. For types which implement + ``__eq__()`` which includes all dictionaries, lists, etc., + comparison will use ``==`` and is now reliable by default. + +* **convert_bind_param() and convert_result_value() methods + of TypeEngine/TypeDecorator are removed.** - The O'Reilly + book unfortunately documented these methods even though + they were deprecated post 0.3. For a user-defined type + which subclasses ``TypeEngine``, the ``bind_processor()`` + and ``result_processor()`` methods should be used for + bind/result processing. Any user defined type, whether + extending ``TypeEngine`` or ``TypeDecorator``, which uses + the old 0.3 style can be easily adapted to the new style + using the following adapter: + + :: + + class AdaptOldConvertMethods(object): + """A mixin which adapts 0.3-style convert_bind_param and + convert_result_value methods + + """ + def bind_processor(self, dialect): + def convert(value): + return self.convert_bind_param(value, dialect) + return convert + + def result_processor(self, dialect): + def convert(value): + return self.convert_result_value(value, dialect) + return convert + + def convert_result_value(self, value, dialect): + return value + + def convert_bind_param(self, value, dialect): + return value + + To use the above mixin: + + :: + + class MyType(AdaptOldConvertMethods, TypeEngine): + # ... + +* The ``quote`` flag on ``Column`` and ``Table`` as well as + the ``quote_schema`` flag on ``Table`` now control quoting + both positively and negatively. The default is ``None``, + meaning let regular quoting rules take effect. When + ``True``, quoting is forced on. When ``False``, quoting + is forced off. + +* Column ``DEFAULT`` value DDL can now be more conveniently + specified with ``Column(..., server_default='val')``, + deprecating ``Column(..., PassiveDefault('val'))``. + ``default=`` is now exclusively for Python-initiated + default values, and can coexist with server_default. A + new ``server_default=FetchedValue()`` replaces the + ``PassiveDefault('')`` idiom for marking columns as + subject to influence from external triggers and has no DDL + side effects. + +* SQLite's ``DateTime``, ``Time`` and ``Date`` types now + **only accept datetime objects, not strings** as bind + parameter input. If you'd like to create your own + "hybrid" type which accepts strings and returns results as + date objects (from whatever format you'd like), create a + ``TypeDecorator`` that builds on ``String``. If you only + want string-based dates, just use ``String``. + +* Additionally, the ``DateTime`` and ``Time`` types, when + used with SQLite, now represent the "microseconds" field + of the Python ``datetime.datetime`` object in the same + manner as ``str(datetime)`` - as fractional seconds, not a + count of microseconds. That is: + + :: + + dt = datetime.datetime(2008, 6, 27, 12, 0, 0, 125) # 125 usec + + # old way + '2008-06-27 12:00:00.125' + + # new way + '2008-06-27 12:00:00.000125' + + So if an existing SQLite file-based database intends to be + used across 0.4 and 0.5, you either have to upgrade the + datetime columns to store the new format (NOTE: please + test this, I'm pretty sure its correct): + + :: + + UPDATE mytable SET somedatecol = + substr(somedatecol, 0, 19) || '.' || substr((substr(somedatecol, 21, -1) / 1000000), 3, -1); + + or, enable "legacy" mode as follows: + + :: + + from sqlalchemy.databases.sqlite import DateTimeMixin + DateTimeMixin.__legacy_microseconds__ = True + +Connection Pool no longer threadlocal by default +================================================ + +0.4 has an unfortunate default setting of +"pool_threadlocal=True", leading to surprise behavior when, +for example, using multiple Sessions within a single thread. +This flag is now off in 0.5. To re-enable 0.4's behavior, +specify ``pool_threadlocal=True`` to ``create_engine()``, or +alternatively use the "threadlocal" strategy via +``strategy="threadlocal"``. + +\*args Accepted, \*args No Longer Accepted +========================================== + +The policy with ``method(\*args)`` vs. ``method([args])`` +is, if the method accepts a variable-length set of items +which represent a fixed structure, it takes ``\*args``. If +the method accepts a variable-length set of items that are +data-driven, it takes ``[args]``. + +* The various Query.options() functions ``eagerload()``, + ``eagerload_all()``, ``lazyload()``, ``contains_eager()``, + ``defer()``, ``undefer()`` all accept variable-length + ``\*keys`` as their argument now, which allows a path to + be formulated using descriptors, ie.: + + :: + + query.options(eagerload_all(User.orders, Order.items, Item.keywords)) + + A single array argument is still accepted for backwards + compatibility. + +* Similarly, the ``Query.join()`` and ``Query.outerjoin()`` + methods accept a variable length \*args, with a single + array accepted for backwards compatibility: + + :: + + query.join('orders', 'items') + query.join(User.orders, Order.items) + +* the ``in_()`` method on columns and similar only accepts a + list argument now. It no longer accepts ``\*args``. + +Removed +======= + +* **entity_name** - This feature was always problematic and + rarely used. 0.5's more deeply fleshed out use cases + revealed further issues with ``entity_name`` which led to + its removal. If different mappings are required for a + single class, break the class into separate subclasses and + map them separately. An example of this is at + [wiki:UsageRecipes/EntityName]. More information + regarding rationale is described at http://groups.google.c + om/group/sqlalchemy/browse_thread/thread/9e23a0641a88b96d? + hl=en . + +* **get()/load() cleanup** + + + The ``load()`` method has been removed. It's + functionality was kind of arbitrary and basically copied + from Hibernate, where it's also not a particularly + meaningful method. + + To get equivalent functionality: + + :: + + x = session.query(SomeClass).populate_existing().get(7) + + ``Session.get(cls, id)`` and ``Session.load(cls, id)`` + have been removed. ``Session.get()`` is redundant vs. + ``session.query(cls).get(id)``. + + ``MapperExtension.get()`` is also removed (as is + ``MapperExtension.load()``). To override the + functionality of ``Query.get()``, use a subclass: + + :: + + class MyQuery(Query): + def get(self, ident): + # ... + + session = sessionmaker(query_cls=MyQuery)() + + ad1 = session.query(Address).get(1) + +* ``sqlalchemy.orm.relation()`` + + + The following deprecated keyword arguments have been + removed: + + foreignkey, association, private, attributeext, is_backref + + In particular, ``attributeext`` is replaced with + ``extension`` - the ``AttributeExtension`` class is now in + the public API. + +* ``session.Query()`` + + + The following deprecated functions have been removed: + + list, scalar, count_by, select_whereclause, get_by, + select_by, join_by, selectfirst, selectone, select, + execute, select_statement, select_text, join_to, join_via, + selectfirst_by, selectone_by, apply_max, apply_min, + apply_avg, apply_sum + + Additionally, the ``id`` keyword argument to ``join()``, + ``outerjoin()``, ``add_entity()`` and ``add_column()`` has + been removed. To target table aliases in ``Query`` to + result columns, use the ``aliased`` construct: + + :: + + from sqlalchemy.orm import aliased + address_alias = aliased(Address) + print session.query(User, address_alias).join((address_alias, User.addresses)).all() + +* ``sqlalchemy.orm.Mapper`` + + + * instances() + + + * get_session() - this method was not very noticeable, but + had the effect of associating lazy loads with a + particular session even if the parent object was + entirely detached, when an extension such as + ``scoped_session()`` or the old ``SessionContextExt`` + was used. It's possible that some applications which + relied upon this behavior will no longer work as + expected; but the better programming practice here is + to always ensure objects are present within sessions if + database access from their attributes are required. + +* ``mapper(MyClass, mytable)`` + + + Mapped classes no are longer instrumented with a "c" class + attribute; e.g. ``MyClass.c`` + +* ``sqlalchemy.orm.collections`` + + + The _prepare_instrumentation alias for + prepare_instrumentation has been removed. + +* ``sqlalchemy.orm`` + + + Removed the ``EXT_PASS`` alias of ``EXT_CONTINUE``. + +* ``sqlalchemy.engine`` + + + The alias from ``DefaultDialect.preexecute_sequences`` to + ``.preexecute_pk_sequences`` has been removed. + + The deprecated engine_descriptors() function has been + removed. + +* ``sqlalchemy.ext.activemapper`` + + + Module removed. + +* ``sqlalchemy.ext.assignmapper`` + + + Module removed. + +* ``sqlalchemy.ext.associationproxy`` + + + Pass-through of keyword args on the proxy's + ``.append(item, \**kw)`` has been removed and is now + simply ``.append(item)`` + +* ``sqlalchemy.ext.selectresults``, + ``sqlalchemy.mods.selectresults`` + + Modules removed. + +* ``sqlalchemy.ext.declarative`` + + + ``declared_synonym()`` removed. + +* ``sqlalchemy.ext.sessioncontext`` + + + Module removed. + +* ``sqlalchemy.log`` + + + The ``SADeprecationWarning`` alias to + ``sqlalchemy.exc.SADeprecationWarning`` has been removed. + +* ``sqlalchemy.exc`` + + + ``exc.AssertionError`` has been removed and usage replaced + by the Python built-in of the same name. + +* ``sqlalchemy.databases.mysql`` + + + The deprecated ``get_version_info`` dialect method has + been removed. + +Renamed or Moved +================ + +* ``sqlalchemy.exceptions`` is now ``sqlalchemy.exc`` + + + The module may still be imported under the old name until + 0.6. + +* ``FlushError``, ``ConcurrentModificationError``, + ``UnmappedColumnError`` -> sqlalchemy.orm.exc + + These exceptions moved to the orm package. Importing + 'sqlalchemy.orm' will install aliases in sqlalchemy.exc + for compatibility until 0.6. + +* ``sqlalchemy.logging`` -> ``sqlalchemy.log`` + + + This internal module was renamed. No longer needs to be + special cased when packaging SA with py2app and similar + tools that scan imports. + +* ``session.Query().iterate_instances()`` -> + ``session.Query().instances()``. + +Deprecated +========== + +* ``Session.save()``, ``Session.update()``, + ``Session.save_or_update()`` + + All three replaced by ``Session.add()`` + +* ``sqlalchemy.PassiveDefault`` + + + Use ``Column(server_default=...)`` Translates to + sqlalchemy.DefaultClause() under the hood. + +* ``session.Query().iterate_instances()``. It has been + renamed to ``instances()``. + diff --git a/doc/build/changelog/migration_06.rst b/doc/build/changelog/migration_06.rst new file mode 100644 index 0000000000..d561452e2b --- /dev/null +++ b/doc/build/changelog/migration_06.rst @@ -0,0 +1,1228 @@ +============================== +What's New in SQLAlchemy 0.6 ? +============================== + +.. admonition:: About this Document + + This document describes changes between SQLAlchemy version 0.5, + last released January 16, 2010, and SQLAlchemy version 0.6, + last released May 5, 2012. + + Document date: June 6, 2010 + +This guide documents API changes which affect users +migrating their applications from the 0.5 series of +SQLAlchemy to 0.6. Note that SQLAlchemy 0.6 removes some +behaviors which were deprecated throughout the span of the +0.5 series, and also deprecates more behaviors specific to +0.5. + +Platform Support +================ + +* cPython versions 2.4 and upwards throughout the 2.xx + series + +* Jython 2.5.1 - using the zxJDBC DBAPI included with + Jython. + +* cPython 3.x - see [source:sqlalchemy/trunk/README.py3k] + for information on how to build for python3. + +New Dialect System +================== + +Dialect modules are now broken up into distinct +subcomponents, within the scope of a single database +backend. Dialect implementations are now in the +``sqlalchemy.dialects`` package. The +``sqlalchemy.databases`` package still exists as a +placeholder to provide some level of backwards compatibility +for simple imports. + +For each supported database, a sub-package exists within +``sqlalchemy.dialects`` where several files are contained. +Each package contains a module called ``base.py`` which +defines the specific SQL dialect used by that database. It +also contains one or more "driver" modules, each one +corresponding to a specific DBAPI - these files are named +corresponding to the DBAPI itself, such as ``pysqlite``, +``cx_oracle``, or ``pyodbc``. The classes used by +SQLAlchemy dialects are first declared in the ``base.py`` +module, defining all behavioral characteristics defined by +the database. These include capability mappings, such as +"supports sequences", "supports returning", etc., type +definitions, and SQL compilation rules. Each "driver" +module in turn provides subclasses of those classes as +needed which override the default behavior to accommodate +the additional features, behaviors, and quirks of that +DBAPI. For DBAPIs that support multiple backends (pyodbc, +zxJDBC, mxODBC), the dialect module will use mixins from the +``sqlalchemy.connectors`` package, which provide +functionality common to that DBAPI across all backends, most +typically dealing with connect arguments. This means that +connecting using pyodbc, zxJDBC or mxODBC (when implemented) +is extremely consistent across supported backends. + +The URL format used by ``create_engine()`` has been enhanced +to handle any number of DBAPIs for a particular backend, +using a scheme that is inspired by that of JDBC. The +previous format still works, and will select a "default" +DBAPI implementation, such as the Postgresql URL below that +will use psycopg2: + +:: + + create_engine('postgresql://scott:tiger@localhost/test') + +However to specify a specific DBAPI backend such as pg8000, +add it to the "protocol" section of the URL using a plus +sign "+": + +:: + + create_engine('postgresql+pg8000://scott:tiger@localhost/test') + +Important Dialect Links: + +* Documentation on connect arguments: + http://www.sqlalchemy.org/docs/06/dbengine.html#create- + engine-url-arguments. + +* Reference documentation for individual dialects: http://ww + w.sqlalchemy.org/docs/06/reference/dialects/index.html + +* The tips and tricks at DatabaseNotes. + + +Other notes regarding dialects: + +* the type system has been changed dramatically in + SQLAlchemy 0.6. This has an impact on all dialects + regarding naming conventions, behaviors, and + implementations. See the section on "Types" below. + +* the ``ResultProxy`` object now offers a 2x speed + improvement in some cases thanks to some refactorings. + +* the ``RowProxy``, i.e. individual result row object, is + now directly pickleable. + +* the setuptools entrypoint used to locate external dialects + is now called ``sqlalchemy.dialects``. An external + dialect written against 0.4 or 0.5 will need to be + modified to work with 0.6 in any case so this change does + not add any additional difficulties. + +* dialects now receive an initialize() event on initial + connection to determine connection properties. + +* Functions and operators generated by the compiler now use + (almost) regular dispatch functions of the form + "visit_" and "visit__fn" to provide + customed processing. This replaces the need to copy the + "functions" and "operators" dictionaries in compiler + subclasses with straightforward visitor methods, and also + allows compiler subclasses complete control over + rendering, as the full _Function or _BinaryExpression + object is passed in. + +Dialect Imports +--------------- + +The import structure of dialects has changed. Each dialect +now exports its base "dialect" class as well as the full set +of SQL types supported on that dialect via +``sqlalchemy.dialects.``. For example, to import a +set of PG types: + +:: + + from sqlalchemy.dialects.postgresql import INTEGER, BIGINT, SMALLINT,\ + VARCHAR, MACADDR, DATE, BYTEA + +Above, ``INTEGER`` is actually the plain ``INTEGER`` type +from ``sqlalchemy.types``, but the PG dialect makes it +available in the same way as those types which are specific +to PG, such as ``BYTEA`` and ``MACADDR``. + +Expression Language Changes +=========================== + +An Important Expression Language Gotcha +--------------------------------------- + +There's one quite significant behavioral change to the +expression language which may affect some applications. +The boolean value of Python boolean expressions, i.e. +``==``, ``!=``, and similar, now evaluates accurately with +regards to the two clause objects being compared. + +As we know, comparing a ``ClauseElement`` to any other +object returns another ``ClauseElement``: + +:: + + >>> from sqlalchemy.sql import column + >>> column('foo') == 5 + + +This so that Python expressions produce SQL expressions when +converted to strings: + +:: + + >>> str(column('foo') == 5) + 'foo = :foo_1' + +But what happens if we say this? + +:: + + >>> if column('foo') == 5: + ... print "yes" + ... + +In previous versions of SQLAlchemy, the returned +``_BinaryExpression`` was a plain Python object which +evaluated to ``True``. Now it evaluates to whether or not +the actual ``ClauseElement`` should have the same hash value +as to that being compared. Meaning: + +:: + + >>> bool(column('foo') == 5) + False + >>> bool(column('foo') == column('foo')) + False + >>> c = column('foo') + >>> bool(c == c) + True + >>> + +That means code such as the following: + +:: + + if expression: + print "the expression is:", expression + +Would not evaluate if ``expression`` was a binary clause. +Since the above pattern should never be used, the base +``ClauseElement`` now raises an exception if called in a +boolean context: + +:: + + >>> bool(c) + Traceback (most recent call last): + File "", line 1, in + ... + raise TypeError("Boolean value of this clause is not defined") + TypeError: Boolean value of this clause is not defined + +Code that wants to check for the presence of a +``ClauseElement`` expression should instead say: + +:: + + if expression is not None: + print "the expression is:", expression + +Keep in mind, **this applies to Table and Column objects +too**. + +The rationale for the change is twofold: + +* Comparisons of the form ``if c1 == c2: `` + can actually be written now + +* Support for correct hashing of ``ClauseElement`` objects + now works on alternate platforms, namely Jython. Up until + this point SQLAlchemy relied heavily on the specific + behavior of cPython in this regard (and still had + occasional problems with it). + +Stricter "executemany" Behavior +------------------------------- + +An "executemany" in SQLAlchemy corresponds to a call to +``execute()``, passing along a collection of bind parameter +sets: + +:: + + connection.execute(table.insert(), {'data':'row1'}, {'data':'row2'}, {'data':'row3'}) + +When the ``Connection`` object sends off the given +``insert()`` construct for compilation, it passes to the +compiler the keynames present in the first set of binds +passed along to determine the construction of the +statement's VALUES clause. Users familiar with this +construct will know that additional keys present in the +remaining dictionaries don't have any impact. What's +different now is that all subsequent dictionaries need to +include at least *every* key that is present in the first +dictionary. This means that a call like this no longer +works: + +:: + + connection.execute(table.insert(), + {'timestamp':today, 'data':'row1'}, + {'timestamp':today, 'data':'row2'}, + {'data':'row3'}) + +Because the third row does not specify the 'timestamp' +column. Previous versions of SQLAlchemy would simply insert +NULL for these missing columns. However, if the +``timestamp`` column in the above example contained a +Python-side default value or function, it would *not* be +used. This because the "executemany" operation is optimized +for maximum performance across huge numbers of parameter +sets, and does not attempt to evaluate Python-side defaults +for those missing keys. Because defaults are often +implemented either as SQL expressions which are embedded +inline with the INSERT statement, or are server side +expressions which again are triggered based on the structure +of the INSERT string, which by definition cannot fire off +conditionally based on each parameter set, it would be +inconsistent for Python side defaults to behave differently +vs. SQL/server side defaults. (SQL expression based +defaults are embedded inline as of the 0.5 series, again to +minimize the impact of huge numbers of parameter sets). + +SQLAlchemy 0.6 therefore establishes predictable consistency +by forbidding any subsequent parameter sets from leaving any +fields blank. That way, there's no more silent failure of +Python side default values and functions, which additionally +are allowed to remain consistent in their behavior versus +SQL and server side defaults. + +UNION and other "compound" constructs parenthesize consistently +--------------------------------------------------------------- + +A rule that was designed to help SQLite has been removed, +that of the first compound element within another compound +(such as, a ``union()`` inside of an ``except_()``) wouldn't +be parenthesized. This is inconsistent and produces the +wrong results on Postgresql, which has precedence rules +regarding INTERSECTION, and its generally a surprise. When +using complex composites with SQLite, you now need to turn +the first element into a subquery (which is also compatible +on PG). A new example is in the SQL expression tutorial at +the end of +[http://www.sqlalchemy.org/docs/06/sqlexpression.html +#unions-and-other-set-operations]. See :ticket:`1665` and +r6690 for more background. + +C Extensions for Result Fetching +================================ + +The ``ResultProxy`` and related elements, including most +common "row processing" functions such as unicode +conversion, numerical/boolean conversions and date parsing, +have been re-implemented as optional C extensions for the +purposes of performance. This represents the beginning of +SQLAlchemy's path to the "dark side" where we hope to +continue improving performance by reimplementing critical +sections in C. The extensions can be built by specifying +``--with-cextensions``, i.e. ``python setup.py --with- +cextensions install``. + +The extensions have the most dramatic impact on result +fetching using direct ``ResultProxy`` access, i.e. that +which is returned by ``engine.execute()``, +``connection.execute()``, or ``session.execute()``. Within +results returned by an ORM ``Query`` object, result fetching +is not as high a percentage of overhead, so ORM performance +improves more modestly, and mostly in the realm of fetching +large result sets. The performance improvements highly +depend on the dbapi in use and on the syntax used to access +the columns of each row (eg ``row['name']`` is much faster +than ``row.name``). The current extensions have no impact +on the speed of inserts/updates/deletes, nor do they improve +the latency of SQL execution, that is, an application that +spends most of its time executing many statements with very +small result sets will not see much improvement. + +Performance has been improved in 0.6 versus 0.5 regardless +of the extensions. A quick overview of what connecting and +fetching 50,000 rows looks like with SQLite, using mostly +direct SQLite access, a ``ResultProxy``, and a simple mapped +ORM object: + +:: + + sqlite select/native: 0.260s + + 0.6 / C extension + + sqlalchemy.sql select: 0.360s + sqlalchemy.orm fetch: 2.500s + + 0.6 / Pure Python + + sqlalchemy.sql select: 0.600s + sqlalchemy.orm fetch: 3.000s + + 0.5 / Pure Python + + sqlalchemy.sql select: 0.790s + sqlalchemy.orm fetch: 4.030s + +Above, the ORM fetches the rows 33% faster than 0.5 due to +in-python performance enhancements. With the C extensions +we get another 20%. However, ``ResultProxy`` fetches +improve by 67% with the C extension versus not. Other +tests report as much as a 200% speed improvement for some +scenarios, such as those where lots of string conversions +are occurring. + +New Schema Capabilities +======================= + +The ``sqlalchemy.schema`` package has received some long- +needed attention. The most visible change is the newly +expanded DDL system. In SQLAlchemy, it was possible since +version 0.5 to create custom DDL strings and associate them +with tables or metadata objects: + +:: + + from sqlalchemy.schema import DDL + + DDL('CREATE TRIGGER users_trigger ...').execute_at('after-create', metadata) + +Now the full suite of DDL constructs are available under the +same system, including those for CREATE TABLE, ADD +CONSTRAINT, etc.: + +:: + + from sqlalchemy.schema import Constraint, AddConstraint + + AddContraint(CheckConstraint("value > 5")).execute_at('after-create', mytable) + +Additionally, all the DDL objects are now regular +``ClauseElement`` objects just like any other SQLAlchemy +expression object: + +:: + + from sqlalchemy.schema import CreateTable + + create = CreateTable(mytable) + + # dumps the CREATE TABLE as a string + print create + + # executes the CREATE TABLE statement + engine.execute(create) + +and using the ``sqlalchemy.ext.compiler`` extension you can +make your own: + +:: + + from sqlalchemy.schema import DDLElement + from sqlalchemy.ext.compiler import compiles + + class AlterColumn(DDLElement): + + def __init__(self, column, cmd): + self.column = column + self.cmd = cmd + + @compiles(AlterColumn) + def visit_alter_column(element, compiler, **kw): + return "ALTER TABLE %s ALTER COLUMN %s %s ..." % ( + element.column.table.name, + element.column.name, + element.cmd + ) + + engine.execute(AlterColumn(table.c.mycolumn, "SET DEFAULT 'test'")) + +Deprecated/Removed Schema Elements +---------------------------------- + +The schema package has also been greatly streamlined. Many +options and methods which were deprecated throughout 0.5 +have been removed. Other little known accessors and methods +have also been removed. + +* the "owner" keyword argument is removed from ``Table``. + Use "schema" to represent any namespaces to be prepended + to the table name. + +* deprecated ``MetaData.connect()`` and + ``ThreadLocalMetaData.connect()`` have been removed - send + the "bind" attribute to bind a metadata. + +* deprecated metadata.table_iterator() method removed (use + sorted_tables) + +* the "metadata" argument is removed from + ``DefaultGenerator`` and subclasses, but remains locally + present on ``Sequence``, which is a standalone construct + in DDL. + +* deprecated ``PassiveDefault`` - use ``DefaultClause``. + + +* Removed public mutability from ``Index`` and + ``Constraint`` objects: + + * ``ForeignKeyConstraint.append_element()`` + + + * ``Index.append_column()`` + + + * ``UniqueConstraint.append_column()`` + + + * ``PrimaryKeyConstraint.add()`` + + + * ``PrimaryKeyConstraint.remove()`` + + +These should be constructed declaratively (i.e. in one +construction). + +* Other removed things: + + + * ``Table.key`` (no idea what this was for) + + + * ``Column.bind`` (get via column.table.bind) + + + * ``Column.metadata`` (get via column.table.metadata) + + + * ``Column.sequence`` (use column.default) + + +Other Behavioral Changes +------------------------ + +* ``UniqueConstraint``, ``Index``, ``PrimaryKeyConstraint`` + all accept lists of column names or column objects as + arguments. + +* The ``use_alter`` flag on ``ForeignKey`` is now a shortcut + option for operations that can be hand-constructed using + the ``DDL()`` event system. A side effect of this refactor + is that ``ForeignKeyConstraint`` objects with + ``use_alter=True`` will *not* be emitted on SQLite, which + does not support ALTER for foreign keys. This has no + effect on SQLite's behavior since SQLite does not actually + honor FOREIGN KEY constraints. + +* ``Table.primary_key`` is not assignable - use + ``table.append_constraint(PrimaryKeyConstraint(...))`` + +* A ``Column`` definition with a ``ForeignKey`` and no type, + e.g. ``Column(name, ForeignKey(sometable.c.somecol))`` + used to get the type of the referenced column. Now support + for that automatic type inference is partial and may not + work in all cases. + +Logging opened up +================= + +At the expense of a few extra method calls here and there, +you can set log levels for INFO and DEBUG after an engine, +pool, or mapper has been created, and logging will commence. +The ``isEnabledFor(INFO)`` method is now called +per-``Connection`` and ``isEnabledFor(DEBUG)`` +per-``ResultProxy`` if already enabled on the parent +connection. Pool logging sends to ``log.info()`` and +``log.debug()`` with no check - note that pool +checkout/checkin is typically once per transaction. + +Reflection/Inspector API +======================== + +The reflection system, which allows reflection of table +columns via ``Table('sometable', metadata, autoload=True)`` +has been opened up into its own fine-grained API, which +allows direct inspection of database elements such as +tables, columns, constraints, indexes, and more. This API +expresses return values as simple lists of strings, +dictionaries, and ``TypeEngine`` objects. The internals of +``autoload=True`` now build upon this system such that the +translation of raw database information into +``sqlalchemy.schema`` constructs is centralized and the +contract of individual dialects greatly simplified, vastly +reducing bugs and inconsistencies across different backends. + +To use an inspector: + +:: + + from sqlalchemy.engine.reflection import Inspector + insp = Inspector.from_engine(my_engine) + + print insp.get_schema_names() + +the ``from_engine()`` method will in some cases provide a +backend-specific inspector with additional capabilities, +such as that of Postgresql which provides a +``get_table_oid()`` method: + +:: + + + my_engine = create_engine('postgresql://...') + pg_insp = Inspector.from_engine(my_engine) + + print pg_insp.get_table_oid('my_table') + +RETURNING Support +================= + +The ``insert()``, ``update()`` and ``delete()`` constructs +now support a ``returning()`` method, which corresponds to +the SQL RETURNING clause as supported by Postgresql, Oracle, +MS-SQL, and Firebird. It is not supported for any other +backend at this time. + +Given a list of column expressions in the same manner as +that of a ``select()`` construct, the values of these +columns will be returned as a regular result set: + +:: + + + result = connection.execute( + table.insert().values(data='some data').returning(table.c.id, table.c.timestamp) + ) + row = result.first() + print "ID:", row['id'], "Timestamp:", row['timestamp'] + +The implementation of RETURNING across the four supported +backends varies wildly, in the case of Oracle requiring an +intricate usage of OUT parameters which are re-routed into a +"mock" result set, and in the case of MS-SQL using an +awkward SQL syntax. The usage of RETURNING is subject to +limitations: + +* it does not work for any "executemany()" style of + execution. This is a limitation of all supported DBAPIs. + +* Some backends, such as Oracle, only support RETURNING that + returns a single row - this includes UPDATE and DELETE + statements, meaning the update() or delete() construct + must match only a single row, or an error is raised (by + Oracle, not SQLAlchemy). + +RETURNING is also used automatically by SQLAlchemy, when +available and when not otherwise specified by an explicit +``returning()`` call, to fetch the value of newly generated +primary key values for single-row INSERT statements. This +means there's no more "SELECT nextval(sequence)" pre- +execution for insert statements where the primary key value +is required. Truth be told, implicit RETURNING feature +does incur more method overhead than the old "select +nextval()" system, which used a quick and dirty +cursor.execute() to get at the sequence value, and in the +case of Oracle requires additional binding of out +parameters. So if method/protocol overhead is proving to be +more expensive than additional database round trips, the +feature can be disabled by specifying +``implicit_returning=False`` to ``create_engine()``. + +Type System Changes +=================== + +New Archicture +-------------- + +The type system has been completely reworked behind the +scenes to provide two goals: + +* Separate the handling of bind parameters and result row + values, typically a DBAPI requirement, from the SQL + specification of the type itself, which is a database + requirement. This is consistent with the overall dialect + refactor that separates database SQL behavior from DBAPI. + +* Establish a clear and consistent contract for generating + DDL from a ``TypeEngine`` object and for constructing + ``TypeEngine`` objects based on column reflection. + +Highlights of these changes include: + +* The construction of types within dialects has been totally + overhauled. Dialects now define publically available types + as UPPERCASE names exclusively, and internal + implementation types using underscore identifiers (i.e. + are private). The system by which types are expressed in + SQL and DDL has been moved to the compiler system. This + has the effect that there are much fewer type objects + within most dialects. A detailed document on this + architecture for dialect authors is in [source:/lib/sqlalc + hemy/dialects/type_migration_guidelines.txt]. + +* Reflection of types now returns the exact UPPERCASE type + within types.py, or the UPPERCASE type within the dialect + itself if the type is not a standard SQL type. This means + reflection now returns more accurate information about + reflected types. + +* User defined types that subclass ``TypeEngine`` and wish + to provide ``get_col_spec()`` should now subclass + ``UserDefinedType``. + +* The ``result_processor()`` method on all type classes now + accepts an additional argument ``coltype``. This is the + DBAPI type object attached to cursor.description, and + should be used when applicable to make better decisions on + what kind of result-processing callable should be + returned. Ideally result processor functions would never + need to use ``isinstance()``, which is an expensive call + at this level. + +Native Unicode Mode +------------------- + +As more DBAPIs support returning Python unicode objects +directly, the base dialect now performs a check upon the +first connection which establishes whether or not the DBAPI +returns a Python unicode object for a basic select of a +VARCHAR value. If so, the ``String`` type and all +subclasses (i.e. ``Text``, ``Unicode``, etc.) will skip the +"unicode" check/conversion step when result rows are +received. This offers a dramatic performance increase for +large result sets. The "unicode mode" currently is known to +work with: + +* sqlite3 / pysqlite + + +* psycopg2 - SQLA 0.6 now uses the "UNICODE" type extension + by default on each psycopg2 connection object + +* pg8000 + + +* cx_oracle (we use an output processor - nice feature !) + + +Other types may choose to disable unicode processing as +needed, such as the ``NVARCHAR`` type when used with MS-SQL. + +In particular, if porting an application based on a DBAPI +that formerly returned non-unicode strings, the "native +unicode" mode has a plainly different default behavior - +columns that are declared as ``String`` or ``VARCHAR`` now +return unicode by default whereas they would return strings +before. This can break code which expects non-unicode +strings. The psycopg2 "native unicode" mode can be +disabled by passing ``use_native_unicode=False`` to +``create_engine()``. + +A more general solution for string columns that explicitly +do not want a unicode object is to use a ``TypeDecorator`` +that converts unicode back to utf-8, or whatever is desired: + +:: + + class UTF8Encoded(TypeDecorator): + """Unicode type which coerces to utf-8.""" + + impl = sa.VARCHAR + + def process_result_value(self, value, dialect): + if isinstance(value, unicode): + value = value.encode('utf-8') + return value + +Note that the ``assert_unicode`` flag is now deprecated. +SQLAlchemy allows the DBAPI and backend database in use to +handle Unicode parameters when available, and does not add +operational overhead by checking the incoming type; modern +systems like sqlite and Postgresql will raise an encoding +error on their end if invalid data is passed. In those +cases where SQLAlchemy does need to coerce a bind parameter +from Python Unicode to an encoded string, or when the +Unicode type is used explicitly, a warning is raised if the +object is a bytestring. This warning can be suppressed or +converted to an exception using the Python warnings filter +documented at: http://docs.python.org/library/warnings.html + +Generic Enum Type +----------------- + +We now have an ``Enum`` in the ``types`` module. This is a +string type that is given a collection of "labels" which +constrain the possible values given to those labels. By +default, this type generates a ``VARCHAR`` using the size of +the largest label, and applies a CHECK constraint to the +table within the CREATE TABLE statement. When using MySQL, +the type by default uses MySQL's ENUM type, and when using +Postgresql the type will generate a user defined type using +``CREATE TYPE AS ENUM``. In order to create the +type using Postgresql, the ``name`` parameter must be +specified to the constructor. The type also accepts a +``native_enum=False`` option which will issue the +VARCHAR/CHECK strategy for all databases. Note that +Postgresql ENUM types currently don't work with pg8000 or +zxjdbc. + +Reflection Returns Dialect-Specific Types +----------------------------------------- + +Reflection now returns the most specific type possible from +the database. That is, if you create a table using +``String``, then reflect it back, the reflected column will +likely be ``VARCHAR``. For dialects that support a more +specific form of the type, that's what you'll get. So a +``Text`` type would come back as ``oracle.CLOB`` on Oracle, +a ``LargeBinary`` might be an ``mysql.MEDIUMBLOB`` etc. The +obvious advantage here is that reflection preserves as much +information possible from what the database had to say. + +Some applications that deal heavily in table metadata may +wish to compare types across reflected tables and/or non- +reflected tables. There's a semi-private accessor available +on ``TypeEngine`` called ``_type_affinity`` and an +associated comparison helper ``_compare_type_affinity``. +This accessor returns the "generic" ``types`` class which +the type corresponds to: + +:: + + >>> String(50)._compare_type_affinity(postgresql.VARCHAR(50)) + True + >>> Integer()._compare_type_affinity(mysql.REAL) + False + +Miscellaneous API Changes +------------------------- + +The usual "generic" types are still the general system in +use, i.e. ``String``, ``Float``, ``DateTime``. There's a +few changes there: + +* Types no longer make any guesses as to default parameters. + In particular, ``Numeric``, ``Float``, as well as + subclasses NUMERIC, FLOAT, DECIMAL don't generate any + length or scale unless specified. This also continues to + include the controversial ``String`` and ``VARCHAR`` types + (although MySQL dialect will pre-emptively raise when + asked to render VARCHAR with no length). No defaults are + assumed, and if they are used in a CREATE TABLE statement, + an error will be raised if the underlying database does + not allow non-lengthed versions of these types. + +* the ``Binary`` type has been renamed to ``LargeBinary``, + for BLOB/BYTEA/similar types. For ``BINARY`` and + ``VARBINARY``, those are present directly as + ``types.BINARY``, ``types.VARBINARY``, as well as in the + MySQL and MS-SQL dialects. + +* ``PickleType`` now uses == for comparison of values when + mutable=True, unless the "comparator" argument with a + comparison function is specified to the type. If you are + pickling a custom object you should implement an + ``__eq__()`` method so that value-based comparisons are + accurate. + +* The default "precision" and "scale" arguments of Numeric + and Float have been removed and now default to None. + NUMERIC and FLOAT will be rendered with no numeric + arguments by default unless these values are provided. + +* DATE, TIME and DATETIME types on SQLite can now take + optional "storage_format" and "regexp" argument. + "storage_format" can be used to store those types using a + custom string format. "regexp" allows to use a custom + regular expression to match string values from the + database. + +* ``__legacy_microseconds__`` on SQLite ``Time`` and + ``DateTime`` types is not supported anymore. You should + use the new "storage_format" argument instead. + +* ``DateTime`` types on SQLite now use by a default a + stricter regular expression to match strings from the + database. Use the new "regexp" argument if you are using + data stored in a legacy format. + +ORM Changes +=========== + +Upgrading an ORM application from 0.5 to 0.6 should require +little to no changes, as the ORM's behavior remains almost +identical. There are some default argument and name +changes, and some loading behaviors have been improved. + +New Unit of Work +---------------- + +The internals for the unit of work, primarily +``topological.py`` and ``unitofwork.py``, have been +completely rewritten and are vastly simplified. This +should have no impact on usage, as all existing behavior +during flush has been maintained exactly (or at least, as +far as it is exercised by our testsuite and the handful of +production environments which have tested it heavily). The +performance of flush() now uses 20-30% fewer method calls +and should also use less memory. The intent and flow of the +source code should now be reasonably easy to follow, and the +architecture of the flush is fairly open-ended at this +point, creating room for potential new areas of +sophistication. The flush process no longer has any +reliance on recursion so flush plans of arbitrary size and +complexity can be flushed. Additionally, the mapper's +"save" process, which issues INSERT and UPDATE statements, +now caches the "compiled" form of the two statements so that +callcounts are further dramatically reduced with very large +flushes. + +Any changes in behavior observed with flush versus earlier +versions of 0.6 or 0.5 should be reported to us ASAP - we'll +make sure no functionality is lost. + +Changes to ``query.update()`` and ``query.delete()`` +---------------------------------------------------- + +* the 'expire' option on query.update() has been renamed to + 'fetch', thus matching that of query.delete() + +* ``query.update()`` and ``query.delete()`` both default to + 'evaluate' for the synchronize strategy. + +* the 'synchronize' strategy for update() and delete() + raises an error on failure. There is no implicit fallback + onto "fetch". Failure of evaluation is based on the + structure of criteria, so success/failure is deterministic + based on code structure. + +``relation()`` is officially named ``relationship()`` +----------------------------------------------------- + +This to solve the long running issue that "relation" means a +"table or derived table" in relational algebra terms. The +``relation()`` name, which is less typing, will hang around +for the foreseeable future so this change should be entirely +painless. + +Subquery eager loading +---------------------- + +A new kind of eager loading is added called "subquery" +loading. This is a load that emits a second SQL query +immediately after the first which loads full collections for +all the parents in the first query, joining upwards to the +parent using INNER JOIN. Subquery loading is used simlarly +to the current joined-eager loading, using the +```subqueryload()```` and ````subqueryload_all()```` options +as well as the ````lazy='subquery'```` setting on +````relationship()```. The subquery load is usually much +more efficient for loading many larger collections as it +uses INNER JOIN unconditionally and also doesn't re-load +parent rows. + +```eagerload()````, ````eagerload_all()```` is now ````joinedload()````, ````joinedload_all()``` +------------------------------------------------------------------------------------------------ + +To make room for the new subquery load feature, the existing +```eagerload()````/````eagerload_all()```` options are now +superceded by ````joinedload()```` and +````joinedload_all()````. The old names will hang around +for the foreseeable future just like ````relation()```. + +```lazy=False|None|True|'dynamic'```` now accepts ````lazy='noload'|'joined'|'subquery'|'select'|'dynamic'``` +------------------------------------------------------------------------------------------------------------- + +Continuing on the theme of loader strategies opened up, the +standard keywords for the ```lazy```` option on +````relationship()```` are now ````select```` for lazy +loading (via a SELECT issued on attribute access), +````joined```` for joined-eager loading, ````subquery```` +for subquery-eager loading, ````noload```` for no loading +should occur, and ````dynamic```` for a "dynamic" +relationship. The old ````True````, ````False````, +````None``` arguments are still accepted with the identical +behavior as before. + +innerjoin=True on relation, joinedload +-------------------------------------- + +Joined-eagerly loaded scalars and collections can now be +instructed to use INNER JOIN instead of OUTER JOIN. On +Postgresql this is observed to provide a 300-600% speedup on +some queries. Set this flag for any many-to-one which is +on a NOT NULLable foreign key, and similarly for any +collection where related items are guaranteed to exist. + +At mapper level: + +:: + + mapper(Child, child) + mapper(Parent, parent, properties={ + 'child':relationship(Child, lazy='joined', innerjoin=True) + }) + +At query time level: + +:: + + session.query(Parent).options(joinedload(Parent.child, innerjoin=True)).all() + +The ``innerjoin=True`` flag at the ``relationship()`` level +will also take effect for any ``joinedload()`` option which +does not override the value. + +Many-to-one Enhancements +------------------------ + +* many-to-one relations now fire off a lazyload in fewer + cases, including in most cases will not fetch the "old" + value when a new one is replaced. + +* many-to-one relation to a joined-table subclass now uses + get() for a simple load (known as the "use_get" + condition), i.e. ``Related``->``Sub(Base)``, without the + need to redefine the primaryjoin condition in terms of the + base table. [ticket:1186] + +* specifying a foreign key with a declarative column, i.e. + ``ForeignKey(MyRelatedClass.id)`` doesn't break the + "use_get" condition from taking place [ticket:1492] + +* relationship(), joinedload(), and joinedload_all() now + feature an option called "innerjoin". Specify ``True`` or + ``False`` to control whether an eager join is constructed + as an INNER or OUTER join. Default is ``False`` as always. + The mapper options will override whichever setting is + specified on relationship(). Should generally be set for + many-to-one, not nullable foreign key relations to allow + improved join performance. [ticket:1544] + +* the behavior of joined eager loading such that the main + query is wrapped in a subquery when LIMIT/OFFSET are + present now makes an exception for the case when all eager + loads are many-to-one joins. In those cases, the eager + joins are against the parent table directly along with the + limit/offset without the extra overhead of a subquery, + since a many-to-one join does not add rows to the result. + + For example, in 0.5 this query: + + :: + + session.query(Address).options(eagerload(Address.user)).limit(10) + + would produce SQL like: + + :: + + SELECT * FROM + (SELECT * FROM addresses LIMIT 10) AS anon_1 + LEFT OUTER JOIN users AS users_1 ON users_1.id = anon_1.addresses_user_id + + This because the presence of any eager loaders suggests + that some or all of them may relate to multi-row + collections, which would necessitate wrapping any kind of + rowcount-sensitive modifiers like LIMIT inside of a + subquery. + + In 0.6, that logic is more sensitive and can detect if all + eager loaders represent many-to-ones, in which case the + eager joins don't affect the rowcount: + + :: + + SELECT * FROM addresses LEFT OUTER JOIN users AS users_1 ON users_1.id = addresses.user_id LIMIT 10 + +Mutable Primary Keys with Joined Table Inheritance +-------------------------------------------------- + +A joined table inheritance config where the child table has +a PK that foreign keys to the parent PK can now be updated +on a CASCADE-capable database like Postgresql. +``mapper()`` now has an option ``passive_updates=True`` +which indicates this foreign key is updated automatically. +If on a non-cascading database like SQLite or MySQL/MyISAM, +set this flag to ``False``. A future feature enhancement +will try to get this flag to be auto-configuring based on +dialect/table style in use. + +Beaker Caching +-------------- + +A promising new example of Beaker integration is in +``examples/beaker_caching``. This is a straightforward +recipe which applies a Beaker cache within the result- +generation engine of ``Query``. Cache parameters are +provided via ``query.options()``, and allows full control +over the contents of the cache. SQLAlchemy 0.6 includes +improvements to the ``Session.merge()`` method to support +this and similar recipes, as well as to provide +significantly improved performance in most scenarios. + +Other Changes +------------- + +* the "row tuple" object returned by ``Query`` when multiple + column/entities are selected is now picklable as well as + higher performing. + +* ``query.join()`` has been reworked to provide more + consistent behavior and more flexibility (includes + [ticket:1537]) + +* ``query.select_from()`` accepts multiple clauses to + produce multiple comma separated entries within the FROM + clause. Useful when selecting from multiple-homed join() + clauses. + +* the "dont_load=True" flag on ``Session.merge()`` is + deprecated and is now "load=False". + +* added "make_transient()" helper function which transforms + a persistent/ detached instance into a transient one (i.e. + deletes the instance_key and removes from any session.) + [ticket:1052] + +* the allow_null_pks flag on mapper() is deprecated and has + been renamed to allow_partial_pks. It is turned "on" by + default. This means that a row which has a non-null value + for any of its primary key columns will be considered an + identity. The need for this scenario typically only occurs + when mapping to an outer join. When set to False, a PK + that has NULLs in it will not be considered a primary key + - in particular this means a result row will come back as + None (or not be filled into a collection), and new in 0.6 + also indicates that session.merge() won't issue a round + trip to the database for such a PK value. [ticket:1680] + +* the mechanics of "backref" have been fully merged into the + finer grained "back_populates" system, and take place + entirely within the ``_generate_backref()`` method of + ``RelationProperty``. This makes the initialization + procedure of ``RelationProperty`` simpler and allows + easier propagation of settings (such as from subclasses of + ``RelationProperty``) into the reverse reference. The + internal ``BackRef()`` is gone and ``backref()`` returns a + plain tuple that is understood by ``RelationProperty``. + +* the keys attribute of ``ResultProxy`` is now a method, so + references to it (``result.keys``) must be changed to + method invocations (``result.keys()``) + +* ``ResultProxy.last_inserted_ids`` is now deprecated, use + ``ResultProxy.inserted_primary_key`` instead. + +Deprecated/Removed ORM Elements +------------------------------- + +Most elements that were deprecated throughout 0.5 and raised +deprecation warnings have been removed (with a few +exceptions). All elements that were marked "pending +deprecation" are now deprecated and will raise a warning +upon use. + +* 'transactional' flag on sessionmaker() and others is + removed. Use 'autocommit=True' to indicate + 'transactional=False'. + +* 'polymorphic_fetch' argument on mapper() is removed. + Loading can be controlled using the 'with_polymorphic' + option. + +* 'select_table' argument on mapper() is removed. Use + 'with_polymorphic=("*", )' for this + functionality. + +* 'proxy' argument on synonym() is removed. This flag did + nothing throughout 0.5, as the "proxy generation" + behavior is now automatic. + +* Passing a single list of elements to joinedload(), + joinedload_all(), contains_eager(), lazyload(), defer(), + and undefer() instead of multiple positional \*args is + deprecated. + +* Passing a single list of elements to query.order_by(), + query.group_by(), query.join(), or query.outerjoin() + instead of multiple positional \*args is deprecated. + +* ``query.iterate_instances()`` is removed. Use + ``query.instances()``. + +* ``Query.query_from_parent()`` is removed. Use the + sqlalchemy.orm.with_parent() function to produce a + "parent" clause, or alternatively ``query.with_parent()``. + +* ``query._from_self()`` is removed, use + ``query.from_self()`` instead. + +* the "comparator" argument to composite() is removed. Use + "comparator_factory". + +* ``RelationProperty._get_join()`` is removed. + + +* the 'echo_uow' flag on Session is removed. Use logging + on the "sqlalchemy.orm.unitofwork" name. + +* ``session.clear()`` is removed. use + ``session.expunge_all()``. + +* ``session.save()``, ``session.update()``, + ``session.save_or_update()`` are removed. Use + ``session.add()`` and ``session.add_all()``. + +* the "objects" flag on session.flush() remains deprecated. + + +* the "dont_load=True" flag on session.merge() is deprecated + in favor of "load=False". + +* ``ScopedSession.mapper`` remains deprecated. See the + usage recipe at http://www.sqlalchemy.org/trac/wiki/Usag + eRecipes/SessionAwareMapper + +* passing an ``InstanceState`` (internal SQLAlchemy state + object) to ``attributes.init_collection()`` or + ``attributes.get_history()`` is deprecated. These + functions are public API and normally expect a regular + mapped object instance. + +* the 'engine' parameter to ``declarative_base()`` is + removed. Use the 'bind' keyword argument. + +Extensions +========== + +SQLSoup +------- + +SQLSoup has been modernized and updated to reflect common +0.5/0.6 capabilities, including well defined session +integration. Please read the new docs at [http://www.sqlalc +hemy.org/docs/06/reference/ext/sqlsoup.html]. + +Declarative +----------- + +The ``DeclarativeMeta`` (default metaclass for +``declarative_base``) previously allowed subclasses to +modify ``dict_`` to add class attributes (e.g. columns). +This no longer works, the ``DeclarativeMeta`` constructor +now ignores ``dict_``. Instead, the class attributes should +be assigned directly, e.g. ``cls.id=Column(...)``, or the +`MixIn class `_ approach should be used +instead of the metaclass approach. + diff --git a/doc/build/changelog/migration_07.rst b/doc/build/changelog/migration_07.rst new file mode 100644 index 0000000000..810b41290a --- /dev/null +++ b/doc/build/changelog/migration_07.rst @@ -0,0 +1,1360 @@ +============================== +What's New in SQLAlchemy 0.7 ? +============================== + +.. admonition:: About this Document + + This document describes changes between SQLAlchemy version 0.6, + last released May 5, 2012, and SQLAlchemy version 0.7, + undergoing maintenance releases as of October, 2012. + + Document date: July 27, 2011 + +Introduction +============ + +This guide introduces what's new in SQLAlchemy version 0.7, +and also documents changes which affect users migrating +their applications from the 0.6 series of SQLAlchemy to 0.7. + +To as great a degree as possible, changes are made in such a +way as to not break compatibility with applications built +for 0.6. The changes that are necessarily not backwards +compatible are very few, and all but one, the change to +mutable attribute defaults, should affect an exceedingly +small portion of applications - many of the changes regard +non-public APIs and undocumented hacks some users may have +been attempting to use. + +A second, even smaller class of non-backwards-compatible +changes is also documented. This class of change regards +those features and behaviors that have been deprecated at +least since version 0.5 and have been raising warnings since +their deprecation. These changes would only affect +applications that are still using 0.4- or early 0.5-style +APIs. As the project matures, we have fewer and fewer of +these kinds of changes with 0.x level releases, which is a +product of our API having ever fewer features that are less +than ideal for the use cases they were meant to solve. + +An array of existing functionalities have been superseded in +SQLAlchemy 0.7. There's not much difference between the +terms "superseded" and "deprecated", except that the former +has a much weaker suggestion of the old feature would ever +be removed. In 0.7, features like ``synonym`` and +``comparable_property``, as well as all the ``Extension`` +and other event classes, have been superseded. But these +"superseded" features have been re-implemented such that +their implementations live mostly outside of core ORM code, +so their continued "hanging around" doesn't impact +SQLAlchemy's ability to further streamline and refine its +internals, and we expect them to remain within the API for +the foreseeable future. + +New Features +============ + +New Event System +---------------- + +SQLAlchemy started early with the ``MapperExtension`` class, +which provided hooks into the persistence cycle of mappers. +As SQLAlchemy quickly became more componentized, pushing +mappers into a more focused configurational role, many more +"extension", "listener", and "proxy" classes popped up to +solve various activity-interception use cases in an ad-hoc +fashion. Part of this was driven by the divergence of +activities; ``ConnectionProxy`` objects wanted to provide a +system of rewriting statements and parameters; +``AttributeExtension`` provided a system of replacing +incoming values, and ``DDL`` objects had events that could +be switched off of dialect-sensitive callables. + +0.7 re-implements virtually all of these plugin points with +a new, unified approach, which retains all the +functionalities of the different systems, provides more +flexibility and less boilerplate, performs better, and +eliminates the need to learn radically different APIs for +each event subsystem. The pre-existing classes +``MapperExtension``, ``SessionExtension``, +``AttributeExtension``, ``ConnectionProxy``, +``PoolListener`` as well as the ``DDLElement.execute_at`` +method are deprecated and now implemented in terms of the +new system - these APIs remain fully functional and are +expected to remain in place for the foreseeable future. + +The new approach uses named events and user-defined +callables to associate activities with events. The API's +look and feel was driven by such diverse sources as JQuery, +Blinker, and Hibernate, and was also modified further on +several occasions during conferences with dozens of users on +Twitter, which appears to have a much higher response rate +than the mailing list for such questions. + +It also features an open-ended system of target +specification that allows events to be associated with API +classes, such as for all ``Session`` or ``Engine`` objects, +with specific instances of API classes, such as for a +specific ``Pool`` or ``Mapper``, as well as for related +objects like a user- defined class that's mapped, or +something as specific as a certain attribute on instances of +a particular subclass of a mapped parent class. Individual +listener subsystems can apply wrappers to incoming user- +defined listener functions which modify how they are called +- an mapper event can receive either the instance of the +object being operated upon, or its underlying +``InstanceState`` object. An attribute event can opt whether +or not to have the responsibility of returning a new value. + +Several systems now build upon the new event API, including +the new "mutable attributes" API as well as composite +attributes. The greater emphasis on events has also led to +the introduction of a handful of new events, including +attribute expiration and refresh operations, pickle +loads/dumps operations, completed mapper construction +operations. + +.. seealso:: + + :ref:`event_toplevel` + +:ticket:`1902` + +Hybrid Attributes, implements/supersedes synonym(), comparable_property() +------------------------------------------------------------------------- + +The "derived attributes" example has now been turned into an +official extension. The typical use case for ``synonym()`` +is to provide descriptor access to a mapped column; the use +case for ``comparable_property()`` is to be able to return a +``PropComparator`` from any descriptor. In practice, the +approach of "derived" is easier to use, more extensible, is +implemented in a few dozen lines of pure Python with almost +no imports, and doesn't require the ORM core to even be +aware of it. The feature is now known as the "Hybrid +Attributes" extension. + +``synonym()`` and ``comparable_property()`` are still part +of the ORM, though their implementations have been moved +outwards, building on an approach that is similar to that of +the hybrid extension, so that the core ORM +mapper/query/property modules aren't really aware of them +otherwise. + +.. seealso:: + + :ref:`hybrids_toplevel` + +:ticket:`1903` + +Speed Enhancements +------------------ + +As is customary with all major SQLA releases, a wide pass +through the internals to reduce overhead and callcounts has +been made which further reduces the work needed in common +scenarios. Highlights of this release include: + +* The flush process will now bundle INSERT statements into + batches fed to ``cursor.executemany()``, for rows where + the primary key is already present. In particular this + usually applies to the "child" table on a joined table + inheritance configuration, meaning the number of calls to + ``cursor.execute`` for a large bulk insert of joined- + table objects can be cut in half, allowing native DBAPI + optimizations to take place for those statements passed + to ``cursor.executemany()`` (such as re-using a prepared + statement). + +* The codepath invoked when accessing a many-to-one + reference to a related object that's already loaded has + been greatly simplified. The identity map is checked + directly without the need to generate a new ``Query`` + object first, which is expensive in the context of + thousands of in-memory many-to-ones being accessed. The + usage of constructed-per-call "loader" objects is also no + longer used for the majority of lazy attribute loads. + +* The rewrite of composites allows a shorter codepath when + mapper internals access mapped attributes within a + flush. + +* New inlined attribute access functions replace the + previous usage of "history" when the "save-update" and + other cascade operations need to cascade among the full + scope of datamembers associated with an attribute. This + reduces the overhead of generating a new ``History`` + object for this speed-critical operation. + +* The internals of the ``ExecutionContext``, the object + corresponding to a statement execution, have been + inlined and simplified. + +* The ``bind_processor()`` and ``result_processor()`` + callables generated by types for each statement + execution are now cached (carefully, so as to avoid memory + leaks for ad-hoc types and dialects) for the lifespan of + that type, further reducing per-statement call overhead. + +* The collection of "bind processors" for a particular + ``Compiled`` instance of a statement is also cached on + the ``Compiled`` object, taking further advantage of the + "compiled cache" used by the flush process to re-use the + same compiled form of INSERT, UPDATE, DELETE statements. + +A demonstration of callcount reduction including a sample +benchmark script is at +http://techspot.zzzeek.org/2010/12/12/a-tale-of-three- +profiles/ + +Composites Rewritten +-------------------- + +The "composite" feature has been rewritten, like +``synonym()`` and ``comparable_property()``, to use a +lighter weight implementation based on descriptors and +events, rather than building into the ORM internals. This +allowed the removal of some latency from the mapper/unit of +work internals, and simplifies the workings of composite. +The composite attribute now no longer conceals the +underlying columns it builds upon, which now remain as +regular attributes. Composites can also act as a proxy for +``relationship()`` as well as ``Column()`` attributes. + +The major backwards-incompatible change of composites is +that they no longer use the ``mutable=True`` system to +detect in-place mutations. Please use the `Mutation +Tracking `_ extension to establish in-place change events +to existing composite usage. + +.. seealso:: + + :ref:`mapper_composite` + + :ref:`mutable_toplevel` + +:ticket:`2008` :ticket:`2024` + +More succinct form of query.join(target, onclause) +-------------------------------------------------- + +The default method of issuing ``query.join()`` to a target +with an explicit onclause is now: + +:: + + query.join(SomeClass, SomeClass.id==ParentClass.some_id) + +In 0.6, this usage was considered to be an error, because +``join()`` accepts multiple arguments corresponding to +multiple JOIN clauses - the two-argument form needed to be +in a tuple to disambiguate between single-argument and two- +argument join targets. In the middle of 0.6 we added +detection and an error message for this specific calling +style, since it was so common. In 0.7, since we are +detecting the exact pattern anyway, and since having to type +out a tuple for no reason is extremely annoying, the non- +tuple method now becomes the "normal" way to do it. The +"multiple JOIN" use case is exceedingly rare compared to the +single join case, and multiple joins these days are more +clearly represented by multiple calls to ``join()``. + +The tuple form will remain for backwards compatibility. + +Note that all the other forms of ``query.join()`` remain +unchanged: + +:: + + query.join(MyClass.somerelation) + query.join("somerelation") + query.join(MyTarget) + # ... etc + +`Querying with Joins +`_ + +:ticket:`1923` + +Mutation event extension, supersedes "mutable=True" +--------------------------------------------------- + +A new extension, `Mutation Tracking `_, provides a +mechanism by which user-defined datatypes can provide change +events back to the owning parent or parents. The extension +includes an approach for scalar database values, such as +those managed by ``PickleType``, ``postgresql.ARRAY``, or +other custom ``MutableType`` classes, as well as an approach +for ORM "composites", those configured using :ref:`composite() +`_. + +.. seealso:: + + :ref:`mutable_toplevel` + +NULLS FIRST / NULLS LAST operators +---------------------------------- + +These are implemented as an extension to the ``asc()`` and +``desc()`` operators, called ``nullsfirst()`` and +``nullslast()``. + +.. seealso:: + + :func:`.nullsfirst` + + :func:`.nullslast` + +:ticket:`723` + +select.distinct(), query.distinct() accepts \*args for Postgresql DISTINCT ON +----------------------------------------------------------------------------- + +This was already available by passing a list of expressions +to the ``distinct`` keyword argument of ``select()``, the +``distinct()`` method of ``select()`` and ``Query`` now +accept positional arguments which are rendered as DISTINCT +ON when a Postgresql backend is used. + +`distinct() `_ + +`Query.distinct() `_ + +:ticket:`1069` + +``Index()`` can be placed inline inside of ``Table``, ``__table_args__`` +------------------------------------------------------------------------ + +The Index() construct can be created inline with a Table +definition, using strings as column names, as an alternative +to the creation of the index outside of the Table. That is: + +:: + + Table('mytable', metadata, + Column('id',Integer, primary_key=True), + Column('name', String(50), nullable=False), + Index('idx_name', 'name') + ) + +The primary rationale here is for the benefit of declarative +``__table_args__``, particularly when used with mixins: + +:: + + class HasNameMixin(object): + name = Column('name', String(50), nullable=False) + @declared_attr + def __table_args__(cls): + return (Index('name'), {}) + + class User(HasNameMixin, Base): + __tablename__ = 'user' + id = Column('id', Integer, primary_key=True) + +`Indexes `_ + +Window Function SQL Construct +----------------------------- + +A "window function" provides to a statement information +about the result set as it's produced. This allows criteria +against various things like "row number", "rank" and so +forth. They are known to be supported at least by +Postgresql, SQL Server and Oracle, possibly others. + +The best introduction to window functions is on Postgresql's +site, where window functions have been supported since +version 8.4: + +http://www.postgresql.org/docs/9.0/static/tutorial- +window.html + +SQLAlchemy provides a simple construct typically invoked via +an existing function clause, using the ``over()`` method, +which accepts ``order_by`` and ``partition_by`` keyword +arguments. Below we replicate the first example in PG's +tutorial: + +:: + + from sqlalchemy.sql import table, column, select, func + + empsalary = table('empsalary', + column('depname'), + column('empno'), + column('salary')) + + s = select([ + empsalary, + func.avg(empsalary.c.salary). + over(partition_by=empsalary.c.depname). + label('avg') + ]) + + print s + +SQL: + +:: + + SELECT empsalary.depname, empsalary.empno, empsalary.salary, + avg(empsalary.salary) OVER (PARTITION BY empsalary.depname) AS avg + FROM empsalary + +`sqlalchemy.sql.expression.over `_ + +:ticket:`1844` + +execution_options() on Connection accepts "isolation_level" argument +-------------------------------------------------------------------- + +This sets the transaction isolation level for a single +``Connection``, until that ``Connection`` is closed and its +underlying DBAPI resource returned to the connection pool, +upon which the isolation level is reset back to the default. +The default isolation level is set using the +``isolation_level`` argument to ``create_engine()``. + +Transaction isolation support is currently only supported by +the Postgresql and SQLite backends. + +`execution_options() `_ + +:ticket:`2001` + +``TypeDecorator`` works with integer primary key columns +-------------------------------------------------------- + +A ``TypeDecorator`` which extends the behavior of +``Integer`` can be used with a primary key column. The +"autoincrement" feature of ``Column`` will now recognize +that the underlying database column is still an integer so +that lastrowid mechanisms continue to function. The +``TypeDecorator`` itself will have its result value +processor applied to newly generated primary keys, including +those received by the DBAPI ``cursor.lastrowid`` accessor. + +:ticket:`2005` :ticket:`2006` + +``TypeDecorator`` is present in the "sqlalchemy" import space +------------------------------------------------------------- + +No longer need to import this from ``sqlalchemy.types``, +it's now mirrored in ``sqlalchemy``. + +New Dialects +------------ + +Dialects have been added: + +* a MySQLdb driver for the Drizzle database: + + + `Drizzle `_ + +* support for the pymysql DBAPI: + + + `pymsql Notes + `_ + +* psycopg2 now works with Python 3 + + +Behavioral Changes (Backwards Compatible) +========================================= + +C Extensions Build by Default +----------------------------- + +This is as of 0.7b4. The exts will build if cPython 2.xx +is detected. If the build fails, such as on a windows +install, that condition is caught and the non-C install +proceeds. The C exts won't build if Python 3 or Pypy is +used. + +Query.count() simplified, should work virtually always +------------------------------------------------------ + +The very old guesswork which occurred within +``Query.count()`` has been modernized to use +``.from_self()``. That is, ``query.count()`` is now +equivalent to: + +:: + + query.from_self(func.count(literal_column('1'))).scalar() + +Previously, internal logic attempted to rewrite the columns +clause of the query itself, and upon detection of a +"subquery" condition, such as a column-based query that +might have aggregates in it, or a query with DISTINCT, would +go through a convoluted process of rewriting the columns +clause. This logic failed in complex conditions, +particularly those involving joined table inheritance, and +was long obsolete by the more comprehensive ``.from_self()`` +call. + +The SQL emitted by ``query.count()`` is now always of the +form: + +:: + + SELECT count(1) AS count_1 FROM ( + SELECT user.id AS user_id, user.name AS user_name from user + ) AS anon_1 + +that is, the original query is preserved entirely inside of +a subquery, with no more guessing as to how count should be +applied. + +:ticket:`2093` + +To emit a non-subquery form of count() +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +MySQL users have already reported that the MyISAM engine not +surprisingly falls over completely with this simple change. +Note that for a simple ``count()`` that optimizes for DBs +that can't handle simple subqueries, ``func.count()`` should +be used: + +:: + + from sqlalchemy import func + session.query(func.count(MyClass.id)).scalar() + +or for ``count(*)``: + +:: + + from sqlalchemy import func, literal_column + session.query(func.count(literal_column('*'))).select_from(MyClass).scalar() + +LIMIT/OFFSET clauses now use bind parameters +-------------------------------------------- + +The LIMIT and OFFSET clauses, or their backend equivalents +(i.e. TOP, ROW NUMBER OVER, etc.), use bind parameters for +the actual values, for all backends which support it (most +except for Sybase). This allows better query optimizer +performance as the textual string for multiple statements +with differing LIMIT/OFFSET are now identical. + +:ticket:`805` + +Logging enhancements +-------------------- + +Vinay Sajip has provided a patch to our logging system such +that the "hex string" embedded in logging statements for +engines and pools is no longer needed to allow the ``echo`` +flag to work correctly. A new system that uses filtered +logging objects allows us to maintain our current behavior +of ``echo`` being local to individual engines without the +need for additional identifying strings local to those +engines. + +:ticket:`1926` + +Simplified polymorphic_on assignment +------------------------------------ + +The population of the ``polymorphic_on`` column-mapped +attribute, when used in an inheritance scenario, now occurs +when the object is constructed, i.e. its ``__init__`` method +is called, using the init event. The attribute then behaves +the same as any other column-mapped attribute. Previously, +special logic would fire off during flush to populate this +column, which prevented any user code from modifying its +behavior. The new approach improves upon this in three +ways: 1. the polymorphic identity is now present on the +object as soon as its constructed; 2. the polymorphic +identity can be changed by user code without any difference +in behavior from any other column-mapped attribute; 3. the +internals of the mapper during flush are simplified and no +longer need to make special checks for this column. + +:ticket:`1895` + +contains_eager() chains across multiple paths (i.e. "all()") +------------------------------------------------------------ + +The ```contains_eager()```` modifier now will chain itself +for a longer path without the need to emit individual +````contains_eager()``` calls. Instead of: + +:: + + session.query(A).options(contains_eager(A.b), contains_eager(A.b, B.c)) + +you can say: + +:: + + session.query(A).options(contains_eager(A.b, B.c)) + +:ticket:`2032` + +Flushing of orphans that have no parent is allowed +-------------------------------------------------- + +We've had a long standing behavior that checks for a so- +called "orphan" during flush, that is, an object which is +associated with a ``relationship()`` that specifies "delete- +orphan" cascade, has been newly added to the session for an +INSERT, and no parent relationship has been established. +This check was added years ago to accommodate some test +cases which tested the orphan behavior for consistency. In +modern SQLA, this check is no longer needed on the Python +side. The equivalent behavior of the "orphan check" is +accomplished by making the foreign key reference to the +object's parent row NOT NULL, where the database does its +job of establishing data consistency in the same way SQLA +allows most other operations to do. If the object's parent +foreign key is nullable, then the row can be inserted. The +"orphan" behavior runs when the object was persisted with a +particular parent, and is then disassociated with that +parent, leading to a DELETE statement emitted for it. + +:ticket:`1912` + +Warnings generated when collection members, scalar referents not part of the flush +---------------------------------------------------------------------------------- + +Warnings are now emitted when related objects referenced via +a loaded ``relationship()`` on a parent object marked as +"dirty" are not present in the current ``Session``. + +The ``save-update`` cascade takes effect when objects are +added to the ``Session``, or when objects are first +associated with a parent, so that an object and everything +related to it are usually all present in the same +``Session``. However, if ``save-update`` cascade is +disabled for a particular ``relationship()``, then this +behavior does not occur, and the flush process does not try +to correct for it, instead staying consistent to the +configured cascade behavior. Previously, when such objects +were detected during the flush, they were silently skipped. +The new behavior is that a warning is emitted, for the +purposes of alerting to a situation that more often than not +is the source of unexpected behavior. + +:ticket:`1973` + +Setup no longer installs a Nose plugin +-------------------------------------- + +Since we moved to nose we've used a plugin that installs via +setuptools, so that the ``nosetests`` script would +automatically run SQLA's plugin code, necessary for our +tests to have a full environment. In the middle of 0.6, we +realized that the import pattern here meant that Nose's +"coverage" plugin would break, since "coverage" requires +that it be started before any modules to be covered are +imported; so in the middle of 0.6 we made the situation +worse by adding a separate ``sqlalchemy-nose`` package to +the build to overcome this. + +In 0.7 we've done away with trying to get ``nosetests`` to +work automatically, since the SQLAlchemy module would +produce a large number of nose configuration options for all +usages of ``nosetests``, not just the SQLAlchemy unit tests +themselves, and the additional ``sqlalchemy-nose`` install +was an even worse idea, producing an extra package in Python +environments. The ``sqla_nose.py`` script in 0.7 is now +the only way to run the tests with nose. + +:ticket:`1949` + +Non-``Table``-derived constructs can be mapped +---------------------------------------------- + +A construct that isn't against any ``Table`` at all, like a +function, can be mapped. + +:: + + from sqlalchemy import select, func + from sqlalchemy.orm import mapper + + class Subset(object): + pass + selectable = select(["x", "y", "z"]).select_from(func.some_db_function()).alias() + mapper(Subset, selectable, primary_key=[selectable.c.x]) + +:ticket:`1876` + +aliased() accepts ``FromClause`` elements +----------------------------------------- + +This is a convenience helper such that in the case a plain +``FromClause``, such as a ``select``, ``Table`` or ``join`` +is passed to the ``orm.aliased()`` construct, it passes +through to the ``.alias()`` method of that from construct +rather than constructing an ORM level ``AliasedClass``. + +:ticket:`2018` + +Session.connection(), Session.execute() accept 'bind' +----------------------------------------------------- + +This is to allow execute/connection operations to +participate in the open transaction of an engine explicitly. +It also allows custom subclasses of ``Session`` that +implement their own ``get_bind()`` method and arguments to +use those custom arguments with both the ``execute()`` and +``connection()`` methods equally. + +`Session.connection `_ +`Session.execute `_ + +:ticket:`1996` + +Standalone bind parameters in columns clause auto-labeled. +---------------------------------------------------------- + +Bind parameters present in the "columns clause" of a select +are now auto-labeled like other "anonymous" clauses, which +among other things allows their "type" to be meaningful when +the row is fetched, as in result row processors. + +SQLite - relative file paths are normalized through os.path.abspath() +--------------------------------------------------------------------- + +This so that a script that changes the current directory +will continue to target the same location as subsequent +SQLite connections are established. + +:ticket:`2036` + +MS-SQL - ``String``/``Unicode``/``VARCHAR``/``NVARCHAR``/``VARBINARY`` emit "max" for no length +----------------------------------------------------------------------------------------------- + +On the MS-SQL backend, the String/Unicode types, and their +counterparts VARCHAR/ NVARCHAR, as well as VARBINARY +(:ticket:`1833`) emit "max" as the length when no length is +specified. This makes it more compatible with Postgresql's +VARCHAR type which is similarly unbounded when no length +specified. SQL Server defaults the length on these types +to '1' when no length is specified. + +Behavioral Changes (Backwards Incompatible) +=========================================== + +Note again, aside from the default mutability change, most +of these changes are \*extremely minor* and will not affect +most users. + +``PickleType`` and ARRAY mutability turned off by default +--------------------------------------------------------- + +This change refers to the default behavior of the ORM when +mapping columns that have either the ``PickleType`` or +``postgresql.ARRAY`` datatypes. The ``mutable`` flag is now +set to ``False`` by default. If an existing application uses +these types and depends upon detection of in-place +mutations, the type object must be constructed with +``mutable=True`` to restore the 0.6 behavior: + +:: + + Table('mytable', metadata, + # .... + + Column('pickled_data', PickleType(mutable=True)) + ) + +The ``mutable=True`` flag is being phased out, in favor of +the new `Mutation Tracking `_ extension. This extension +provides a mechanism by which user-defined datatypes can +provide change events back to the owning parent or parents. + +The previous approach of using ``mutable=True`` does not +provide for change events - instead, the ORM must scan +through all mutable values present in a session and compare +them against their original value for changes every time +``flush()`` is called, which is a very time consuming event. +This is a holdover from the very early days of SQLAlchemy +when ``flush()`` was not automatic and the history tracking +system was not nearly as sophisticated as it is now. + +Existing applications which use ``PickleType``, +``postgresql.ARRAY`` or other ``MutableType`` subclasses, +and require in-place mutation detection, should migrate to +the new mutation tracking system, as ``mutable=True`` is +likely to be deprecated in the future. + +:ticket:`1980` + +Mutability detection of ``composite()`` requires the Mutation Tracking Extension +-------------------------------------------------------------------------------- + +So-called "composite" mapped attributes, those configured +using the technique described at `Composite Column Types +`_, have been re-implemented such +that the ORM internals are no longer aware of them (leading +to shorter and more efficient codepaths in critical +sections). While composite types are generally intended to +be treated as immutable value objects, this was never +enforced. For applications that use composites with +mutability, the `Mutation Tracking `_ extension offers a +base class which establishes a mechanism for user-defined +composite types to send change event messages back to the +owning parent or parents of each object. + +Applications which use composite types and rely upon in- +place mutation detection of these objects should either +migrate to the "mutation tracking" extension, or change the +usage of the composite types such that in-place changes are +no longer needed (i.e., treat them as immutable value +objects). + +SQLite - the SQLite dialect now uses ``NullPool`` for file-based databases +-------------------------------------------------------------------------- + +This change is **99.999% backwards compatible**, unless you +are using temporary tables across connection pool +connections. + +A file-based SQLite connection is blazingly fast, and using +``NullPool`` means that each call to ``Engine.connect`` +creates a new pysqlite connection. + +Previously, the ``SingletonThreadPool`` was used, which +meant that all connections to a certain engine in a thread +would be the same connection. It's intended that the new +approach is more intuitive, particularly when multiple +connections are used. + +``SingletonThreadPool`` is still the default engine when a +``:memory:`` database is used. + +Note that this change **breaks temporary tables used across +Session commits**, due to the way SQLite handles temp +tables. See the note at +http://www.sqlalchemy.org/docs/dialects/sqlite.html#using- +temporary-tables-with-sqlite if temporary tables beyond the +scope of one pool connection are desired. + +:ticket:`1921` + +``Session.merge()`` checks version ids for versioned mappers +------------------------------------------------------------ + +Session.merge() will check the version id of the incoming +state against that of the database, assuming the mapping +uses version ids and incoming state has a version_id +assigned, and raise StaleDataError if they don't match. +This is the correct behavior, in that if incoming state +contains a stale version id, it should be assumed the state +is stale. + +If merging data into a versioned state, the version id +attribute can be left undefined, and no version check will +take place. + +This check was confirmed by examining what Hibernate does - +both the ``merge()`` and the versioning features were +originally adapted from Hibernate. + +:ticket:`2027` + +Tuple label names in Query Improved +----------------------------------- + +This improvement is potentially slightly backwards +incompatible for an application that relied upon the old +behavior. + +Given two mapped classes ``Foo`` and ``Bar`` each with a +column ``spam``: + +:: + + + qa = session.query(Foo.spam) + qb = session.query(Bar.spam) + + qu = qa.union(qb) + +The name given to the single column yielded by ``qu`` will +be ``spam``. Previously it would be something like +``foo_spam`` due to the way the ``union`` would combine +things, which is inconsistent with the name ``spam`` in the +case of a non-unioned query. + +:ticket:`1942` + +Mapped column attributes reference the most specific column first +----------------------------------------------------------------- + +This is a change to the behavior involved when a mapped +column attribute references multiple columns, specifically +when dealing with an attribute on a joined-table subclass +that has the same name as that of an attribute on the +superclass. + +Using declarative, the scenario is this: + +:: + + class Parent(Base): + __tablename__ = 'parent' + id = Column(Integer, primary_key=True) + + class Child(Parent): + __tablename__ = 'child' + id = Column(Integer, ForeignKey('parent.id'), primary_key=True) + +Above, the attribute ``Child.id`` refers to both the +``child.id`` column as well as ``parent.id`` - this due to +the name of the attribute. If it were named differently on +the class, such as ``Child.child_id``, it then maps +distinctly to ``child.id``, with ``Child.id`` being the same +attribute as ``Parent.id``. + +When the ``id`` attribute is made to reference both +``parent.id`` and ``child.id``, it stores them in an ordered +list. An expression such as ``Child.id`` then refers to +just *one* of those columns when rendered. Up until 0.6, +this column would be ``parent.id``. In 0.7, it is the less +surprising ``child.id``. + +The legacy of this behavior deals with behaviors and +restrictions of the ORM that don't really apply anymore; all +that was needed was to reverse the order. + +A primary advantage of this approach is that it's now easier +to construct ``primaryjoin`` expressions that refer to the +local column: + +:: + + class Child(Parent): + __tablename__ = 'child' + id = Column(Integer, ForeignKey('parent.id'), primary_key=True) + some_related = relationship("SomeRelated", + primaryjoin="Child.id==SomeRelated.child_id") + + class SomeRelated(Base): + __tablename__ = 'some_related' + id = Column(Integer, primary_key=True) + child_id = Column(Integer, ForeignKey('child.id')) + +Prior to 0.7 the ``Child.id`` expression would reference +``Parent.id``, and it would be necessary to map ``child.id`` +to a distinct attribute. + +It also means that a query like this one changes its +behavior: + +:: + + session.query(Parent).filter(Child.id > 7) + +In 0.6, this would render: + +:: + + SELECT parent.id AS parent_id + FROM parent + WHERE parent.id > :id_1 + +in 0.7, you get: + +:: + + SELECT parent.id AS parent_id + FROM parent, child + WHERE child.id > :id_1 + +which you'll note is a cartesian product - this behavior is +now equivalent to that of any other attribute that is local +to ``Child``. The ``with_polymorphic()`` method, or a +similar strategy of explicitly joining the underlying +``Table`` objects, is used to render a query against all +``Parent`` objects with criteria against ``Child``, in the +same manner as that of 0.5 and 0.6: + +:: + + print s.query(Parent).with_polymorphic([Child]).filter(Child.id > 7) + +Which on both 0.6 and 0.7 renders: + +:: + + SELECT parent.id AS parent_id, child.id AS child_id + FROM parent LEFT OUTER JOIN child ON parent.id = child.id + WHERE child.id > :id_1 + +Another effect of this change is that a joined-inheritance +load across two tables will populate from the child table's +value, not that of the parent table. An unusual case is that +a query against "Parent" using ``with_polymorphic="*"`` +issues a query against "parent", with a LEFT OUTER JOIN to +"child". The row is located in "Parent", sees the +polymorphic identity corresponds to "Child", but suppose the +actual row in "child" has been *deleted*. Due to this +corruption, the row comes in with all the columns +corresponding to "child" set to NULL - this is now the value +that gets populated, not the one in the parent table. + +:ticket:`1892` + +Mapping to joins with two or more same-named columns requires explicit declaration +---------------------------------------------------------------------------------- + +This is somewhat related to the previous change in +:ticket:`1892`. When mapping to a join, same-named columns +must be explicitly linked to mapped attributes, i.e. as +described in `Mapping a Class Against Multiple Tables `_. + +Given two tables ``foo`` and ``bar``, each with a primary +key column ``id``, the following now produces an error: + +:: + + + foobar = foo.join(bar, foo.c.id==bar.c.foo_id) + mapper(FooBar, foobar) + +This because the ``mapper()`` refuses to guess what column +is the primary representation of ``FooBar.id`` - is it +``foo.c.id`` or is it ``bar.c.id`` ? The attribute must be +explicit: + +:: + + + foobar = foo.join(bar, foo.c.id==bar.c.foo_id) + mapper(FooBar, foobar, properties={ + 'id':[foo.c.id, bar.c.id] + }) + +:ticket:`1896` + +Mapper requires that polymorphic_on column be present in the mapped selectable +------------------------------------------------------------------------------ + +This is a warning in 0.6, now an error in 0.7. The column +given for ``polymorphic_on`` must be in the mapped +selectable. This to prevent some occasional user errors +such as: + +:: + + mapper(SomeClass, sometable, polymorphic_on=some_lookup_table.c.id) + +where above the polymorphic_on needs to be on a +``sometable`` column, in this case perhaps +``sometable.c.some_lookup_id``. There are also some +"polymorphic union" scenarios where similar mistakes +sometimes occur. + +Such a configuration error has always been "wrong", and the +above mapping doesn't work as specified - the column would +be ignored. It is however potentially backwards +incompatible in the rare case that an application has been +unknowingly relying upon this behavior. + +:ticket:`1875` + +``DDL()`` constructs now escape percent signs +--------------------------------------------- + +Previously, percent signs in ``DDL()`` strings would have to +be escaped, i.e. ``%%`` depending on DBAPI, for those DBAPIs +that accept ``pyformat`` or ``format`` binds (i.e. psycopg2, +mysql-python), which was inconsistent versus ``text()`` +constructs which did this automatically. The same escaping +now occurs for ``DDL()`` as for ``text()``. + +:ticket:`1897` + +``Table.c`` / ``MetaData.tables`` refined a bit, don't allow direct mutation +---------------------------------------------------------------------------- + +Another area where some users were tinkering around in such +a way that doesn't actually work as expected, but still left +an exceedingly small chance that some application was +relying upon this behavior, the construct returned by the +``.c`` attribute on ``Table`` and the ``.tables`` attribute +on ``MetaData`` is explicitly non-mutable. The "mutable" +version of the construct is now private. Adding columns to +``.c`` involves using the ``append_column()`` method of +``Table``, which ensures things are associated with the +parent ``Table`` in the appropriate way; similarly, +``MetaData.tables`` has a contract with the ``Table`` +objects stored in this dictionary, as well as a little bit +of new bookkeeping in that a ``set()`` of all schema names +is tracked, which is satisfied only by using the public +``Table`` constructor as well as ``Table.tometadata()``. + +It is of course possible that the ``ColumnCollection`` and +``dict`` collections consulted by these attributes could +someday implement events on all of their mutational methods +such that the appropriate bookkeeping occurred upon direct +mutation of the collections, but until someone has the +motivation to implement all that along with dozens of new +unit tests, narrowing the paths to mutation of these +collections will ensure no application is attempting to rely +upon usages that are currently not supported. + +:ticket:`1893` :ticket:`1917` + +server_default consistently returns None for all inserted_primary_key values +---------------------------------------------------------------------------- + +Established consistency when server_default is present on an +Integer PK column. SQLA doesn't pre-fetch these, nor do they +come back in cursor.lastrowid (DBAPI). Ensured all backends +consistently return None in result.inserted_primary_key for +these - some backends may have returned a value previously. +Using a server_default on a primary key column is extremely +unusual. If a special function or SQL expression is used +to generate primary key defaults, this should be established +as a Python-side "default" instead of server_default. + +Regarding reflection for this case, reflection of an int PK +col with a server_default sets the "autoincrement" flag to +False, except in the case of a PG SERIAL col where we +detected a sequence default. + +:ticket:`2020` :ticket:`2021` + +The ``sqlalchemy.exceptions`` alias in sys.modules is removed +------------------------------------------------------------- + +For a few years we've added the string +``sqlalchemy.exceptions`` to ``sys.modules``, so that a +statement like "``import sqlalchemy.exceptions``" would +work. The name of the core exceptions module has been +``exc`` for a long time now, so the recommended import for +this module is: + +:: + + from sqlalchemy import exc + +The ``exceptions`` name is still present in "``sqlalchemy``" +for applications which might have said ``from sqlalchemy +import exceptions``, but they should also start using the +``exc`` name. + +Query Timing Recipe Changes +--------------------------- + +While not part of SQLAlchemy itself, it's worth mentioning +that the rework of the ``ConnectionProxy`` into the new +event system means it is no longer appropriate for the +"Timing all Queries" recipe. Please adjust query-timers to +use the ``before_cursor_execute()`` and +``after_cursor_execute()`` events, demonstrated in the +updated recipe UsageRecipes/Profiling. + +Deprecated API +============== + +Default constructor on types will not accept arguments +------------------------------------------------------ + +Simple types like ``Integer``, ``Date`` etc. in the core +types module don't accept arguments. The default +constructor that accepts/ignores a catchall ``\*args, +\**kwargs`` is restored as of 0.7b4/0.7.0, but emits a +deprecation warning. + +If arguments are being used with a core type like +``Integer``, it may be that you intended to use a dialect +specific type, such as ``sqlalchemy.dialects.mysql.INTEGER`` +which does accept a "display_width" argument for example. + +compile_mappers() renamed configure_mappers(), simplified configuration internals +--------------------------------------------------------------------------------- + +This system slowly morphed from something small, implemented +local to an individual mapper, and poorly named into +something that's more of a global "registry-" level function +and poorly named, so we've fixed both by moving the +implementation out of ``Mapper`` altogether and renaming it +to ``configure_mappers()``. It is of course normally not +needed for an application to call ``configure_mappers()`` as +this process occurs on an as-needed basis, as soon as the +mappings are needed via attribute or query access. + +:ticket:`1966` + +Core listener/proxy superseded by event listeners +------------------------------------------------- + +``PoolListener``, ``ConnectionProxy``, +``DDLElement.execute_at`` are superseded by +``event.listen()``, using the ``PoolEvents``, +``EngineEvents``, ``DDLEvents`` dispatch targets, +respectively. + +ORM extensions superseded by event listeners +-------------------------------------------- + +``MapperExtension``, ``AttributeExtension``, +``SessionExtension`` are superseded by ``event.listen()``, +using the ``MapperEvents``/``InstanceEvents``, +``AttributeEvents``, ``SessionEvents``, dispatch targets, +respectively. + +Sending a string to 'distinct' in select() for MySQL should be done via prefixes +-------------------------------------------------------------------------------- + +This obscure feature allows this pattern with the MySQL +backend: + +:: + + select([mytable], distinct='ALL', prefixes=['HIGH_PRIORITY']) + +The ``prefixes`` keyword or ``prefix_with()`` method should +be used for non-standard or unusual prefixes: + +:: + + select([mytable]).prefix_with('HIGH_PRIORITY', 'ALL') + +``useexisting`` superseded by ``extend_existing`` and ``keep_existing`` +----------------------------------------------------------------------- + +The ``useexisting`` flag on Table has been superseded by a +new pair of flags ``keep_existing`` and ``extend_existing``. +``extend_existing`` is equivalent to ``useexisting`` - the +existing Table is returned, and additional constructor +elements are added. With ``keep_existing``, the existing +Table is returned, but additional constructor elements are +not added - these elements are only applied when the Table +is newly created. + +Backwards Incompatible API Changes +================================== + +Callables passed to ``bindparam()`` don't get evaluated - affects the Beaker example +------------------------------------------------------------------------------------ + +:ticket:`1950` + +Note this affects the Beaker caching example, where the +workings of the ``_params_from_query()`` function needed a +slight adjustment. If you're using code from the Beaker +example, this change should be applied. + +types.type_map is now private, types._type_map +---------------------------------------------- + +We noticed some users tapping into this dictionary inside of +``sqlalchemy.types`` as a shortcut to associating Python +types with SQL types. We can't guarantee the contents or +format of this dictionary, and additionally the business of +associating Python types in a one-to-one fashion has some +grey areas that should are best decided by individual +applications, so we've underscored this attribute. + +:ticket:`1870` + +Renamed the ``alias`` keyword arg of standalone ``alias()`` function to ``name`` +-------------------------------------------------------------------------------- + +This so that the keyword argument ``name`` matches that of +the ``alias()`` methods on all ``FromClause`` objects as +well as the ``name`` argument on ``Query.subquery()``. + +Only code that uses the standalone ``alias()`` function, and +not the method bound functions, and passes the alias name +using the explicit keyword name ``alias``, and not +positionally, would need modification here. + +Non-public ``Pool`` methods underscored +--------------------------------------- + +All methods of ``Pool`` and subclasses which are not +intended for public use have been renamed with underscores. +That they were not named this way previously was a bug. + +Pooling methods now underscored or removed: + +``Pool.create_connection()`` -> +``Pool._create_connection()`` + +``Pool.do_get()`` -> ``Pool._do_get()`` + +``Pool.do_return_conn()`` -> ``Pool._do_return_conn()`` + +``Pool.do_return_invalid()`` -> removed, was not used + +``Pool.return_conn()`` -> ``Pool._return_conn()`` + +``Pool.get()`` -> ``Pool._get()``, public API is +``Pool.connect()`` + +``SingletonThreadPool.cleanup()`` -> ``_cleanup()`` + +``SingletonThreadPool.dispose_local()`` -> removed, use +``conn.invalidate()`` + +:ticket:`1982` + +Previously Deprecated, Now Removed +================================== + +Query.join(), Query.outerjoin(), eagerload(), eagerload_all(), others no longer allow lists of attributes as arguments +---------------------------------------------------------------------------------------------------------------------- + +Passing a list of attributes or attribute names to +``Query.join``, ``eagerload()``, and similar has been +deprecated since 0.5: + +:: + + # old way, deprecated since 0.5 + session.query(Houses).join([Houses.rooms, Room.closets]) + session.query(Houses).options(eagerload_all([Houses.rooms, Room.closets])) + +These methods all accept \*args as of the 0.5 series: + +:: + + # current way, in place since 0.5 + session.query(Houses).join(Houses.rooms, Room.closets) + session.query(Houses).options(eagerload_all(Houses.rooms, Room.closets)) + +``ScopedSession.mapper`` is removed +----------------------------------- + +This feature provided a mapper extension which linked class- +based functionality with a particular ``ScopedSession``, in +particular providing the behavior such that new object +instances would be automatically associated with that +session. The feature was overused by tutorials and +frameworks which led to great user confusion due to its +implicit behavior, and was deprecated in 0.5.5. Techniques +for replicating its functionality are at +[wiki:UsageRecipes/SessionAwareMapper] + diff --git a/doc/build/conf.py b/doc/build/conf.py index 7985b35b24..245a84b80d 100644 --- a/doc/build/conf.py +++ b/doc/build/conf.py @@ -11,7 +11,8 @@ # All configuration values have a default; values that are commented out # serve to show the default. -import sys, os +import sys +import os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -33,7 +34,14 @@ import sqlalchemy # 'sphinx.ext.doctest', 'builder.builders'] extensions = ['sphinx.ext.autodoc', - 'sphinx.ext.doctest', 'builder.builders'] + 'sphinx.ext.doctest', + 'sphinx.ext.doctest', + 'builder.autodoc_mods', + 'builder.changelog', + 'builder.dialect_info', + 'builder.mako', + 'builder.sqlformatter', + ] # Add any paths that contain templates here, relative to this directory. # not sure why abspath() is needed here, some users @@ -45,7 +53,19 @@ nitpicky = True # The suffix of source filenames. source_suffix = '.rst' -template_bridge = "builder.builders.MakoBridge" +# section names used by the changelog extension. +changelog_sections = ["general", "orm", "orm declarative", "orm querying", \ + "orm configuration", "engine", "sql", \ + "schema", \ + "postgresql", "mysql", "sqlite", "mssql", \ + "oracle", "firebird"] +# tags to sort on inside of sections +changelog_inner_tag_sort = ["feature", "bug", "moved", "changed", "removed"] + +# how to render changelog links +changelog_render_ticket = "http://www.sqlalchemy.org/trac/ticket/%s" +changelog_render_pullreq = "https://bitbucket.org/sqlalchemy/sqlalchemy/pull-request/%s" +changelog_render_changeset = "http://www.sqlalchemy.org/trac/changeset/%s" # The encoding of source files. #source_encoding = 'utf-8-sig' diff --git a/doc/build/index.rst b/doc/build/index.rst index e4c7d5f680..8a64239a91 100644 --- a/doc/build/index.rst +++ b/doc/build/index.rst @@ -10,8 +10,9 @@ Getting Started A high level view and getting set up. :ref:`Overview ` | -:ref:`Installation Guide ` | -:ref:`Migration from 0.6 ` +:ref:`Installation Guide ` | +:doc:`Migration from 0.6 ` | +:doc:`Changelog catalog ` SQLAlchemy ORM ============== diff --git a/doc/build/intro.rst b/doc/build/intro.rst index 7c653e575d..471fb622cf 100644 --- a/doc/build/intro.rst +++ b/doc/build/intro.rst @@ -189,5 +189,4 @@ Python prompt like this: 0.6 to 0.7 Migration ===================== -Notes on what's changed from 0.6 to 0.7 is available on the SQLAlchemy wiki at -`07Migration `_. +Notes on what's changed from 0.6 to 0.7 is available at :doc:`changelog/migration_07`. diff --git a/doc/build/static/docs.css b/doc/build/static/docs.css index 23c3abe632..c0dbdcb289 100644 --- a/doc/build/static/docs.css +++ b/doc/build/static/docs.css @@ -7,7 +7,7 @@ body { } a { - font-weight:normal; + font-weight:normal; text-decoration:none; } @@ -29,7 +29,7 @@ a:hover { /* paragraph links after sections. These aren't visible until hovering - over the tag, then have a + over the tag, then have a "reverse video" effect over the actual link */ @@ -226,13 +226,20 @@ a.headerlink:hover { #docs-body h1 { /* hide the

for each content section. */ display:none; - font-size:1.8em; + font-size:2.0em; } #docs-body h2 { - font-size:1.6em; + font-size:1.8em; + border-top:1px solid; + /*border-bottom:1px solid;*/ + padding-top:20px; } +#sqlalchemy-documentation h2 { + border-top:none; + padding-top:0; +} #docs-body h3 { font-size:1.4em; } @@ -252,7 +259,7 @@ a.headerlink:hover { } #docs-container pre { - background-color: #f0f0f0; + background-color: #f0f0f0; border: solid 1px #ccc; box-shadow: 2px 2px 3px #DFDFDF; padding:10px; @@ -284,7 +291,7 @@ a.headerlink:hover { line-height:1.2em; } -#docs-container a.sql_link, +#docs-container a.sql_link, #docs-container .sql_link { text-decoration: none; @@ -298,13 +305,21 @@ a.headerlink:hover { background-color: #900; } +/* changeset stuff */ + +#docs-container a.changeset-link { + font-size: 0.8em; + padding: 0 4px 0 4px; + text-decoration: none; +} + /* docutils-specific elements */ th.field-name { text-align:right; } -div.note, div.warning, p.deprecated, div.topic { +div.note, div.warning, p.deprecated, div.topic, div.admonition { background-color:#EEFFEF; } @@ -313,6 +328,14 @@ div.admonition, div.topic, p.deprecated, p.versionadded, p.versionchanged { border:1px solid #CCCCCC; padding:5px 10px; font-size:.9em; + margin-top:5px; + box-shadow: 2px 2px 3px #DFDFDF; +} + +div.inherited-member { + border:1px solid #CCCCCC; + padding:5px 5px; + font-size:.9em; box-shadow: 2px 2px 3px #DFDFDF; } @@ -353,6 +376,7 @@ dl.glossary > dt { font-size:1.1em; } + dt:target, span.highlight { background-color:#FBE54E; } @@ -404,7 +428,7 @@ tt { .go {color:#804049;} -/* special "index page" sections +/* special "index page" sections with specific formatting */ diff --git a/test/orm/test_attributes.py b/test/orm/test_attributes.py index 472b5f8e10..7a4ef038e8 100644 --- a/test/orm/test_attributes.py +++ b/test/orm/test_attributes.py @@ -1429,10 +1429,10 @@ class HistoryTest(fixtures.TestBase): useobject=True) return Foo, Bar - def _someattr_history(self, f): + def _someattr_history(self, f, **kw): return attributes.get_state_history( attributes.instance_state(f), - 'someattr') + 'someattr', **kw) def _commit_someattr(self, f): attributes.instance_state(f).commit(attributes.instance_dict(f), @@ -1600,6 +1600,12 @@ class HistoryTest(fixtures.TestBase): assert 'someattr' not in f.__dict__ assert 'someattr' not in attributes.instance_state(f).committed_state + def test_collection_never_set(self): + Foo = self._fixture(uselist=True, useobject=True, + active_history=True) + f = Foo() + eq_(self._someattr_history(f, passive=True), ((), [], ())) + def test_scalar_active_set(self): Foo = self._fixture(uselist=False, useobject=False, active_history=True) -- 2.47.2