Rails3 SQLite3 DROP TABLE CASCADE error - ruby-on-rails-3

I have a project on Rails 3.0.2. Its rather big and working well with MySQL database.
But when I try to run it with SQLite database there is an error during migrations:
SQLite3::SQLException: near "CASCADE": syntax error: DROP TABLE "table_name" CASCADE
I searched and found that probably 'PRAGMA foreign_keys = ON' for SQLite will help.
So I have tried to add 'execute("PRAGMA foreign_keys = ON")' in migration right before 'DROP TABLE table_name' but this did not help.
How to turn foreign_keys ON for SQLite in Rails3?
Gems versions
sqlite3 (1.3.6)
sqlite3-ruby (1.3.3)

Here's the syntax diagram for SQLite's DROP TABLE:
In case the image moves, the syntax is like this:
drop table if exists db_name.table_name
where the if exists and db_name. parts are optional. There is no CASCADE in there so SQLite simply doesn't support CASCADE when using DROP TABLE and there's nothing you can do to add it (unless, of course, you want to hack the SQLite C source and add it yourself). You have to accept certain limitations when using SQLite, this is one of them.
If you want to use one migration for both SQLite and MySQL then you'll have to check which database is being used and execute the appropriate SQL or find something that works everywhere (i.e. perform the CASCADE by hand). The easy way to check which database you're using that I can think of right now would be:
case connection
when ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
# PostgreSQL things go here
when ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter
# MySQL things go here
when ActiveRecord::ConnectionAdapters::SQLiteAdapter
# SQLite things go here
...
end

Related

mysqldump not creating table, then attempting to LOCK / ALTER the non-existing table

Having several issues with a mysqldump on mysql Ver 14.14 Distrib 5.1.66, for unknown-linux-gnu (x86_64), first being:
A standard mysqldump is not creating a table, then attempting to LOCK / ALTER the non-existent table.
SQL query:
--Dumping data for table `catalog_product_index_price_cfg_opt_tmp`
LOCK TABLES `catalog_product_incatalog_category_entitydex_price_cfg_opt_tmp` WRITE;
MySQL said:
Documentation
#1146 - Table 'group_high.catalog_product_incatalog_category_entitydex_price_cfg_opt_tmp' doesn't exist.
Any idea on how this could be happening?
I've had similar issues in the past. And this answer might be similar to the "did you try turning it on". But how I have fixed it in the past is to close connection to DB then start again and make sure all the tables are there, and I can query that specific table. Then begin the MySQL. If it's still not outputting then you've narrowed the problem down to the dump.

Oracle create table with column comments

Is there a column comment syntax that allows me to specify a column comment directly where I declare the column in the create table statement (i.e. inline)? The 11g spec does not mention anything, on another page something is mentioned but I could not get it to work. There is a way to specify comments after creating the table, but I think it is annoying that the comment is separated from the field definition. I am looking for something like this (which does not work):
create table whatever (
field number(15,0) primary key comment 'primary key generated from sequence pkseq',
...
)
I'm afraid the "annoying" COMMENT ON syntax is the only way of doing this. SQL Server, PostgreSQL and DB2 use the same syntax (even though, as far as I know, there is no ANSI standard syntax for adding comments to database objects).
MySQL supports the way you would like it to work. I agree it would be a nicer mechanism, but in my experience so few people use comments at all that I doubt Oracle will ever change it.
I'm afraid it can only be done after table creation, using the comment on column ... is '' syntax.
A workaround to this annoying syntax is also to view and edit the tables in Oracles SQLExplorer. It contains a wizard that allows you to edit the comments right next to the columns. It even allows easy creation of alter table scripts.
My procedure when editing tables is to enter the changes in the wizard without actually executing them, then go to its DDL tab and retrieve the SQL from there (as update, not full create script) and press cancel on the wizard. Then I put the created SQL into the SQL script I am writing. Only when I am finished with the script I execute everything; I do never make any changes with the wizard itself.
Test on sqlplus (or similar), but the syntax is as follows:
-- assuming you have privileges
COMMENT ON COLUMN SCHEMA1.TABLE1.COL1
IS 'My comment'
-- then you can double check like this
SELECT * FROM all_col_comments WHERE
(OWNER, TABLE_NAME, COLUMN_NAME)
IN (('SCHEMA1','TABLE1','COL1'));
Note that the comment will now show in SQLDeveloper (or Toad or whatever env you have) until you reopen said table's properties.
Similar syntax can be used to annotate tables, indexes and materialized views. [source: https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_4009.htm]
I understand similar syntax exists for MySQL and others, but it is not proper ANSI. It's very useful, though.

Renaming SQLite Tables/Columns/Rows after indices have been created

If I rename SQLite Tables/Columns/Rows after indices have been created, will the old indices still be functional?
Thanks!
If you're using ALTER TABLE with RENAME TO to rename a table, then as described on this page (from the sqlite docs) the indices will still work:
The ALTER TABLE command in SQLite allows the user to rename a table [...] If the table being renamed has triggers or indices, then these remain attached to the table after it has been renamed.
But note there's no renaming of columns allowed. This is one of the SQL features not implemented by sqlite:
Only the RENAME TABLE and ADD COLUMN variants of the ALTER TABLE command are supported. Other kinds of ALTER TABLE operations such as DROP COLUMN, ALTER COLUMN, ADD CONSTRAINT, and so forth are omitted.
Rows don't have names (except in the sense of having a PK) so there's not really a way of renaming them.
I highly recommend using Rails ActiveRecord migrations to maintain your database. This can be done outside of Rails. So you app doesn't need to be a Rails app to use rake tasks
See here for an excellent blog on how to do this http://exposinggotchas.blogspot.com/2011/02/activerecord-migrations-without-rails.html
Yes, the old indices will still be functional.
Be aware, that sqlite doesn't care about the names for the indexes. Initially when an index is created usually they are named after the table and field, so when you rename the table, the indexes will still have the name of the old table in it. This can cause problems, when you for example:
dump the table
rename the old table:
sqlite3 "$DB" "PRAGMA busy_timeout=20000; ALTER TABLE '$TABLE' RENAME TO '$TABLE"_backup"'"
reimport the dumped table
This will cause an error, that the indexes already exist.
Solution: Rename the indexes too, or delete them in the renamed table before you reimport the original (see this answer).

symfony doctrine build-sql error

I have some big problems with symfony and doctrine at the beginning of a new project. I have created database diagram with mysql workbench, inserted the sql into phpmyadmin and then I've tried symfony doctrine:build-schema to generate the YAML schema.
It generates a wrong schema (relations don't have on delete/on update) and after this I've tried symfony doctrine:build --sql and symfony doctrine:insert-sql
The insert-sql statement generates error (can't create table ... failing query alter table add constraint ....), so I've decided to take a look over the generated sql and I've found out some differences between the sql generated from mysql workbench (which works perfect, including relations) and the sql generated by doctrine.
I'll be short from now: I have to tables, EVENT and FORM and a 1 to n relation (each event may have multiple forms) so the correct constraint (generated with workbench) is
ALTER TABLE `form` ADD CONSTRAINT `fk_form_event1` FOREIGN KEY (`event_id`) REFERENCES `event` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
doctrine generated statement is:
ALTER TABLE event ADD CONSTRAINT event_id_form_event_id FOREIGN KEY (id) REFERENCES form(event_id);
It's totally reversed and I am sure here is the error. What should I do? It's also correct like this?
It it broken, I've wrote the schema manually and it works perfect. I didn't want to do that because it was a very large file, but I've also learned from it!
Thank you guys!
To get both visual representation and automatic code generation you can use ORM Designer so you will have everything covered by one tool.

Dropping a group of tables in SQL Server

Is there a simple way to drop a group of interrelated tables in SQL Server? Ideally I'd like to avoid having to worry about what order they're being dropped in since I know the entire group will be gone by the end of the process.
At the risk of sounding stupid, I don't believe SQL Server supports the delete / cascade syntax. I think you can configure a delete rule to do cascading deletes (http://msdn.microsoft.com/en-us/library/ms152507.aspx), but as far as I know the trick with SQL Server is to just to run your drop query once for each table you're dropping, then check it worked.
I'm not sure, if Derek's approach works. You haven't mark it as best answer yet.
If not: with SQL Server 2005 it should be possible, I guess.
There they introduced exceptions (which I've not used yet). So drop the table, catch the exception, if one occurs and try the next table till they are all gone.
You can store the list of tables in a temp-table and use a cursor to traverse it, if you want to.
A diferent approach could be: first get rid of the constraints, then drop the tables in a single shot.
In other words, a DROP CONSTRAINT for every constraint, then a DROP TABLE for each table; at this point the order of execution shouldn't be an issue.
This requires the sp___drop___constraints script you can find at Database Journal:
sp_MSforeachtable #command1="print 'disabling constraints: ?'", #command2="sp_drop_constraints #tablename=?"
GO
sp_MSforeachtable #command1="print 'dropping: ?'", #command2="DROP TABLE ?"
GO
NOTE this - obviously - if you meant to drop ALL of the tables in your database, so be careful
I don't have access to SQL Server to test this, but how about:
DROP TABLE IF EXISTS table1, table2, table3 CASCADE;
I ended up using Apache's ddlutils to perform the dropping for me, which sorted it out in my case, though a solution which worked only within sql server would be quite a bit simpler.
#Derek Park, I didn't know you could comma separate tables there, so that's handy, but it doesn't seem to work quite as expected. Nether IF EXISTS nor CASCADE are recognised by sql server it seems, and running drop table X, Y, Z seems to work only if they should be dropped in the stated order.
See also http://msdn.microsoft.com/en-us/library/ms173790.aspx, which describes the drop table syntax.
The thing holding you back from dropping the tables in any order are foreign key dependencies between the tables. So get rid of the FK's before you start.
Using the INFORMATION_SCHEMA system views, retrieve a list of all foreign keys related to any of these tables
Drop each of these foreign keys
Now you should be able to drop all of the tables, using any order that you want.