Since Odoo 13.0 and the refactor of the internal synchronisation between
the cache and the database, it is unsafe to use the ORM with the cursor
in autocommit mode. The function is deprecated for removal in the
future.
closesodoo/odoo#68313
Task: 2442905
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
The goal of this change is to simplify the code managing `create_date`
and `write_date` in methods `create()` and `write()`, and also to remove
weird behaviors caused by the way those fields were updated.
Assume we update a simple field on a record. This adds pending updates
for the field and `write_date`. However, the value of `write_date` is
not known yet: it will be updated as `NOW() AT TIME ZONE 'UTC'` in SQL.
So `write_date` is actually given a dummy value in pending updates, and
it is invalidated from cache, until its value is flushed to the database
and fetched again.
Now assume we access another field on the record, and that field is not
in cache. The prefetching mechanism will read all column fields,
including `write_date`, and flush them first.
# this adds pending updates foo: 42, write_uid: 1, write_date: False
record.foo = 42
# assume 'bar' is not in cache; this prefetches all column fields,
# which flushes the pending updates above before reading them back
result = record.bar
We can avoid flushing pending updates if the values read from database
do not overwrite existing values in cache. If you assume that the value
of a pending update is in cache (in the example, `foo: 42`), you don't
need to flush the corresponding field. Indeed, the value of `foo` will
remain 42 in cache, whatever its value in the database. This assumption
(pending updates are in cache) is true for all fields *except* for
`write_date`: it is invalidated from cache, and given a dummy value in
pending updates. This branch actually makes this assumption true for
all fields. The avoidance of flushing pending updates will be done in
another commit.
In order to directly assign `write_date` its value, we use a cache for
the value `NOW() AT TIME ZONE 'UTC'` from the database. This costs at
most one query per transaction, and potentially saves a few queries.
Co-authored-by: Victor Feyens <vfe@odoo.com>
Before this change the rollback hooks were never called since rollback() was never explicitely called by the framework. At the end of a transaction, if no error occurs the famework call commit() on the odoo cursor. In all cases, the transaction ends with a call to close(). Into the implementation of _close() rollback() is called on the underlying connection to ensure that not committed changes are rollbacked. That's the reason why despite the fact that rollback() was not called on the Odoo cursor, changes are not committed into the db in case of exception. To keep the same behaviour and avoid to have to explicitely call rollback() on the odoo cursor to trigger the execution of registered rollback hooks, these hooks are now processed in _close(). Since the list of registered hooks is emptied if commit() is called, we are sure that rollback hooks are only executed in case of rollback.
OPW #2294911closesodoo/odoo#60339
X-original-commit: dce9a05f3a5d37fab711c8ca3c5444941f98e814
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
Co-authored-by: Raphael Collet <rco@odoo.com>
This fixes a crash in some controllers with `auth='None'` where some
updates are flushed with an environment where `uid=None`. When there is
an environment with a real uid, preferably use it.
closesodoo/odoo#59658
X-original-commit: 2795c86df54389b858a454cbc1782b1f34f3ba4f
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
Python 3.8 changed the equality rules for bound methods to be based on
the *identity* of the receiver (`__self__`) rather than its *equality*.
This means that in 3.7, methods from different instances will compare
(and hash) equal, thereby landing in the same map "slot", but that isn't
the case in 3.8.
While it's usually not relevant, it's an issue for `GroupCalls` which is
indexed by a function: in 3.7, that being a method from recordsets
comparing equal will deduplicate them, but not anymore in 3.8, leading
to duplicated callbacks (exactly the thing GroupCalls aims to avoid).
Also, the API of `GroupCalls` turned out to be unusual and weird. The
bug above is fixed by using a plain list for callbacks, thereby avoiding
comparisons between registered functions. The API is now:
callbacks.add(func) # add func to callbacks
callbacks.run() # run all callbacks in addition order
callbacks.clear() # remove all callbacks
In order to handle aggregated data, the `callbacks` object provides a
dictionary `callbacks.data` that any callback function can freely use.
For the sake of consistency, the `callbacks.data` dict is automatically
cleared upon execution of callbacks.
Discovered by @william-andre
Related to odoo#56583
References:
* https://bugs.python.org/issue1617161
* python/cpython#7848
* https://docs.python.org/3/whatsnew/changelog.html#python-3-8-0-alpha-1
(no direct link because individual entries are not linkable, look for
bpo-1617161)
X-original-commit: d4b2e9224839aed8fc160ebe5a89e0f7d4c6a5bb
Upon cursor `commit()`, the pending computations are performed with
method `flush()`. However the latter method leaves fields to compute on
new records. As the `commit` ends the current transaction, we can clear
those pending computations.
X-original-commit: d27e98d9048d0cb1250522205286ebc7b7d5ea39
- A bug has been introduced by the PR https://github.com/odoo/odoo/pull/46719
This issue prevented flushes to database when no `uid` is set in the
current environment.
This happens when database changes are made in `auth="none"` routes.
In a MonoDB setup this was working because Odoo consider `None`, `False` as
`null` and was always bound to a database.
Nothing prevents to write `null` in the columns `create_uid` and
`write_uid` in database.
The PR that introduced the bug wanted to block the cases where
`uid` is an instance of the class `RequestUID` to avoid `Cannot adapt
type` errors.
So testing that `uid` is an integer isn't enough.
Two fixes were possible here, either check if `uid` is an instance
of the class `RequestUID` or if it is either an integer, `False` or `None`.
To avoid noise and imports from `odoo`, we test that `uid` is an instance
of `None`.
The case where it is `False` is already tested in the python code:
```python
isinstance(env.uid, int)
```
(manual) forward-port of odoo/odoo#48685closesodoo/odoo#48693
Signed-off-by: Toufik Benjaa (tbe) <tbe@odoo.com>
Signed-off-by: Olivier Dony (odo) <odo@openerp.com>
When routing an HTTP request, the dispatcher uses an environment with a
placeholder for the user (the object `RequestUID`). This environment is
not supposed to be used after routing has been done. However, the
flushing function takes any environment with a given cursor, and it
crashes when this environment is chosen (`psycopg2` cannot adapt the
type `RequestUID` for `write_uid`), and simply does not make sense.
closesodoo/odoo#48495
X-original-commit: da61a64bf6731a08557d23680eabf4d910035ebd
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
The `__closer` attribute is filled with the origin of a call to
`cr.close()`. That information is reused in the `check` decotator that
ensure the user is not using a closed cursor. In case he is using a
closed cursor, an error is raised with that optional origin in case of
`--log-sql`.
The attribute is a dundler so it is only accessible within its class, as
the decorator has been moved outside of the class by 058cf208a8 it is
not directly accessible thus `__getattr__` is called as a fallback. The
`__getattr__` itself is protected by the `check` decorator thus they
call each other in a infinite recursion.
As the related dundler is no more used internally, it has been decided
to remove it entirely.
closesodoo/odoo#47616
Task: 2199895
X-original-commit: 3ebf7cb9cca37b05f44aaffc0b1f289cc65f300f
Signed-off-by: Julien Castiaux <Julien00859@users.noreply.github.com>
Starting with Python 3, queries sent by psyocopg2 are stored as `bytes()` objects.
Logging those raw makes them appear unformatted, harder to read than in v10 or lower Odoo versions (i.e. `\n` instead of a raw newline character).
Decoding the query into unicode makes it easier to read in the logs.
closesodoo/odoo#38074
X-original-commit: 329accde2ed6d4dbfdde6d3d99d71e21d15396b7
Signed-off-by: Christophe Simonis <chs@odoo.com>
[`psycopg2` includes a submodule called `sql`][1] which provides more safety and comfort when dealing with raw SQL queries.
As of today, it works fine with Odoo unless SQL query logging is enabled.
This patch fixes that problem, allowing usage of that module.
[1]: http://initd.org/psycopg/docs/sql.htmlclosesodoo/odoo#37561
Signed-off-by: Christophe Simonis <chs@odoo.com>
When creating a new database from the database manager, with no open
cursor, the wrong env was retrieved during the cr.commit() call.
2019-09-09 18:16:07,454 19886 ERROR None odoo.service.db: CREATE DATABASE failed:
Traceback (most recent call last):
File "/home/odoo/odoo/service/db.py", line 60, in _initialize_db
cr.commit()
File "/home/odoo/odoo/sql_db.py", line 165, in wrapper
return f(self, *args, **kwargs)
File "/home/odoo/odoo/sql_db.py", line 389, in commit
env = get_env(currentframe(), 2)
File "/home/odoo/odoo/sql_db.py", line 72, in get_env
env = getattr(frame.f_locals.get('self'), 'env', SENTINEL)
File "/home/odoo/odoo/http.py", line 268, in env
self._env = odoo.api.Environment(self.cr, self.uid, self.context)
File "/home/odoo/odoo/http.py", line 238, in cr
raise RuntimeError('request not bound to a database')
get_env method checks every frame to find a variable called 'env'
As none was found, it used the one of the WebRequest object.
In a WebRequest, env is a property that will try to create a new
Environment, which fails as no database is available (yet).
At eafdf1812d the iteration on Environment.envs was removed as envs
is a weakset and it introduced potential errors where the content was
garbage-collected during the iteration.
Go back to the simpler iteration but convert the set to list to avoid
garbage-collection issues.
Fixesodoo/odoo#36588closesodoo/odoo#37005
Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
Co-authored-by: Raphael Collet <rco@odoo.com>
ee03fc3770 introduced a non deterministic bug by choosing an
environment in a set, so the environment is not always the good one.
closesodoo/odoo#36056
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
This branch is the combination of several optimizations in the ORM:
* store field values once in the cache: the cache reflects more
faithfully the database, only fields that explicitly depend on the
context have an extra indirection in the cache;
* delay recomputations by default: use method `recompute` to explicitly
flush out pending recomputations;
* delay updates in method `write`: updates are stored in a data
structure that can be flushed efficiently to the database with method
`flush` (which also flush out recomputations);
* make method `modified` take advantage of inverse fields to inverse
dependencies;
* filter records by evaluating a domain on records in Python;
* a computed field with `readonly=False` behaves like a normal field
with an onchange method;
* computed fields are computed in superuser mode by default.
Work done by Toufik Ben Jaa, Raphael Collet, Denis Ledoux and Fabien
Pinckaers.
closesodoo/odoo#35659
Signed-off-by: Denis Ledoux <beledouxdenis@users.noreply.github.com>
This commit replaces calls to pycompat helpers that were intended for
python 2 <-> python 3 interoperability for python 3 builtins, as python
2 is no longer officially supported by Odoo.
This includes:
* calls to imap/izip/ifilter replaced by map/zip/filter
* uses of text_type replaced by str
* uses of unichr replaced by chr
* calls to implements_to_string, implements_iterator removed
* string_types and integer_types replaced by str, int respectively
* calls to to_native replaced by calls to to_text
This is done in preparation to the removal of these deprecated helpers
in the following commit.
When there is a performance issue, it's sometimes difficult to discover
which request increased the query count or its duration.
With this commit, the query count, the query time and "python and io" time are displayed
in the logs at the end of each werkzeug request line.
Co-authored-by: Christophe Monniez <moc@odoo.com>
From this commit onwards, Date fields will return datetime.date objects and Datetime fields will return datetime.datetime objects, this implies a number of things that are clearly explained both in the ORM API for master.
This commit also introduces a number of helper functions for dates and datetimes that are exposed in tools.date_utils and fields.Date[time], explained in the documentation as well.
Task-ID: 47189
Since 1a58e108 (on 10.0 and over) parameters are no longer present when
logging sql queries.
This removes some of the usefulness of the feature, and this commit adds
them back.
Since mogrify returns a byte string in the database encoding, we decode
it using the corresponding python encoding.
opw-1839241
closes#24446
This allows rpc requests in `HttpCase` to use the cursor `self.cr`, which is
now shared between the Python test and the rpc requests. This simplifies code
to prepare a JS test, and code to check the result of a JS tour.
Fixes#12237
Now that we're closer to switching to P3 for good, these helpers have
outlived their usefulness, and mostly add noise.
All remaining dict.iter*() or dict.view*() must be converted to the
normal keys(), values() or items() calls.
Whenever the result is likely to be used for more than the scope of a
loop, or when the dict needs to be modified during iteration, the calls
must be wrapped in a ``list()``, to protect the new P3 semantics.
Those cases are very exceptional.
Also removed some dead code or improved the API to remove unnecessary
conversions.
NUL characters must not be used in query parameters,
as they will be ignored by libpq, being end-of-string
characters.
Preventing NULs avoids unexpected results from
queries. It is only necessary with psycopg2
versions before 2.7, which includes the upstream
fix.
In Python 3, all of these were "consolidated" under urllib(.request,
.parse, .errors) which is inconvenient.
Since we already have hard dependencies on requests and
werkzeug(.urls, which is a backport of Python 3's unicode-aware
urllib.parse) migrate *everything* to that.
A sticking point is urllib2.URLError, those were (mostly) replaced by
the slightly more general IOError which URLError extends.
In Python 3:
* various builtins and dict methods were changed to return
view/iterable objects rather than lists
* and the separate Python 2 view/iterable builtins and methods were
removed altogether
This is problematic when using these items as list (which the happens
repeatedly in Odoo), but more viciously when iterating *multiple times*
over them (which also happens, which I've messed up multiple times while
writing this, and which is a pain to debug even when you've just created
the issue).
Convert all code using these to semantics-matching cross-version
helper functions to get the LCD behaviour between P2 and P3, and
forbid the builtins via lint.
issue #8530
Purpose:
When we have a SQL error, it's not very easy to identify the root of the crash. For example if a mandatory field is not set on a row creation, it difficult to see which field isn't correctly set as a lot of fields are not required and a lot a NULL values are present in the INSERT querry.
Specification:
Show a proper log message, with the reason (cause) of the sql error.
Behavior Modification Examples:
Some sample log after applied fix. The new line are those beginning by '+'
2016-10-25 09:59:40,208 21161 INFO ent_master odoo.sql_db: bad query: INSERT INTO "res_partner_category" ("id", "active", "color", "create_uid", "write_uid", "create_date", "write_date") VALUES(nextval('res_partner_category_id_seq'), true, 10, 1, 1, (now() at time zone 'UTC'), (now() at time zone 'UTC')) RETURNING id
+REASON: null value in column "name" violates not-null constraint
+DETAIL: Failing row contains (27, null, null, 1, null, 10, 1, null, 2016-10-25 09:59:40.207202, t, 2016-10-25 09:59:40.207202).
2016-10-25 10:00:29,710 21161 INFO ent_master odoo.sql_db: bad query: UPDATE "res_partner" SET "parent_id"=1001,"type"='contact',"name"='Course Script',"company_name"=NULL,"write_uid"=1,"write_date"=(now() at time zone 'UTC') WHERE id IN (1)
+REASON: insert or update on table "res_partner" violates foreign key constraint "res_partner_parent_id_fkey"
+DETAIL: Key (parent_id)=(1001) is not present in table "res_partner".
2016-10-25 10:23:28,690 21336 INFO ent_master odoo.sql_db: bad query: DELETE FROM res_country WHERE id IN (235)
+REASON: null value in column "country_id" violates not-null constraint
+DETAIL: Failing row contains (9, 1, AL, Alabama, null, 1, 2016-10-24 10:19:58.765552, 2016-10-21 09:32:26.939607).
+CONTEXT: SQL statement "UPDATE ONLY "public"."res_country_state" SET "country_id" = NULL WHERE $1 OPERATOR(pg_catalog.=) "country_id""