views:

244

answers:

4

I'm doing maintenance work on a Rails site that I inherited; it's driven by an Oracle database, and I've got access to both development and production installations of the site (each with its own Oracle DB). I'm running into an Oracle error when trying to insert data on the production site, but not the dev site:

ActiveRecord::StatementInvalid (OCIError: ORA-00001: unique constraint (DATABASE_NAME.PK_REGISTRATION_OWNERSHIP) violated: INSERT INTO registration_ownerships (updated_at, company_ownership_id, created_by, updated_by, registration_id, created_at) VALUES ('2006-05-04 16:30:47', 3, NULL, NULL, 2920, '2006-05-04 16:30:47')):
/usr/local/lib/ruby/gems/1.8/gems/activerecord-oracle-adapter-1.0.0.9250/lib/active_record/connection_adapters/oracle_adapter.rb:221:in `execute'
app/controllers/vendors_controller.rb:94:in `create'

As far as I can tell (I'm using Navicat as an Oracle client), the DB schema for the dev site is identical to that of the live site. I'm not an Oracle expert; can anyone shed light on why I'd be getting the error in one installation and not the other?

Incidentally, both dev and production registration_ownerships tables are populated with lots of data, including duplicate entries for country_ownership_id (driven by index PK_REGISTRATION_OWNERSHIP). Please let me know if you need more information to troubleshoot. I'm sorry I haven't given more already, but I just wasn't sure which details would be helpful.

UPDATE: I've tried dropping the constraint on the production server but it had no effect; I didn't want to drop the index as well because I'm not sure what the consequences might be and I don't want to make production less stable than it already is.

Curiously, I tried executing by hand the SQL that was throwing an error, and Oracle accepted the insert statement (though I had to wrap the dates in to_date() calls with string literals to get around an "ORA-01861: literal does not match format string" error). What might be going on here?

+3  A: 

Based on the name of the constraint, PK_REGISTRATION_OWNERSHIP, you have a primary key violation. If these databases aren't maintaining this data in lockstep, something/someone has already inserted a record into the registration_ownerships table in your production database with company_ownership_id=2 & registration_id=2920. (I'm guessing at the specifics based on the names)

If this particular set of values needs to exist in the production database,

1) check that what's already there isn't what you're trying to insert. if it is, you're done.

2) If you need to insert your sample data as-is, you need to modify the existing data & re-insert it (and all the dependent/refering records), then you can insert your values.

DaveE
Thanks for the feedback, Dave. I ran a select where company_ownership_id = 3 and registration_id = 2920 on the production database and I didn't get back any records. registration_id is the first primary key and company_ownership_id is the second in registration_ownerships...could there be another reason I'm getting the error? Or am I just misunderstanding you?
justinbach
Well, I guessed at the components of the primary key based on the names. You probably want to look at the definition of PK_REGISTRATION_OWNERSHIP directly to find out exactly what the database thinks a unique value is. Is this a single statement that's failing, or part of a batch where you might have duplicates?
DaveE
It's a single insert that's failing, though it's part of a set of insert queries (the registration_ownerships is part of the registrations model). Your guess was a good one; the definition of PK_REGISTRATION_OWNERSHIP is composed of registration_id and company_ownership_id as fields, and is associated with the registration_ownerships table. Each of the two ids corresponds to a defined sequence, as well. Could it be the case that records used to exist in the table with this combination of attributes and were deleted, but Oracle marked that specific key combination as being "used"?
justinbach
If this is part of a series, has a COMMIT been done before this one fails? Could an earlier uncommitted INSERT have inserted these values? (then they all roll back at failure so there's no evidence...)Is either of the fields an IDENTITY type where the system-defined 'next value' is beyond what you're tring to insert? It's been a while since I dealt with Oracle's idiosyncracies so that might be out in left field.
DaveE
Hmm...production.log doesn't show any evidence of a commit being attempted; would it, if that were the case? I don't think either field is an identity. Thanks for your responses--this thing is driving me nuts!
justinbach
+1  A: 

If you query the table and find no matching rows, then one of the following may be the cause:

  1. The session is trying to insert the row twice.
  2. Another session has inserted the row, but hasn't committed yet.

Also, check that the state of the unique constraint is the same between dev and prod. Perhaps the one on dev is marked as not validated - check that the index exists on dev and is a unique index (note: in Oracle it is possible to have a unique constraint validated by a non-unique index).

Jeffrey Kemp
Jeffrey, as far as I can tell, the index is identical on production and dev; both are valid and unique. The codebases are also identical between dev and production (minus some configuration details like DB credentials), so I imagine if it were a session double insert or a commit conflict I'd be seeing it on both installations. Is there anything else that could be causing this?
justinbach
A: 

Take a hard look at the underlying unique index for the constraint. The reason dropping the constraint doesn't change anything is because the index remains, and it's a unique index. What does the following tell you about the indexes in both environments? Are both indexes valid? Are both defined the same? Are they both actually unique?

SELECT ai.table_name, ai.index_name, ai.uniqueness, aic.column_name, ai.status
  FROM all_constraints ac JOIN all_indexes ai ON (ac.index_name = ai.index_name)
                          JOIN all_ind_columns aic ON (ai.index_name = aic.index_name)
 WHERE ac.owner = 'YOUR_USER'
   AND ac.constraint_name = 'PK_REGISTRATION_OWNERSHIP'
 ORDER BY ai.index_name, column_position;
DCookie
DCookie, thanks for the response. Both environments yield precisely the same results for the query; namely, that both index are unique, valid, and defined exactly the same. What else might be causing this?
justinbach
A: 

As it happens, there was a spare copy of the "registrations" model lying around the directory; even though it had a different name ("registrations_2349871.rb" or something like that) Rails was running all model functionality (saving, validating, etc) twice, hence the key constraint violation! I've never seen behavior like this before. Deleting the rogue file solved the problem.

justinbach