schema update with doctrine2 postgresql always DROPs and then ADDs CONSTRAINTs - postgresql

When updating schema, doctrine always drops and add constraints. I think, it is something wrong...
php app/console doctrine:schema:update --force
Updating database schema...
Database schema updated successfully! "112" queries were executed
php app/console doctrine:schema:update --dump-sql
ALTER TABLE table.managers DROP CONSTRAINT FK_677E81B7A76ED395;
ALTER TABLE table.managers ADD CONSTRAINT FK_677E81B7A76ED395 FOREIGN KEY (user_id) REFERENCES table."user" (id) NOT DEFERRABLE INITIALLY IMMEDIATE;
...
php app/console doctrine:schema:validate
[Mapping] OK - The mapping files are correct.
[Database] FAIL - The database schema is not in sync with the current mapping file.
How can this may be fixed?

After some digging into doctrine update schema methods, I've finally found an issue. The problem was with table names - "table.order" and "table.user". When doctrine makes diff, this names become non equal, because of internal escaping (?). So, "user" != user, and foreign keys to those tables (order, user) always recreating.
Solution #1 - just rename tables to avoid name matching with postgresql keywords, like my_user, my_order.
Solution #2 - manually escape table names. This not worked for me, tried many different escaping ways.
I've applied solution #1 and now I see:
Nothing to update - your database is already in sync with the current
entity metadata

I have had the same issue on Postgres with a uniqueConstraint with a where clause.
* #ORM\Table(name="avatar",
* uniqueConstraints={
* #ORM\UniqueConstraint(name="const_name", columns={"id_user", "status"}, options={"where": "(status = 'pending')"})
Doctrine is comparing schemas from metadata and new generated schema, during indexes comparation where clauses are not matching.
string(34) "((status)::text = 'pending'::text)"
string(20) "(status = 'pending')"
You just have to change you where clause to match by
((avatar)::text = 'pending'::text)
PS: My issue was with Postgres database
I hope this will help someone.

I have come across this several times and it's because the php object was changed a few times and still does not match the mapping to the database. Basically a reboot will fix the issue but it can be ugly to implement.
If you drop the constraint in the database and php objects (remove the doctrine2 mappings), then update schema and confirm that nothing needs to be updated. Then add the doctrine mapping back to the php, update the schema using --dump-sql and review the changes that are shown. Confirm that this is exactly what you want and execute the update query. Now updating the schema should not show that anything else needs to be updated.

Related

A single Postgresql table is not allowing deletes and foreign keys are not working

We have a Postgresql database table with many tables. All of the tables seem to be functioning perfectly except for 1. In the last day or two it has stopped performing row deletes. When we try something simple like
delete from bad_table where id_foo = 123;
It acts as if it has successfully deleted the row. But when we do
select * from bad_table where id_foo = 123;
the row is still there.
The same type of queries work fine on all the other tables we tried.
In addition, the foreign keys on this table are not working. There is a foreign key constraint on a column that references a different table. There is an id in the "bad_table", but that id does not exist in the referenced table. Again, foreign key constraints appear to be working fine in all other tables, it is just this one. We tried dropping and recreating the foreign key (which seemed to be successful), but it had no effect.
Between my coworkers and myself we probably have 80 years of relational database experience across oracle, sql server, postgres, etc. and none of us has ever seen anything like this. We've been banging our heads against a wall and are now reaching out to the wider world to see if anyone has any ideas of what we could try. Has anyone else ever seen something like this in Postgres?
It turned out that the issue with foreign keys was solved by dropping the foreign key constraint and then immediately adding it again.
The issue with not being able to delete rows was fixed by dropping a trigger than was called on row delete and then immediate recreating the same trigger.
I don't know what happened, but it is acting like a constraint and a trigger on that particular table were corrupted.

How to ensure validity of foreign keys in Postgres

Using Postgres 10.6
The issue:
Some data in my tables violates the foreign key constraints (not sure how). The constraints are ON DELETE CASCADE ON UPDATE CASCADE
On a pg_dump of the database, those foreign keys are dropped (due to being in an invalid state?)
A pg_restore is done into a blank database, which no longer has the foreign keys
The new database has all its primary keys updated to valid keys not used in a second database. Tables which had invalid data do not have their foreign keys updated, due to the now missing constraint.
A pg_dump of the new database is done, then the database is deleted
On a pg_restore into a second database which has the foreign key constraints, the data gets imported in an invalid state, and corrupts the new database.
What I want to do is this: Every few hours (or once a day, depending of how long the query would take), is to verify that all data in all the tables which have foreign keys are valid.
I have read about ALTER TABLE ... VALIDATE CONSTRAINT ... but this wouldn't fix my issue, as the data is not currently marked as NOT VALID. I know could do statements like:
DELETE FROM a WHERE a.b_id NOT IN ( SELECT b.id )
However, I have 144 tables with foreign keys, so this would be rather tedious. I would also maybe not want to immediately delete the data, but log the issue and inform user about a correction which will happen.
Of course, I'd like to know how the original corruption occurred, and prevent that; however at the moment I'm just trying to prevent it from spreading.
Example table:
CREATE TABLE dependencies (
...
from_task int references tasks(id) ON DELETE CASCADE ON UPDATE CASCADE NOT NULL,
to_task int references tasks(id) ON DELETE CASCADE ON UPDATE CASCADE NOT NULL,
...
);
Dependencies will end up with values for to_task and from_task which do not exist in the tasks table (see image)
Note:
Have tried EXPLAIN ANALYZE nothing odd
pg_tablespace, has just two records. pg_default and pg_global
relforcerowsecurity, relispartition are both 'false' on both tables
Arguments to pg_dump (from c++ call) arguments << "--file=" + fileName << "--username=" + connection.userName() << databaseName << "--format=c"
This is either an index (or table) corruption problem, or the constraint has been created invalid to defer the validity check till later.
pg_dump will never silently "drop" a constraint — perhaps there was an error while restoring the dump that you didn't notice.
The proper fix is to clean up the data that violate the constraint and re-create it.
If it is a data corruption problem, check your hardware.
There is no need to regularly check for data corruption, PostgreSQL is not in the habit of corrupting data by itself.
The best test would be to take a pg_dump regularly and see if restoring the dump causes any errors.

How to set Ignore Duplicate Key in Postgresql while table creation itself

I am creating a table in Postgresql 9.5 where id is the primary key. While inserting rows in the table if anyone tries to insert duplicate id, i want it to get ignored instead of raising exception. Is there any way such that i can set this while table creation itself that duplicate entries get ignored.
There are many techniques to resolve duplicate insertion issue while writing insertion query i.e. using ON CONFLICT DO NOTHING, or using WHERE EXISTS clause etc. But i want to handle this at table creation end so that the person writing insertion query doesn't need to bother any.
Creating RULE is one of the possible solution. Are there other possible solutions? Maybe something like this:
`CREATE TABLE dbo.foo (bar int PRIMARY KEY WITH (FILLFACTOR=90, IGNORE_DUP_KEY = ON))`
Although exact this statement doesn't work on Postgresql 9.5 on my machine.
add a trigger before insert or rule on insert do instead - otherwise has to be handled by inserting query. both solutions will require more resources on each insert.
Alternative way to use function with arguments for insert, that will check for duplicates, so end users will use function instead of INSERT statement.
WHERE EXISTS sub-query is not atomic btw - so you can still have exception after check...
9.5 ON CONFLICT DO NOTHING is the best solution still

Postgres: Error constraint "fk" of relation "tbl" does not exist (with Yii - PHP)

I searched for this problem. But my postgres user has enough grant and I do not think I have misspelling error. However I am newbie.
I have this error message:
21:38:03 set search_path='public'
21:38:03 ALTER TABLE public.tbl_user DROP CONSTRAINT "fk-user-access-user-id"
21:38:03 ERROR: constraint "fk-user-access-user-id" of relation "tbl_user" does not exist
I use the PhpStorm. I just open the database view, expanded the tbl_user table, right click and select "drop". And I got this error in the console.
So the above SQL command generated by the PhpStorm.
Then I tried with these commands manually on Ubuntu:
ALTER TABLE tbl_user DROP CONSTRAINT "fk-user-access-user-id"
ALTER TABLE "tbl_user" DROP CONSTRAINT "fk-user-access-user-id"
But I get the same error.
In the PhpStorm I see this definition:
"fk-user-access-user-id" FOREIGN KEY (access_id) REFERENCES tbl_access (id)
The tbl_access table exists with the primary id key.
I do not understand this error message, because the "fk-user-access-user-id" foreign key is at the tbl_user and so for me the 'relation "tbl_user" does not exist' strange. I do not understand.
I tried to find similar problem on StackOverflow, but I gave up after 20x question reading.
By the way, the postgres code was generated by the Yii framework.
$this->addColumn('{{%user}}', 'access_id', $this->integer()->notNull()->defaultValue(1)->after('status'));
$this->addForeignKey('fk-user-access-user-id', '{{%user}}', 'access_id', '{{%access}}', 'id');
first row mean add access_id column to the user table.
second row: create foreign key with 'fk-user...' name on tbl_user table's access_id column references to tbl_access table's id column.
So I used this PHP code to generate this SQL commands. I prefer this way because for me the migration files are very useful.
Most likely the definition and actual implementation in your underlying DB has changed from what the app has recorded. Depending on what the history is, either a change in the app for that foreign key relationship was not migrated to persist the change at the database level, or someone has executed some operation directly at the DB level to remove the relationship. You will need to sync up the app layer to the DB at this point I would think.

Relation already exists during rake migration

I have installed a blog engine to refinerycms which is working perfectly.
Now I have generated a migration with some table fields changes (of course not refinerycms or blog tables), but I'm getting an error:
== CreateBlogStructure: migrating ============================================
-- create_table("refinery_blog_posts", {:id=>true})
NOTICE: CREATE TABLE will create implicit sequence "refinery_blog_posts_id_seq1" for serial column "refinery_blog_posts.id"
rake aborted!
An error has occurred, this and all later migrations canceled:
PG::Error: ERROR: relation "refinery_blog_posts" already exists
: CREATE TABLE "refinery_blog_posts" ("id" serial primary key, "title" character varying(255), "body" text, "draft" boolean, "published_at" timestamp, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
Tasks: TOP => db:migrate
(See full trace by running task with --trace)
Check your db/schema.rb
You most likely have the same table being created there in addition to a migration in db/migrate/[timestamp]your_migration
You can delete the db/migrate/[timestamp]your_migration if it is a duplicate of the one found in the schema and it should work.
PG::Error: ERROR: relation “refinery_blog_posts” already exists
Pg is a Rails gem, the piece of code that allows communication between Rails and PostgreSQL. It relates your migrations to SQL tables, thus a relation error. So, what the error is saying is:
I'm trying to create table X, based on migration X, but table X
already exists in the database.
Possible solutions:
Create migrations that drop those, probably old, tables.
Change the migration's name.
Login to PostgreSQL and drop the table. Something like:
$ psql -U username databasename
then
database_name=# drop table table-name;
The exact commands might be a little different though.
Adding as this is an obvious but easy to overlook cause of this error (and this is the first post search engines bring up).
If you accidentally defined the same relationship twice in the same migration this is the error that shows up.
def change
create_table :books do |t|
t.belongs_to :author
t.belongs_to :author # Duplicated column definition
end
end
Seems obvious but easy to overlook. To fix just remove the duplicated reference.