How to determine the programming language - sqlite

I'm trying to find out, which programming language is used in these functions - newVersion() and curVersion(). I've tried to search in Google, even on exact match like "newVersion()" OR "curVersion()", but it does not find.
As db is used sqlite db.
If short, it's proprietary app and I don't have access to source code of app, but I have to resolve the issue with pop-up error in Android app.
Have anyone some ideas about that?
CREATE TABLE "tblEvents" (
--some fields before
"version" int NOT NULL DEFAULT (newVersion()),
"isModified" int NOT NULL GENERATED ALWAYS AS ("version" > curVersion()) VIRTUAL,
);
The error occurs in one of these triggers:
CREATE TRIGGER [tr_i_tblEvents]
BEFORE INSERT ON [tblEvents]
WHEN isVersionEnabled() AND new.version<>newVersion()
BEGIN SELECT RAISE(FAIL, 'DON''T TOUCH ROW VERSION!!!'); ENDл
CREATE TRIGGER [tr_u_tblEvents]
BEFORE UPDATE OF version,SyncStatus,[EventId],[EventTypeId],[Name],[Description],[DateStart],[DateEnd],[CreationDate],[EventStatus],[OrgStructureID],[Color],[Location],[Mode],[StaffGroupID],[PlannedDay],[Recurrence_ID]
ON [tblEvents]
WHEN isVersionEnabled() AND new.version<>newVersion()
BEGIN SELECT CASE WHEN new.version<>old.version THEN RAISE(FAIL, 'DON''T TOUCH ROW VERSION!!!') END;
update [tblEvents] set version=newVersion() where rowId=old.rowId; ENDБ

Related

How To Create a PL/SQL Trigger That Detects an Inserted or Updated Row and updates a Record in a Different Table?

I am creating a book tracking database for myself that holds information about my books and allows me to keep track of who is borrowing them. I am trying to create a trigger on my Checkouts table that runs if a record is added or updated that will determine if a checkout data has been entered or if a checkin date has been entered and change the "available" field in my Books table to "Y" or "N".
I have created a trigger called "update_book_availablility" on my Checkouts table but I keep getting this error:
"PLS-00103: Encountered the symbol 'end-of-file' when expecting one of the following: ( begin case declare and exception exit for goto if loop mod null pragma raise return select update while with <<continue close current delete fetch lock insert open rollback savepoint set sql execute commit forall merge standard pipe purge json_object
Errors: check compiler log"
Here is my trigger code:
CREATE OR REPLACE NONEDITIONABLE TRIGGER "UPDATE_BOOK_AVAILABILITY"
AFTER INSERT OR UPDATE OF ISBN, PersonID, checkout_date, checkin_date
ON Checkouts
FOR EACH ROW
BEGIN
IF :NEW.checkout_date = NULL
THEN
UPDATE Book
SET available = 'N'
WHERE ISBN IN (SELECT :NEW.ISBN FROM Checkouts);
END IF;
END;
Here is an image of my ERD:
ERD
I have been looking into and double checking my trigger syntax, If condition syntax, subquery syntax, and googling this error but have found nothing that has helped. I am new to PL/SQL and would appreciate any help in understanding what I have done wrong or missed.
PLS-00103: Encountered the symbol end-of-file error is SYNTAX ERROR
Copied your trigger and adjusted it to one of my test tables - it works. I removed NONEDITIONABLE and changed trigger table name as well as column names and table/column beeing updated by trigger.
To Do:
Check your syntax again or write the trigger from scratch once more
"...WHERE ISBN IN (SELECT :NEW.ISBN FROM Checkouts)..." selects one fixed value (FOR EACH ROW) :NEW.ISBN of triggering table, better ->> "... WHERE ISBN = :NEW.ISBN ..."
Prety sure that you don't need NONEDITIONABLE trigger for your books tracking app...
Regards...

'Numeric or value error' during execution of trigger

I am currently working on an application using Oracle Apex which is being used as a database to keep a record of cabling.
When components in the database are deleted, a PL/SQL trigger is executed which deletes any associations to the components from another table (PORT) and sets the port references to 0.
The trigger seems to work perfectly for the majority of components I attempt to delete, but presents me with a 'numeric or value error' for others and I am struggling to find out why (as shown below)
The trigger being executed looks like this:
create or replace trigger "COMPONENT_TRIGPORT"
AFTER delete
on "COMPONENT"
for each row
declare
TYPE portType IS TABLE OF PORT%ROWTYPE;
port_arr portType;
begin
DELETE FROM PORT
where PORT.COMPONENT_ID = :old.COMPONENT_ID
RETURNING PORT_ID, PORT_NUMBER, COMPONENT_ID, CONNECTOR_ID, PORT_TYPE
BULK COLLECT INTO port_arr;
begin
FOR i IN port_arr.FIRST .. port_arr.LAST
LOOP
update PORT
set PORT.CONNECTOR_ID = 0
where PORT.CONNECTOR_ID = port_arr(i).CONNECTOR_ID;
END LOOP;
end;
end;​
I know that the line giving me the error is
where PORT.COMPONENT_ID = :old.COMPONENT_ID
But I cannot work out why it works fine in some cases but not in others!
Replace
FOR i IN port_arr.FIRST .. port_arr.LAST
with:
FOR i IN 1 .. port_arr.COUNT
If no records are deleted the array will not be initialized and port_arr.FIRST and port_arr.LAST will return null, which will raise the exception ORA-06502: PL/SQL: numeric or value error. COUNT is always safe to use, even on a collection that has not been initialized.

SQLitePlugin Phonegap crashing for Windows Phone 8

I am trying to use a SQLite plugin for PhoneGap for Windows Phone 8. I've found 2 or 3 different plugins (maybe all of them are based from the same base) and all give me an error when the applicattion is executed.
The plugin I'm using is from here: https://github.com/marcucio/Cordova-WP-SqlitePlugin
I am including also the dll. I'm using PhoneGap 3.3.
When I execute the application, the plugin is loaded (it seems is loades correctly) and some operations are done correctly (some CREATE and some INSERT are performed) but at a given moment the Visual Studio gives me this error infinite times:
An exception of type 'System.Security.SecurityException' occurred in mscorlib.ni.dll and wasn't handled before a managed/native boundary
An exception of type 'System.Security.SecurityException' occurred in mscorlib.ni.dll and wasn't handled before a managed/native boundary
A first chance exception of type 'System.IO.IsolatedStorage.IsolatedStorageException' occurred in mscorlib.ni.dll
I've tried other similar plugins and the error still appears.
The other threads in stackoverflow related to this problem didn't solve the problem. The application always crashes in an IsolatedStorage operation.
Anyone had the same problem and could solve it? If I don't perform any INSERT operation the plugin doesn't crash.
Thank you.
I had the same problem using Community.CsharpSqlite.WinPhone, it's possible that we have the same issue.
This happened when I did an INSERT OR REPLACE or INSERT OR IGNORE with a table which primary key was TEXT and had NOT NULL constraint. If the primary key is INTEGER and AUTOINCREMENT, it works fine.
For example:
CREATE TABLE table1 (
tableid TEXT NOT NULL,
value TEXT NOT NULL,
PRIMARY KEY(tableid)
);
INSERT or REPLACE INTO table1 (tableid, value) VALUES ("id1","test");
If your id column has NOT NULL constraint, SQLite will return a System.Security.SecurityException. Try to remove this constraint:
CREATE TABLE table1 (
tableid TEXT,
value TEXT NOT NULL,
PRIMARY KEY(tableid)
);
It's a bug, in other platforms (Android, iOS, etc) the table can have a NOT NULL constraint and it works fine.

How do I call user-defined function only if it exists?

SQLite allows to define custom functions that can be called from SQL statements. I use this to get notified of trigger activity in my application:
CREATE TRIGGER AfterInsert AFTER INSERT ON T
BEGIN
-- main trigger code involves some extra db modifications
-- ...
-- invoke application callback
SELECT ChangeNotify('T', 'INSERT', NEW.id);
END;
However, user-defined functions are added only to current database connection. There may be other clients who haven't defined ChangeNotify and I don't want them to get a "no such function" error.
Is is possible to call a function only if it's defined? Any alternative solution is also appreciated.
SQLite is designed as an embedded database, so it is assumed that your application controls what is done with the database.
SQLite has no SQL function to check for user-defined functions.
If you want to detect changes made only from your own program, use sqlite3_update_hook.
Prior to calling your user defined function, you can check if the function exists by selecting from pragma_function_list;
select exists(select 1 from pragma_function_list where name='ChangeNotify');
1
It would be possible by combining a query against pragma_function_list and a WHEN statement on the trigger --
CREATE TRIGGER AfterInsert AFTER INSERT ON T
WHEN EXISTS (SELECT 1 FROM pragma_function_list WHERE name = 'ChangeNotify')
BEGIN
SELECT ChangeNotify('T', 'INSERT', NEW.id);
END;
except that query preparation attempts to resolve functions prior to execution. So, afaik, this isn't possible to do in a trigger.
I need to do the same thing and asked here: https://sqlite.org/forum/forumpost/a997b1a01d
Hopefully they come back with a solution.
Update
SQLite forum suggestion is to use create temp trigger when your extension loads -- https://sqlite.org/forum/forumpost/96160a6536e33f71
This is actually a great solution as temp triggers are:
not visible to other connections
are cleaned up when the connection creating them ends

How to find out which package/procedure is updating a table?

I would like to find out if it is possible to find out which package or procedure in a package is updating a table?
Due to a certain project being handed over (the person who handed over the project has since left) without proper documentation, data that we know we have updated always go back to some strange source point.
We are guessing that this could be a database job or scheduler that is running the update command without our knowledge. I am hoping that there is a way to find out where the source code is calling from that is updating the table and inserting the source as a trigger on that table that we are monitoring.
Any ideas?
Thanks.
UPDATE: I poked around and found out
how to trace a statement back to its
owning PL/SQL object.
In combination with what Tony mentioned, you can create a logging table and a trigger that looks like this:
CREATE TABLE statement_tracker
( SID NUMBER
, serial# NUMBER
, date_run DATE
, program VARCHAR2(48) null
, module VARCHAR2(48) null
, machine VARCHAR2(64) null
, osuser VARCHAR2(30) null
, sql_text CLOB null
, program_id number
);
CREATE OR REPLACE TRIGGER smb_t_t
AFTER UPDATE
ON smb_test
BEGIN
INSERT
INTO statement_tracker
SELECT ss.SID
, ss.serial#
, sysdate
, ss.program
, ss.module
, ss.machine
, ss.osuser
, sq.sql_fulltext
, sq.program_id
FROM v$session ss
, v$sql sq
WHERE ss.sql_address = sq.address
AND ss.SID = USERENV('sid');
END;
/
In order for the trigger above to compile, you'll need to grant the owner of the trigger these permissions, when logged in as the SYS user:
grant select on V_$SESSION to <user>;
grant select on V_$SQL to <user>;
You will likely want to protect the insert statement in the trigger with some condition that only makes it log when the the change you're interested in is occurring - on my test server this statement runs rather slowly (1 second), so I wouldn't want to be logging all these updates. Of course, in that case, you'd need to change the trigger to be a row-level one so that you could inspect the :new or :old values. If you are really concerned about the overhead of the select, you can change it to not join against v$sql, and instead just save the SQL_ADDRESS column, then schedule a job with DBMS_JOB to go off and update the sql_text column with a second update statement, thereby offloading the update into another session and not blocking your original update.
Unfortunately, this will only tell you half the story. The statement you're going to see logged is going to be the most proximal statement - in this case, an update - even if the original statement executed by the process that initiated it is a stored procedure. This is where the program_id column comes in. If the update statement is part of a procedure or trigger, program_id will point to the object_id of the code in question - you can resolve it thusly:
SELECT * FROM all_objects where object_id = <program_id>;
In the case when the update statement was executed directly from the client, I don't know what program_id represents, but you wouldn't need it - you'd have the name of the executable in the "program" column of statement_tracker. If the update was executed from an anonymous PL/SQL block, I'm not how to track it back - you'll need to experiment further.
It may be, though, that the osuser/machine/program/module information may be enough to get you pointed in the right direction.
If it is a scheduled database job then you can find out what scheduled database jobs exist and look into what they do. Other things you can do are:
look at the dependencies views e.g. ALL_DEPENDENCIES to see what packages/triggers etc. use that table. Depending on the size of your system that may return a lot of objects to trawl through.
Search all the database source code for references to the table like this:
select distinct type, name
from all_source
where lower(text) like lower('%mytable%');
Again that may return a lot of objects, and of course there will be some "false positives" where the search string appears but isn't actually a reference to that table. You could even try something more specific like:
select distinct type, name
from all_source
where lower(text) like lower('%insert into mytable%');
but of course that would miss cases where the command was formatted differently.
Additionally, could there be SQL scripts being run through "cron" jobs on the server?
Just write an "after update" trigger and, in this trigger, log the results of "DBMS_UTILITY.FORMAT_CALL_STACK" in a dedicated table.
The purpose of this function is exactly to give you the complete call stack of al the stored procedures and triggers that have been fired to reach your code.
I am writing from the mobile app, so i can't give you more detailed examples, but if you google for it you'll find many of them.
A quick and dirty option if you're working locally, and are only interested in the first thing that's altering the data, is to throw an error in the trigger instead of logging. That way, you get the usual stack trace and it's a lot less typing and you don't need to create a new table:
AFTER UPDATE ON table_of_interest
BEGIN
RAISE_APPLICATION_ERROR(-20001, 'something changed it');
END;
/

Resources