I have a schema called "CUSTOMERS". In this schema there is a table called RECEIVABLES.
There is another schema called "ACCOUNTS". In this schema, there is a table called RECEIVABLES_AC.
RECEIVABLES_AC has a public synoym called RECEIVABLES.
The table structure of both the tables is exactly the same.
If your front-end uses the customer schema credentials to establish a connection, how can you ensure that the record will get inserted in RECEIVABLES_AC without changing the front-end code.
I think this is a trick question. Short of renaming the table RECEIVABLES in the CUSTOMERS schema, I don't see how this can be done.
The only way that I can think of (without changing the login or insert statement) is to use a database trigger that runs on login and changes the current schema to ACCOUNTS:
create or replace trigger logon_set_schema
AFTER LOGON ON DATABASE
BEGIN
if sys_context('USERENV','SESSION_USER') = 'CUSTOMERS' then
execute immediate 'alter session set current_schema=accounts';
end if
END;
/
However, this would likely break other aspects of the code, so changing the application to specify the schema name would be vastly preferable.
What isn't specified is if the behavior is supposed to be instead-of or in-addition-to.
Use replication on ACCOUNTS.RECEIVABLES to propagate DML to CUSTOMER.RECEIVABLES_AC. Triggers, streams, what have you.
Use the ALTER SESSION SET CURRENT_SCHEMA statement to change the default namespace of the user's session.
The right way to respond is to fix the design, and to not have multiple receivables tables with public schemas floating about.
Two good ways to solve this problem are:
Option 1
Rename CUSTOMERS.RECEIVABLES.
Drop the public synonym.
Create a private synonym in the CUSTOMERS schema, called RECEIVABLES that points to ACCOUNTS.RECEIVABLES_AC.
Option 2
Change the front-end to refer to RECEIVABLES_AC instead of RECEIVABLES.
Create a private synonym in the CUSTOMERS schema, called RECEIVABLES_AC that points to ACCOUNTS.RECEIVABLES_AC.
I would prefer Option 2. Private synonyms are a great way of controlling which tables are used by a particular schema, without having to hard-code the schema name in the app.
Related
It occurred to me that I have a fundamental issue with respect to privileges.. Anyone who is granted access to my data warehouse, will be given privileges to objects in the reporting schema. However, whenever we drop objects, those privileges are lost.
The fundamental requirements that should be met with the approach are:
Indexes not populated during load of data (dropped, disabled?) to avoid populating while inserting
Retain existing privileges.
What do you guys think is the best approach based on the requirements above?
For requirement 1: depending on the version of Oracle you're running, you may be able to alter the indexes as invisible. Making indexes invisible will cause the optimizer to ignore them, but it can come in handy because you can simply make them visible again after whatever operation you're performing. If that won't work, you could alter them unusable instead. More info here: https://oracle-base.com/articles/11g/invisible-indexes-11gr1
For requirement 2: Once an object is dropped, the privileges are dropped along with it. There's not really any straightforward way to retain the grants as they are when an object is dropped, however, you could use a number of different methods to "save" the privileges when a table is dropped. These are just some ideas to get you going, not a guaranteed method of success.
Method 1: Using Triggers and DBMS_SCHEDULER to issue the grants. Triggers can be very powerful, and if you create a trigger that is set to run when a table of a specific name is created under a specific schema, you can use DBMS_SCHEDULER to run a job that will issue the missing grants.
Method 2: Per Littlefoot's suggestion, you can save the grant statements in a SQL script and run it manually every time the table is created (or create a trigger for it!)
Method 3: Work with the business and implement a process wherein the table does not need to be dropped, and instead is altered to fit business needs. To use this method, you'll have to understand why the object is being dropped in the first place. Is a drop really necessary to accomplish the desired outcome? I've seen teams request that tables be dropped when they really just wanted the tables to be truncated. If this is one of those scenarios, truncating instead of dropping will let you keep the object and its grants intact.
In any scenario, you'll also want to make sure that you are managing permissions via roles whenever possible, rather than issuing grants to individual users/schemas. Utilizing roles will make managing permissions a lot easier in just about any scenario.
If you DROP an object, the grants are gone. However:
Indexes not populated during load of data (dropped, disabled?) to avoid
populating while inserting
Retain existing privileges.
Here is one common approach. There are others. If you have partitioning there are better ways.
ALTER INDEX my_index1 UNUSABLE;
ALTER INDEX my_index2 UNUSABLE;
...
ALTER INDEX my_indexn UNUSABLE;
TRUNCATE TABLE my_table_with_n_indexes; -- OPTIONAL (depends if you need to start empty)
INSERT /*+ APPEND */ INTO my_table_with_n_indexes; -- Do your load here. APPEND hint optional, depending on what you are doing
ALTER INDEX my_index1 REBUILD;
ALTER INDEX my_index2 REBUILD;
...
ALTER INDEX my_indexn REBUILD;
I am creating a simple application where I am using a Servlet and JDBC to create users.
Is there any way I can use a trigger to insert the username into another table when the Oracle user is created with:
create user xyz ......
Once this query executes successfully, it inserts the user information in the DBA_USERS table.
I want the username to also be inserted into another table. Should I add it to that other table manually through JDBC, or can I create a trigger to do it automatically?
You could use a system trigger based on the create user DDL (but not a DML trigger on the dba_users view - you can't do that anyway, but don't even think about trying to do anything based on the data dictionary). But you wouldn't really have any way for that to know if the user being created is actually an application user - you'd be assuming any user added to the DB could only be related to your application.
Since you have to take other steps anyway - such as granting roles and/or privileges, maybe adding other application security data, etc., it probably makes more sense to do the table insert manually.
It may even make more sense to put all the user-creation code into a stored (and probably packaged) procedure, and just call that over JDBC; the downside of that is that the create user and any other DDL would need to be executed from within the procedure as dynamic SQL. Any of your own table inserts would be together though, and you'd only have that single JDBC call to make.
You can also have other procedures to modify and delete users.
Something to bear in mind, however you do it, is that DDL implicitly commits. Not necessarily a problem, just something to be aware of, so you can order the steps in a recoverable way.
I have a situation where I need to update tables in different schemas in a single transaction.I can either use a plain JDBC or a Spring JDBCtemplate.
Any suggestions as to how I can achieve this.Thanks.
Ravi
I suggest you make your database connection from java with a specific user (say JAVA_USR or something like that), and ask your DBA for the proper grants over the destination schemas. Your DBA will like too to know that all the accesses from java applications are made from the same user, since it will make monitoring easier for them.
This way you can send the following alter statements through JDBC or SpringTemplate:
ALTER TABLE JOE.TABLE_1 ADD NAME VARCHAR2(80)
ALTER TABLE MARVIN.TABLE_2 ADD SURNAME VARCHAR2(100)
ALTER TABLE JACK.TABLE_3 ADD ADDRESS VARCHAR2(75)
...
If all the schemas are in the same database, you should be able to do your job in the same transaction in either of the ways you have asked about.
I have a situation in our Oracle environment where I would like to be able to grant select permissions to a certain user/group on all views in a particular schema.
I realize that I could write a dynamic statement to iterate over all the views in the schema and grant permissions to them individually as shown here but I would like to be able to have this apply to all views that exist in the schema now or in the future.
I was also contemplating the possibility of writing a DDL trigger that could monitor for the creation of new views but setting permissions in a trigger isn't something I've seen done before and doesn't seem like accepted practice.
Basically, is there a VIEW analog to the GRANT EXECUTE ANY PROCEDURE?
The EXECUTE ANY PROCEDURE grant allows a user to execute any procedure in any schema in the database, not just those in a particular schema. You can grant a user the SELECT ANY TABLE privilege-- that will allow the user to query any table or view in any schema in the database not just those in a particular schema. That's the analogous privilege, it just seems unlikely that either is really what you're after.
Since views should not be created dynamically, this sort of requirement would normally be handled by simply including the appropriate GRANT statements in the scripts that create the new views which get promoted up through the environments. Dynamically granting privileges is generally frowned upon because it generally implies that you have issues with your change control process that need to be addressed.
I have, for third party applications that insist on creating new objects periodically, created a DDL trigger that grants privileges on new objects. In order to do that, you would need to submit a job that actually does the GRANT. A GRANT is a DDL statement so it issues an implicit commit and implicit commits aren't allowed in triggers, you have to have a separate job that runs moments after the object is created. This means that you end up with a number of moving pieces that generally makes your environment more complex.
I've database with 15 tables. Now due to development process one column has to added to all the tables in the database. This changes should not affect the existing process because some other services are also consuming this database. So to accomplish it I thought of creating a new database. Is there are any other way to do it.
Usually it should be enough to create a new schema ("user") and create the tables in that new schema. In Oracle, identically named tables can exist in several schemas.
CREATE USER xxx IDENTIFIED BY yyy
you can create another schema for development and import the table to new schema.Developer should use the development schema instead of production schema.you can also create new database and import from current database but it might be last option
What's wrong with alter table T add (COL varchar2(5)); ?
Of course dependend stored procedures or packages become invalid.
You can leave them alone, then the first call would return an exception and auto-recompile the called procedure. Or you can alter procedure P compile;.