Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 days ago.
This post was edited and submitted for review 4 days ago.
Improve this question
We have a node.js app with Oracle DB as backend that uses SODA API. Per our internal DB policy there is a OWNER schema which owns tables while USER schema is used to access objects owned by OWNER schema to perform CRUD operations on them. Can the same model be used with SODA Collections as well. Node.js app uses SODA based oracle driver to perform operations on these collection.
I have been able to create the actual collection in OWNER schema and then create a mapping collection in USER schema. But insert document operations to the mapped collection seems to fail. Probably I am missing a grant or something here.
From OWNER Schema do the following:
DECLARE
METADATA varchar2(4000);
l_collection SODA_COLLECTION_T;
BEGIN
METADATA := '{
"schemaName":"OWNER",
"tableName":"TESTCOLLECTION1",
"keyColumn":{"name":"ID","sqlType":"VARCHAR2","maxLength":255,"assignmentMethod":"UUID"},
"contentColumn":{"name":"JSON_DOCUMENT","sqlType":"BLOB","compress":"NONE","cache":true,"encrypt":"NONE","validation":"STANDARD"},
"lastModifiedColumn":{"name":"LAST_MODIFIED"},
"versionColumn":{"name":"VERSION","method":"UUID"},
"creationTimeColumn":{"name":"CREATED_ON"},
"readOnly":false
}';
l_collection := DBMS_SODA.create_collection('TESTCOLLECTION1', METADATA);
IF l_collection IS NOT NULL THEN
DBMS_OUTPUT.put_line('Collection ID : ' || l_collection.get_name());
ELSE
DBMS_OUTPUT.put_line('Collection does not exist.');
END IF;
END;
/
Grants
grant select, insert, update, delete on OWNER.TESTCOLLECTION1 to USER;
From USER Schema do the following:
declare
METADATA varchar2(4000);
COL SODA_COLLECTION_T;
begin
METADATA := '{
"schemaName":"OWNER",
"tableName":"TESTCOLLECTION1",
"keyColumn":{"name":"ID","sqlType":"VARCHAR2","maxLength":255,"assignmentMethod":"UUID"},
"contentColumn":{"name":"JSON_DOCUMENT","sqlType":"BLOB","compress":"NONE","cache":true,"encrypt":"NONE","validation":"STANDARD"},
"lastModifiedColumn":{"name":"LAST_MODIFIED"},
"versionColumn":{"name":"VERSION","method":"UUID"},
"creationTimeColumn":{"name":"CREATED_ON"},
"readOnly":false
}';
COL := dbms_soda.create_collection('TESTCOLLECTION1', METADATA, DBMS_SODA.CREATE_MODE_MAP);
IF COL IS NOT NULL THEN
DBMS_OUTPUT.put_line('Collection ID : ' || COL.get_name());
ELSE
DBMS_OUTPUT.put_line('Collection does not exist.');
END IF;
end;
Insert data into the mapped collection from USER schema
DECLARE
l_collection SODA_COLLECTION_T;
l_document SODA_DOCUMENT_T;
l_status NUMBER;
BEGIN
l_collection := DBMS_SODA.open_collection('TESTCOLLECTION1');
l_document := SODA_DOCUMENT_T(
b_content => UTL_RAW.cast_to_raw('{"employee_number":7521,"employee_name":"WARD"}')
);
l_status := l_collection.insert_one(l_document);
DBMS_OUTPUT.put_line('status : ' || l_status);
COMMIT;
END;
Trying the below code from OWNER SCHEMA works and shows the document however trying the same from USER Schema does not produce the output.
DECLARE
collection SODA_COLLECTION_T;
document SODA_DOCUMENT_T;
cur SODA_CURSOR_T;
status BOOLEAN;
BEGIN
-- Open the collection to be queried
collection := DBMS_SODA.open_collection('TESTCOLLECTION1');
-- Open the cursor to fetch the documents.
cur := collection.find().get_cursor();
-- Loop through the cursor
WHILE cur.has_next
LOOP
document := cur.next;
IF document IS NOT NULL THEN
DBMS_OUTPUT.put_line('Document components:');
DBMS_OUTPUT.put_line('Key: ' || document.get_key);
DBMS_OUTPUT.put_line('Content: '
|| json_query(document.get_blob, '$' PRETTY));
DBMS_OUTPUT.put_line('Creation timestamp: '
|| document.get_created_on);
DBMS_OUTPUT.put_line('Last modified timestamp: '
|| document.get_last_modified);
DBMS_OUTPUT.put_line('Version: ' || document.get_version);
END IF;
END LOOP;
-- IMPORTANT: You must close the cursor, to release resources.
status := cur.close;
END;
I am from the SODA team. Yes, sounds like some grant is missing.
What exact error do you get?
Maybe try to grant read/write priveleges on collection table (which resides in owner schema) to the user schema.
For example (adjust the privileges as appropriate for what you want to allow):
grant select, insert, update, delete on ownerSchemaNameHere.collectionTableNameHere to userSchemaNameHere;
Under the hood, SODA generates regular insert/select/udpate/delete SQL, for all its operations, against the target table backing the collection. So it needs the usual SQL grants to be able to read/write to the target table.
I don't know SODA. However, there are some basic principles that probably apply here:
If SODA permits you to prefix the object owner to the name, then it's as simple as connecting as the connect user and operating on the owner objects, fully qualified (update ownerschema.table set .... )
If SODA does not permit that or you do not wish to fully qualify object names, you can create synonyms under the connect user schema that point to the object owner schema (create synonym connectschema.table for ownerschema.table).
Either options #1 or #2 will require that the connect schema be granted insert,update,delete (just request ALL) on the owning schema objects.
If SODA does it's own dictionary interrogate/describe activities and is not sophisticated enough to handle a synonym, which does happen with some tools, then you can create views under the connect schema that select straight from the object owning schema (create view connectschema.table as select * from owningschema.table). It should be able to interrogate the structure of those views without any idea they are not normal tables, and you can do CRUD operations on them.
With option #3, the connect schema will require insert,update,delete grants "WITH GRANT OPTION" on the owning schema objects.
Related
Using Prisma client 3 I'm trying to create a stored procedure.
The motivation behind it is:
I need to query a table that will be created on run time.
To do this, I need to use dynamic queries,
and I read that stored procedures will be the better practice in this case (pass the table name as a parameter).
I would like for each member of my team to have the updated version of the stored procedure (like all the tables in Prisma)
So, what I've decided to do is to create the stored procedure with prisma.$executeRaw when the app starts and call it when I need.
The code:
let prisma = new PrismaClient();
let res = await prisma.$executeRawUnsafe(`
CREATE PROCEDURE \`module-events\`.GetAllProducts()
BEGIN
select 555;
END
`);
The result:
Invalid `prisma.$executeRaw()` invocation:
Raw query failed. Code: `1295`. Message: `This command is not supported in the prepared statement protocol yet`
As you can see the $executeRawUnsafe() returns the same results. Is there any way to create a stored procedure with Prisma? Is there a way to run a "free style" query that is not limited by Prisma?
I understood from this answer that it is possible to create the stored procedure:
You could also use $executeRaw to generate the stored procedure or use the tool/CLI of your choice.
I'm currently working on saving data in a postgres DB using TypeORM with the NestJS integration. I'm saving data which keeps track of a version property using TypeORM's #VersionColumn feature, which increments a number each time save() is called on a repository.
For my feature it is important to check this version number before updating the records.
Important
I know I could technically achieve this by retrieving the record before updating it and checking the versions, but this leaves a small window for errors. If a 2nd user updates the same record in that millisecond between the get and save or if it would take longer for some weird reason, it would up the version and make the data in the first call invalid. TypeORM doesn't check the version value, so even if a call has a lower value than what is in the database, it still saves the data eventhough it should be seen as out of date.
1: User A checks latest version => TypeORM gives back the latest version: 1
2: User B updates record => TypeORM ups the version: 2
3: User A saves their data with version 1 <-- This needs to validate the versions first.
4: TypeORM overwrites User B's record with User A's data
What I'm looking for is a way to make TypeORM decline step 3 as the latest version in the database is 2 and User A tries to save with version 1.
I've tried using the querybuilder and update statements to make this work, but the build-in #VersionColumn only up the version on every save() call from a repository or entity manager.
Besides this I also got a tip to look into database triggers, but as far as I could find, this feature is not yet supported by TypeORM
Here is an example of the setup:
async update(entity: Foo): Promise<boolean> {
const value = await this._configurationRepository.save(entity);
if (value === entity) {
return true;
}
return false;
}
In my opinion, something like this is much better served through triggers directly in the Database as it will fix concerns around race conditions as well as making it so that modifications made outside the ORM will also update the version number. Here is a SQL Fiddle demonstrating triggers in action. You'll just need to incorporate it into your schema migrations.
Here is the relevant DDL from the SQL Fiddle example:
CREATE TABLE entity_1
(
id serial PRIMARY KEY,
some_value text,
version int NOT NULL DEFAULT 1
);
CREATE OR REPLACE FUNCTION increment_version() RETURNS TRIGGER AS
$BODY$
BEGIN
NEW.version = NEW.version + 1;
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
CREATE TRIGGER increment_entity_1_version
BEFORE UPDATE
ON entity_1
FOR EACH ROW
EXECUTE PROCEDURE increment_version();
The same trigger function can be used for any table that has a version column in case this is a pattern you want to use across multiple tables.
I think you are looking for concurrency control. If this is the case there is a solution in this about 1/2 the way down. TypeORM concurrency control issue
When using Redshift, I would like to get the names of all the procedure that were created in a schema, along with their definition.
I know you can use the SHOW PROCEDURE command to get the definition but that requires to have the procedure name.
In SVV_TABLE there is only information regarding tables and view but not procedure.
So if anyone knows how to get that ?
Redshift doesn't have a system view for that yet but you can use tbe PG_PROC table and join it with pg_namespace to filter on schema name.
select proname, proargnames, prosrc
from PG_PROC
join pg_namespace on pg_namespace.oid = pg_proc.pronamespace
where nspname = 'your_schema_name' and procsecdef = true;
The procsecdef = true is to get only stored procedure definition otherwise you also get python UDF.
Ok, so I'm working with an ObservableList, which is working fine, but now I need to use the observable list to insert rows into and update rows in an SQL database table. I've found little info on working between JavaFX and SQL databases ... all the examples of data tables have the data created in the java code. I had hope when I saw "update SQL database" in this post:
Update sql database from FoxPro data on Glassfish server
but it was not applicable to my situation.
So the question is, how do I start the code to read from the ObservableList so I can run my SQL Insert statement? If you could point me to an example code where an ObservableList is used and an SQL table is created/added to/updated I would greatly appreciate it.
Thanks!
UPDATE TO QUESTION:
I can't really post relevant code here because the relevant parts are what I don't have. However, I'm thinking what I need to do is something like this:
mylist.moveToFirst();
while (mylist.next()) {
make connection // think I got it
INSERT INTO mytable (name, address, phone) VALUES (observablename, observableaddress, observablephone // think I got this as well
Obviously I'm applying my knowledge of other areas to ObservableList, but I am doing it to demonstrate what I don't know how to do with my ObservableList (mylist).
Again, thanks for any help.
Tying up loose ends today, and this question has not really been answered. I reposted a newer question with more specifics once I learned more about the situation, and that question also went unanswered, but I did figure it out, and posted an answer here: Understanding my ObservableList.
However, to be neat and tidy, let me post here some code to help me remember, as well as help anyone else who looks at this question and says, "YES, BUT WHAT IS THE SOLUTION?!?!?"
Generically, it looks something like this:
I like to open my connection and prepare my statement(s) first.
Use the iterator to get the variables from the list
within the iterator, add the variables to the prepared statement and execute.
I read somewhere about batch execution of statements, but with as few updates as I'm doing with each list, that seemed too complicated, so I just do each update individually within the iterator.
Specifically, here is some code:
Connection con;
con = [your connection string]; // I actually keep my connection string in its own class
// and just call it (OpenDB.connect()). This way I can swap out the class OpenDB
// for whatever database I'm using (MySQL, MS Access, etc.) and I don't have to
// change a bunch of connection strings in other classes.
PreparedStatement pst;
String insertString = "INSERT INTO People (Name, Address, Phone) VALUES (?, ?, ?)";
pst = con.prepareStatement(insertString);
for(Person p : mylist) { // read as: for each Person [a data model defined in a class
// named Person] which in this set of statements we shall call 'p' within the list
// previously defined and named 'mylist' ... or "For each Person 'p' in 'mylist'"
String name = p.name.get(); // get the name which corresponds to the Person in this object of 'mylist'
String address = p.address.get(); // ditto, address
Integer phone = p.phone.get(); // ditto, phone. Did as integer here to show how to add to pst below
pst.setString(1, name); // replace question mark 1 with value of 'name'
pst.setString(2, address); // ditto, 2 and 'address'
pst.setInt(3, phone); // ditto, 3 and 'phone'
pst.executeUpdate();
And that's how I did it. Not sure if it's the 'proper' way to do it, but it works. Any input is welcomed, as I'm still learning.
In JavaFX you usually get to be the person to create the example :)
ObservableList supports listeners, these receive events which tell you what has been added or updated by default. There is a good example in the javadocs here.
To get update events you need to provide an 'extractor' to the method creating the list here. This should take an instance of the object in the list and provide an array of the properties you want to listen to.
Try this:
SQLEXEC(lnConn, "Update INVENTORY SET brand = ?_brand, model = ?_model, code =?_code, timestamp =?_datetime where recno=?_id ")
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
XKCD SQL injection - please explain
What is the general concept behind sql injection ?
Being a rails developer
This is unsafe
Booking.find(:all, :conditions => [ 'bookings.user_id = #{params[user_id]]}'] )
and this is safe:--
Booking.find(:all, :conditions => [ 'bookings.user_id = ?', params[user_id]] )
am i right?
So my question is how the sql injection is done?
How those guys do some stuff like that. Any live example/ tutorial where somebody is showing this kind of stuff. Anything basic for knowing the logic.
SQL Injection happens when a programmer gets lazy. A vulnerable query would look like this:
DECLARE #cmd varchar(256)
SET cmd='SELECT #col FROM Table'
EXEC #cmd
With #col being a variable passed into a stored procedure.
Usually, the user would enter a column in that already exists for that variable. But a more devious user could enter something like this:
* FROM Table; DROP DATABASE data;--
The * FROM Table; finishes off the previous statement. Then, DROP DATABASE data; is the payload that does bad things, in this case, dropping the database. Finally, the -- comments out the rest of the query so it doesn't get any errors from the injection.
So, instead of executing this:
SELECT column
FROM Table
You get this:
SELECT *
FROM Table;
DROP DATABASE data;
--
Which is not good.
And this:
All the user has to do is enter:
1234; DROP TABLE BOOKINGS
...
I don't know about rails, but by doing this Booking.find(:all, :conditions => [ 'bookings.user_id = #{params[user_id]]}'] ), you risk that the user give to user_id the value 1 OR 1=1 and as you can see, it will modify your request.
With more injection you could do something like 1; DROP TABLE BOOKINGS etc.
Basically injection is just "hijacking" a basic request to add yours.
Bobby tables
If you have a simple query like
SELECT * FROM bookings WHERE user_id = ORDER BY user_id ASC;
if you don't check user id, it can close your query, then start a new (harmful one) and discard the rest. To achieve this, generally, you would enter something like
1; DELETE FROM bookings; --
initial ; closes the good query, the bad query comes next, then it is closed with ; and -- makes sure that anything that would come next in the good query is commented out. You then end up with
SELECT * FROM bookings WHERE user_id = 1; DELETE FROM bookings; -- ORDER BY user_id ASC;
If your data in properly cleaned and sanatized, a user can try to get their own SQL code to run on the server. for example, let's say you have a query like this:
"SELECT * FROM products WHERE product_type = $type"
where type is unchanged user input from a text field. now, if I were to search for this type:
(DELETE FROM products)
You are gonna be in a world of hurt. This is why it's important to make sure all user input in sanatized before running it in the DB.
Plenty of excellent papers on the theory of SQL injection here:
sql injection filetype:pdf
Should be easy enough to hunt one down that is specific to your language/DB combination.