How to handle/catch error from database trigger, in YII2 - database

this is my trigger
CREATE OR REPLACE TRIGGER trg_cek_pengurus
BEFORE INSERT ON tbl_pengurus
FOR EACH ROW
DECLARE
v_cek NUMBER(2);
BEGIN
IF :NEW.jabatan = 1 OR :NEW.jabatan = 2 THEN
select count(id)
into v_cek
from tbl_pengurus
where idkoperasi = :NEW.idkoperasi and jabatan = :NEW.jabatan;
IF v_cek > 0 THEN
RAISE_APPLICATION_ERROR (-20000, 'kepengurusan sudah ada');
END IF;
END IF;
END;
/
nah.., if the trigger have a return value is good,:v but it doesn't :v
so I set RAISE_APPLICATION_ERROR
And this is my controller
public function actionTambahPengurus()
{
$model = new Pengurus();
if ($model->load(Yii::$app->request->post())){
$model->IDKOPERASI = Yii::$app->user->identity->ID;
if($model->save())
return $this->redirect('kepengurusan');
}
return $this->render('tambah-pengurus',[
'model' => $model,
]);
}
And then I get error
SQLSTATE[HY000]: General error: 20000 OCIStmtExecute: ORA-20000: kepengurusan sudah ada
ORA-06512: at "DB_KOPERASI.TRG_CEK_PENGURUS", line 13
ORA-04088: error during execution of trigger 'DB_KOPERASI.TRG_CEK_PENGURUS'
(ext\pdo_oci\oci_statement.c:148)
The SQL being executed was: INSERT INTO "TBL_PENGURUS" ("NIK", "NAMA", "JABATAN", "EMAIL", "TGL_LAHIR", "ALAMAT", "TELEPON", "IDKOPERASI") VALUES ('2110131041', 'Rahmat Heru Kurniawan', 1, 'rahmatheruka2#gmail.com2', '3 July, 2015', 'sidoarjo', '0987654321', 8) RETURNING "ID" INTO :qp8
this is good, because this tell me that trigger is working
but of course this is bad for my website.
So i want to handle this, I've tries various ways from google, but nothing works.
Please.. is there anyone who can help me?

As far as I remember, any database related error will throw yii\db\Exception. You can use standard try / catch block to handle that:
try {
...
} catch (\yii\db\Exception $e) {
...
}

Related

Is it possible to get both the RAISEERROR message and the return value from a stored procedure in .NET?

I have this procedure that does a RAISEERROR and a return #tmp_cnt at the end. This RAISEERROR doesn't stop the procedure from executing as it should return the tmp_cnt as well. I use this in .NET and my code goes into the catch (SqlException e) part so this tmp_cnt doesn't get returned. This is the code for it
(string, int) result;
result.Item1 = null;
result.Item2 = -1;
try {
result.Item2 = await _context.Database.ExecuteSqlRawAsync("EXECUTE core.STORED_PROCEDURE", params);
} catch (SqlException e) {
foreach(SqlError error in e.Errors) {
if (error.Class > 10) {
result.Item1 = error.Message;
}
}
}
This way, I only get the error.Message while the result.Item2 remains -1 and I'm aware that this is a normal thing to do as this is what it should do. If I remove the try/catch part, the app throws an exception and code 500. The question I have is, is there a way to get both the RAISEERROR and the return from a stored procedure in .NET? This is the SQL part
IF #tmp_cnt < #ent_cnt
BEGIN
DECLARE #msg AS NVARCHAR(MAX) = CONCAT('Not all of the selected entities are eligible for change. Will be changed for ',
CAST(#tmp_cnt AS NVARCHAR(50)), ' out of the selected ', CAST(#ent_cnt AS NVARCHAR(50)), ' entities.')
RAISERROR(#msg, 15, 1)
RETURN #tmp_cnt;
END
If not possible, have you ever stumbled upon a scenario like this and is there a workaround for it?

how boolean function validation works in apex?

declare
curr_quantity number;
begin
select quantity
into curr_quantity
from stockrecord
where itemserialnumber = :p28_item_1
And inventoryid = :p28_inv_id;
if curr_quantity < :p28_quantity_1 then
return false;
else
return true;
end if;
end;
STOCKRECORD(itemserialnumber, inventoryid, quantity).
I am trying to validate my quantity at the front end in APEX Oracle with PL/SQL Function Body (Returning Boolean).
Suppose if I have a 500 quantity of an item in table and I set :p28_quantity_1 from 1-250 validation works fine but when i set it to 251 or so on the validation fails. I can't figure out the problem. Any help please.

Incorrect syntax near Throw - what am I missing?

I am trying to execute a THROW statement like so (value and 12345 being some random values):
use testdb;
go
begin try
if('value' in (select distinct shelf from itemloc))
update itemloc
set shelf = 'value'
where item = '12345';
end try
begin catch
;Throw 160073, 'Failed to update shelf value', 1;
end catch;
Using this reference
I looked at this question and I have the ; before my THROW. I'm also checking the syntax against the reference and fail to see why executing this returns
Msg 102, Level 15, State 1, Line 11
Incorrect syntax near 'Throw'.
You're inside a CATCH, you can't choose your error here, you would just use THROW;. Also, you don't need to start your statement with a semicolon, you already put one at the end of your last statement. It's a terminator (it goes at the end of the line), not at the beginning and end.
If you want to use a custom error, use RAISERROR. For example:
USE TESTDB;
GO
BEGIN TRY
IF('value' IN (SELECT DISTINCT shelf FROM itemloc))
UPDATE itemloc
SET shelf = 'value'
WHERE item = '12345';
END TRY
BEGIN CATCH
DECLARE #ERROR VARCHAR(MAX);
SET #ERROR = 'Failed to update shelf value';
RAISERROR(#ERROR, 11, 160073);
END CATCH

How do I run transactions in CakePHP3 for multiple model operation?

I want to use transactions on multiple insert/update query for multiple model/table.
In cakephp3 documentation have an example of transaction using connection manager execute() method but I have to use transaction with save() method of cakephp3. I tried it using save() method but it didn't work. There was a SQL error, it execute all query and saving data except the query where the sql error have, rollback didn't work!
my code was like-
$connection = ConnectionManager::get('default');
$connection->transactional(function ($connection) use($inputs, $status) {
$serviceTbl = $this->Service;
$service = $serviceTbl->newEntity();
$service->name = $inputs['name'];
$service = $serviceTbl->save($service);
if($service)
{
$this->loadModel('SrvApiClientInfo');
$SrvApiClientInfo = $this->SrvApiClientInfo;
$SrvApiClient = $SrvApiClientInfo->newEntity();
$SrvApiClient->client_name = $inputs['basic_info']['client_name'];
$SrvApiClient->organization_name = $inputs['basic_info']['vendor_name'];
$SrvApiClient->address = $inputs['basic_info']['address'];
$SrvApiClient->email = $inputs['basic_info']['email'];
$SrvApiClient->mobile = $inputs['basic_info']['mobile'];
$SrvApiClient->phone = $inputs['basic_info']['phone'];
$SrvApiClient->fax = $inputs['basic_info']['fax'];
$SrvApiClient->emergency_contact_name = $inputs['basic_info']['emergency_contact_name'];
$SrvApiClient->emergency_contact_mobile = $inputs['basic_info']['emergency_contact_mobile'];
$SrvApiClient->emergency_contact_designation = $inputs['basic_info']['emergency_contact_designation'];
$SrvApiClient = $SrvApiClientInfo->save($SrvApiClient);
if($SrvApiClient){
$this->loadModel('ServiceApiRegistration');
$tblServiceApiRegistration = $this->ServiceApiRegistration;
foreach($inputs['method'] as $method)
{
$ServiceApiRegistration = $tblServiceApiRegistration->newEntity();
$ServiceApiRegistration->service_id = $service['service_id'];
$ServiceApiRegistration->service_api_id = $method;
$ServiceApiRegistration->client_id = $SrvApiClient['client_id'];
$ServiceApiRegistration->status_id = $status['Inactive'];
$tblServiceApiRegistration->save($ServiceApiRegistration);
}
}
}
});
Check the docs that you've linked a little more closely, especially point 3 and 4 of the "The transactional method will do the following" list
The transactional method will do the following:
[...]
If the closure raises an exception, a rollback will be issued. The original exception will be re-thrown.
If the closure returns false, a rollback will be issued.
Your code neither returns false, nor does it throw an exception when something goes wrong, hence no rollback will be issued.
If there really was an SQL "error", ie an exception triggered in the core, then it should have been catched by the transaction wrapper, and a rollback should have been issued. So I'd suspect that either, there was no exception, or that rollbacks aren't supported or the driver thinks they aren't.

ORA-28113: policy predicate has error

I need some help with Oracle's VPD feature. I have never used it before but did some research online about it, however I'm running into a problem.
Here are the steps that I have taken:
QuanTriDL:
create table NhanVien2
table NhanVien2
QuanTriVPD:
CREATE OR REPLACE CONTEXT ThongTinTaiKhoan USING TTTK_PKG;
CREATE OR REPLACE PACKAGE TTTK_PKG IS
PROCEDURE GetTTTK;
END;
/
CREATE OR REPLACE PACKAGE BODY TTTK_PKG IS
PROCEDURE GetTTTK AS
TaiKhoan varchar(30);
tenPhong varchar(30);
tenChucVu varchar(30);
tenMaNV varchar(10);
BEGIN
TaiKhoan := LOWER(SYS_CONTEXT('USERENV','SESSION_USER'));
DBMS_SESSION.set_context('ThongTinTaiKhoan','GetTaiKhoan',TaiKhoan);
if (TaiKhoan = 'nv001') then
DBMS_SESSION.set_context('ThongTinTaiKhoan','GetChucVu','Giam doc');
else
if (TaiKhoan = 'nv002') then
DBMS_SESSION.set_context('ThongTinTaiKhoan','GetChucVu','Truong phong');
DBMS_SESSION.set_context('ThongTinTaiKhoan','GetPhong','Kinh doanh');
else
if (TaiKhoan = 'nv006') then
DBMS_SESSION.set_context('ThongTinTaiKhoan','GetChucVu','Truong phong');
DBMS_SESSION.set_context('ThongTinTaiKhoan','GetPhong','Ky thuat');
else
DBMS_SESSION.set_context('ThongTinTaiKhoan','GetChucVu','Nhan vien');
end if;
end if;
end if;
EXCEPTION
WHEN NO_DATA_FOUND THEN NULL;
END GetTTTK;
END;
/
CREATE OR REPLACE TRIGGER RangBuocTTTK AFTER LOGON ON DATABASE
BEGIN QuanTriVPD.TTTK_PKG.GetTTTK;
EXCEPTION WHEN NO_DATA_FOUND
THEN NULL;
END;
/
then:
CREATE OR REPLACE FUNCTION Select_Nhanvien(
schema_p IN VARCHAR2,
table_p IN VARCHAR2)
RETURN VARCHAR2
AS
getChucVu varchar(50);
trave varchar2(1000);
BEGIN
SELECT SYS_CONTEXT('ThongTinTaiKhoan','GetChucVu') into getChucVu FROM DUAL;
trave := '1=2';
if (getChucVu = 'Giam doc') then
trave := NULL;
else
if (getChucVu = 'Truong phong') then
trave :='Phong=(SELECT SYS_CONTEXT(''ThongTinTaiKhoan'',''GetPhong'') FROM DUAL)';
else
trave :='TenTaiKhoan=(SELECT SYS_CONTEXT(''ThongTinTaiKhoan'',''GetTaiKhoan'') FROM DUAL)';
end if;
end if;
RETURN trave;
END;
/
BEGIN
DBMS_RLS.ADD_POLICY (
object_schema => 'QuanTriDL',
object_name => 'NhanVien2',
policy_name => 'VPD_Select_Nhanvien',
function_schema => 'QuanTriVPD',
policy_function => 'Select_Nhanvien',
statement_types => 'SELECT');
END;
/
When connecting as nv001, nv002, nv006 it's OK. But connecting another user:
ORA-28113: policy predicate has error
Why does it cause that error?
(year old question but since I stumbled across it I'll go ahead and answer it for anyone else...)
ORA-28113 just means that when your policy function returned a where clause, the resulting SQL had some error. You can get details by looking at the trace file. Also, try:
select Select_Nhanvien('myschema','mytable') from dual;
And then append the results to a WHERE clause like this:
SELECT * FROM MYTABLE WHERE <results from above>;
And then you should see the root cause. I'm guessing in the case above the 'other user' didn't have either the sys_context variables required to build the where clause, or access to the login trigger.
As a side note, another problem you can run into here is circular reference when your policy function references its own table - ideally I would expect a policy function to bypass itself within the policy function so you can do NOT EXISTS, etc but it doesn't seem to work that way.

Resources