This follows up e045e76e35.
Change the heuristics for ordering columns, as padding is not determined
by column size, but by column alignment inside a row. Because in Odoo a
row always starts with a column of size 4, the following columns should
be the ones aligned on 4 bytes, then the ones aligned on 1 byte, then
the ones aligned on 8 bytes.
The analysis in the commit message of e045e76e was not correct, as it
did not take into account the fact that rows themselves are aligned on 8
bytes. So we have: before each row used 40 bytes (+24b header)
attname | typname | typlen
-------------+-----------+--------
id | int4 | 4
create_uid | int4 | 4
create_date | timestamp | 8
write_uid | int4 | 4 -> 4 bytes padding
write_date | timestamp | 8
active | bool | 1 -> 7 bytes padding
After each row uses 32 bytes (8 bytes saved per row):
attname | typname | typlen
-------------+-----------+--------
id | int4 | 4
create_uid | int4 | 4
write_uid | int4 | 4
active | bool | 1 -> 3 bytes padding
create_date | timestamp | 8
write_date | timestamp | 8
Of course, when more columns are present, the space savings depend on
the alignment of the other columns.
closesodoo/odoo#88084
Signed-off-by: Vincent Schippefilt (vsc) <vsc@odoo.com>
Postgres is aligning columns to 4 or 8 bytes, depending on their type.
So, consecutive fixed-length columns of differing size will be padded
with empty bytes due to the alignment requirements.
Before this patch, columns where created in their definition order. Now,
they are ordered based on their size, in order to minimize the padding.
As an example, before each row uses 36 bytes (+24b header):
attname | typname | typlen
-------------+-----------+--------
id | int4 | 4
create_uid | int4 | 4
create_date | timestamp | 8
write_uid | int4 | 4 -> 4 bytes padding
write_date | timestamp | 8
active | bool | 1 -> 3 bytes padding
After each row uses 32 bytes (4 bytes saved per row):
attname | typname | typlen
-------------+-----------+--------
id | int4 | 4
create_uid | int4 | 4
write_uid | int4 | 4
active | bool | 1 -> 3 bytes padding
create_date | timestamp | 8
write_date | timestamp | 8
This saving scheme applies to all rows in all tables. We save between 4
and 8 bytes per row just on the usual create_uid, create_date,
write_uid, write_date.
closesodoo/odoo#87896
Signed-off-by: Raphael Collet <rco@odoo.com>
The possible index names have been renamed "btree", "btree_not_null"
(instead of "not null") and "trigram" (instead of "gin").
Task 2742526
Part-of: odoo/odoo#83274
Three supported types:
- btree (default for index=True)
- btree not null (when >90% of the data are null)
- gin trigram search (for char fields)
Review of indexes on all objects.
closesodoo/odoo#83015
Signed-off-by: Fabien Pinckaers <fp@odoo.com>
* add configuration for `flake8[flake8-rst-docstring]`
* enable docstring-related checks
* fix invalid docstrings in odoo's core & `base`
* fix a few more bits (mostly missing or incorrect `:param:` info
fields) are out of scope for the lint but my editor catches
closesodoo/odoo#74604
Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
When computing the foreign key name,
`check_foreign_keys` didn't take into account the limit of 63 characters
for constraint names.
Because of this, some constraints were dropped and recreated
over and over while they were correct, during install and upgrades.
For instance, when installing `base`
when adding the foreign key for which the name was computed
`base_partner_merge_automatic_wizard_res_partner_rel_base_partner_merge_automatic_wizard_id_fkey`
Postgresql created the constraint under the name
`base_partner_merge_automatic__base_partner_merge_automatic_fkey`
and therefore, as the name did not match,
the constraint was dropped and re-created.
closesodoo/odoo#72234
X-original-commit: 43a4738ebf8a74a389b99f8f58330b3044beaa0c
Signed-off-by: Denis Ledoux (dle) <dle@odoo.com>
Before 1721ec1363 and fdc4ef97c9, Odoo did work fine when the
user had another default schema than 'public'.
This commit restores this behaviour by searching
for existing objects in the user's current schema,
which is the first in the schema search path and
the one used when no schema is specified when
creating objects.
closesodoo/odoo#68144
X-original-commit: 223781b34afacd1c0c5674d395cece6d472b048c
Signed-off-by: Olivier Dony (odo) <odo@openerp.com>
*blog, forum, slides
Based on https://github.com/odoo/odoo/pull/48552#discussion_r440061218 suggestion
Add a new method 'increment_skip_lock' in tools.sql to allow to easily
increment a specific field of 1 if the record is not locked.
The method return boolean if at least 1 record has been incremented.
closesodoo/odoo#58765
X-original-commit: d92e61e89f468c2db2fbd68b2f0d6b36c77f1065
Signed-off-by: Jérémy Kersten (jke) <jke@openerp.com>
Create the table with all the columns from scratch, with the NOT NULL
constraint when required. Also do not call `_check_removed_columns()`
on a new table.
This saves 0.5% of the total installation time.
X-original-commit: 0727cacf5194a143b15ab4cb9893f3035a67be1f
Collisions in table names of ORM models with built-in PG structures such
as "attributes", "domains", "routines", "parameters", ... could occur
and render the result of `table_kind` meaningless.
Based on what was done via https://github.com/odoo/odoo/pull/16651 more
than 2 years ago, it seems relying on our tables being in the 'public'
schema is safe, even though it's only a default from PG. We reuse that
same logic rather than the alternative of excluding
('information_schema', 'pg_catalog', ...), even though it looks safer at
first. If we did the latter we'd have to change the other comparison for
consistency, i.e. more risks.
closesodoo/odoo#42358
X-original-commit: d8e74eb14990c82f65a44ffe163aa84159d6ccc4
Signed-off-by: Denis Vermylen <Icallhimtest@users.noreply.github.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>
and use it to determine if the constraint definition was changed. This prevents
endless readding of constraints that are reformatted by postgresql in an
unrecognizable way (in which e.g. "CHECK (credit*debit=0)" becomes
"CHECK ((credit * debit) = 0::numeric)")
Avoid `SELECT *` on `information_schema.columns` because specific access
right restrictions in the context of shared hosting (Heroku, OVH, ...)
might prevent a postgres user to read this field.
Problem: the update of custom models/fields is not fully transactional, and may
potentially lead to an inconsistent database. An other problem is creating two
custom fields by writing on a model: if the second one fails, the first one has
been committed without notice. Retrying the request will give an unexpected
error (duplicate field name).
Solution: never commit in the middle of a request. If the changes have an
impact on the registry, then mark it as invalid (with a new flag), and signal
registry invalidation after everything has been committed. If the request
fails, reset the registry. Both registry and cache invalidation are handled
the same way.
The dictionary `_group_by_full` is replaced by a field parameter `group_expand`
that is assigned to the method name. The API of the method has been simplified
as well:
@api.multi
def _read_group_stage_ids(self, domain, read_group_order=None, access_rights_uid=None):
# the stages are given by self.ids (wrong model);
# read_group_order is the order given to read_group() on self;
# return stages.name_get(), {stage.id: stage.fold)
_group_by_full = {'stage_id': _read_group_stage_ids}
is now written:
stage_id = fields.Many2one(..., group_expand='_read_group_stage_ids')
@api.model
def _read_group_stage_ids(self, stages, domain, order):
# stages is a recordset;
# order is the order to use on stages' model;
# return a recordset which is a superset of stages