SQLite - Foreign Keys Contraints - IOs 5 - ios

it seems that Foreign Keys Constraints are supported since version 3.6.x in SQLite. The version of SQLite on IOS5.0 is 3.7.7 (found in sqlite3.h).
But when I try to insert a row in a table that has a constraint, my row is correctly inserted even if the related foreign key is not existing. I have no error.
Doing the same insert statement using apps like Navicat gives me a "Constraint violation error"
Do you know if foreign keys are supported on IOs 5 ?
Here is the Database Schema:
CREATE TABLE artist(
artistid INTEGER PRIMARY KEY,
artistname TEXT
)
CREATE TABLE "track" (
"trackid" INTEGER PRIMARY KEY AUTOINCREMENT,
"trackname" TEXT,
"trackartist" INTEGER,
CONSTRAINT "trackartist" FOREIGN KEY ("trackartist") REFERENCES "artist" ("artistid") ON DELETE CASCADE ON UPDATE CASCADE)
Really simple, isn't it ?
Thanks
Emmanuel

Foreign keys are disabled by default. You have to enable them separately for each connection. The setting isn't "sticky". You have to do this every time you connect to a SQLite database.
PRAGMA foreign_keys = ON;
Odds are good that Navicat takes care of that for you. In your own code, it's your job.

I've finally found the solution .... and catcall you were right.
By default the sqlite database is opened with foreign keys option disabled, even if the tables have been built with foreign keys constraints !
So just make this simple request :
PRAGMA foreign_keys=ON;
just after opening the database, and outside a transaction (if you are using fmdatabase and transactions functionality)
Hope this will help somebody else.
Emmanuel

This is how I do it using FMDB:
[database executeUpdate:#"PRAGMA foreign_keys=ON"];

It is on the doc:
SQLite Doc
and when you open the connection:
[database executeUpdate:#"PRAGMA foreign_keys=ON"];

Related

TinyTds::Error: Cannot insert the value NULL into column 'ID'

My Ruby on Rails system is moving from Oracle to Microsoft SQL Server 2012. The back end database has already been converted by a third part from Oracle to Microsoft SQL Server. I have no control over the schema structure. This cannot be changed.
Using activerecord-sqlserver-adapter, tiny_tds and Freetds I can connect to the new database. Most DB requests work well.
However, many of the tables have ID primary keys that are auto incremented by SQL Server, in other words, PK IDENTITY(1,1) columns. The same code that worked with Oracle connections fails under SQL Server with the following error:
TinyTds::Error: Cannot insert the value NULL into column 'ID'
I know why it is doing this as the ID column is indeed a primary_key, and IDENTITY(1,1) column and includes the NOT NULL restriction. That is fine.
Inserting into the table works fine if using raw SQL execute statements where of course I exclude the ID column from the INSERT statement.
However I have spent days googling and I cannot find a way of telling Ruby on Rails not to try and save the ID column.
So I have an instance of a class, #book, that contains
Library::Book(id: integer, title: string, isbn: string ...)
When I do a #book.save! it generates the error above.
#book = Library::Book.new( .. )
:
:
#book.save!
TinyTds::Error: Cannot insert the value NULL into column 'ID'
Rather that resort to bare metal SQL, how do I do things more Railsy and tell it I want to save the record but not try and save the ID field as it is auto incremented? So effectively I am trying to save
Library::Book(title: string, isbn: string ...) if a new insert entry
or
Library::Book(id: integer, title: string, isbn: string ...) if trying to update an entry.
Due to imposed restrictions I am using:
Ruby 2.3.3p222
Rails 4.0.13
activerecord (4.0.13)
activerecord-sqlserver-adapter (4.0.4)
tiny_tds (1.0.2)
Freetds 1.00.27
You can use ActiveRecord::Relation#find_or_initialize_by. This assumes that you have enough attributes known at the time to uniquely identify the record.
That will solve the last part of your question. But it sounds like the id column is not set to auto-increment. You need to set that so when Rails sends a null id the DB will set it properly.
Update: To make the column auto-increment you will need to run a migration. You can then do:
Alter table books modify column id int(11) auto_increment;
Update: If we cannot modify the database we can do:
class Book
private
def create_or_update(*args, &block)
self.id ||= Book.maximum(:id) + 1
super
rescue ActiveRecord::RecordNotUnique
self.id = nil
retry
end
end
It's pretty janky, and I would highly recommend updating the column if possible.

Force Delete on a UNIQUE rows SQLite FMDB iOS

I have an app which uses SQLite, i have some problems deleting a row because one of its value is unique.
I get the error :
Unknown error calling sqlite3_step (19: column myField is not unique)
DB Query: DELETE FROM "****" WHERE "myField" = '72645DA9-E95F-452A-94B8-C93A20D9A41C'
Is there a way to force the delete of this unique row ? Or can simply disable the unique constraint when i need to delete.
Of course this behavior should not appear, but it does so please do not tell to re-create my database :)
Thank you very much.

SQL Insert Update Issue in Procedure

This is my first post to this website.
Here is my question: I want to use the same stored procedure for Insert and Update.
For Insert there is no problem. But at the time of update O want to update it based on my primary key, not on any unique column value.
Here is my current Procedure.
IF EXISTS(SELECT MemberID FROM MEMBER WHERE MEMBERSHIPNO=#MEMBERSHIPNO)
WHERE MEMBERSHIPNO=#Membershipno
I want to use WHERE MemberID=#MemberID //Memberid is primary key
Please Help.
I'm not sure if I understand you're question quite clearly, but from what I understand you're trying to do a IF clause that would UPDATE if said credentials exists.
Something like this would do the trick, just fill in the logic and it should all work out.
IF EXISTS (SELECT MemberID FROM MEMBER WHERE MEMBERSHIPNO=#MEMBERSHIPNO)
UPDATE [ADD UPDATE LOGIC HERE] WHERE MemberID=#MemberID
ELSE
INSERT [ADD INSERT LOGIC HERE]
Hope this helps.

How to use autoincrement primary keys with CL-SQL?

I am using CL-SQL with SQLite backend, and I can't quite get autoincremented primary keys to work. I declared a slot like (in def-view-class):
((id :accessor d-id :db-constraints :primary-key :type integer :db-type "INTEGER")
But if I create the class, the field is not updated, not even when I call update-records-from-instance, and if I call update-instance-from-records, it will get updated wrong. Is there a way to use autoincremented fields CL-SQL at all?
I think this might be caused by a bug. I've sent a patch to the clsql mailing list which fixes the problem for me:

Rails - Data Migration vs. value in DB

I have a question about where values in dropdowns are coming from:
I have a migration that set up the original table with some initial values:
add_column :contracts, :signature_status_id, :integer
# lookup data
sig = SignatureStatus.new(:name => "Delivered")
sig.save!
sig = SignatureStatus.new(:name => "Signed")
sig.save!
I have a table called signature_statuses that contains the updated values:
id, name
1, 'Delivered; awaiting signature'
2, 'Delivered; awaiting full execution'
3, 'Terms being negotiated'
4, 'Fully executed and filed'
I have a form that contains the code to pull out the signature status:
<%= collection_select(:contract, :signature_status_id, #signature_statuses, :id, :name) %>
The collection select is pulling in "Signed" and "Delivered" when I want it to be from the DB. How do I make it do that.
Note: I think that the data was edited manually rather than a migration, but I'm not sure. I also searched the code for "signed" and "delivered", but the only place it shows up is in the migration.
I'm just wondering how are you getting that list of values in the signature_statuses table? Are you querying your development database? Is your application running in development mode? Is the database.yml file setup correctly to point to your development database?
Also can you post the controller code that populates the #signature_statuses variable.
A little more info and I'm sure people will be able to help.
Hmmm, this is a bit odd, but i suspect the following: there might be a method called name inside your signature_status model which is overriding the default one and which returns yes and no.
The key to debugging this is to look where
#signature_statuses
is being set in the controller. If it's pulling from the database, then that is what is in the database. I wonder if there is more than one database involved, where your migration updated the development database, but you are running the query against production (or something like that).
It turns out I needed to run "rake db" and that fixed it.

Resources