How to use transaction with PQexecPrepared libpq - postgresql

I'm new to postgresql and would like to ask how to do a transaction using BEGIN, COMMIT and PQexecPrepared. In my program, I have to update many tables before COMMIT. I do understand that we need to use:
1. PQexec(conn,"BEGIN");
2. execute some queries
3. PQexec(conn,"COMMIT");
I had first tried by using PQexecParams, it worked:
PQexec(conn,"BEGIN");
PQexecParams(conn, "INSERT INTO Cars (Id,Name, Price) VALUES ($1,$2,$3)",
3, NULL, parValues, NULL , NULL, 0 );
PQexec(conn,"COMMIT");
However when I had tried by using PQexecPrepared, my table Cars wasn't updated after COMMIT (of course it worked in autocommit mode without BEGIN &COMMIT )
PQexec(conn,"BEGIN");
PQprepare(conn,"teststmt", "INSERT INTO Cars (Id,Name, Price) VALUES ($1,$2,$3)", 3, NULL );
PQexecPrepared(conn, "teststmt", 3, parValues,NULL, NULL,0);
PQexec(conn,"COMMIT");
Do you have any advice in this case?

Related

DB2 measure execution time of triggers

How can I best measure the execution time of triggers in DB2 for insert or update.
It is needed for some performance issues, some of them are behaving very slow.
CREATE OR REPLACE TRIGGER CHECK
NO CASCADE BEFORE INSERT ON DAG
REFERENCING NEW AS OBJ
FOR EACH ROW MODE DB2SQL
WHEN(
xyz)
)
SIGNAL SQLSTATE xxx)
For compiled triggers (that is, with BEGIN ... END body):
SELECT
T.TRIGNAME
, M.SECTION_NUMBER
, M.STMT_EXEC_TIME
, M.NUM_EXEC_WITH_METRICS
-- Other M metrics
, M.*
, M.STMT_TEXT
FROM SYSCAT.TRIGGERS T
JOIN SYSCAT.TRIGDEP D
ON (D.TRIGSCHEMA, D.TRIGNAME) = (T.TRIGSCHEMA, T.TRIGNAME)
JOIN TABLE (MON_GET_PKG_CACHE_STMT (NULL, NULL, NULL, -2)) M
ON (M.PACKAGE_SCHEMA, M.PACKAGE_NAME) = (D.BSCHEMA, D.BNAME)
WHERE D.BTYPE = 'K'
-- Or use whatever filter on your triggers
AND (T.TABSCHEMA, T.TABNAME) = ('MYSCHEMA', 'MYTABLE')
ORDER BY 1, 2
For inlined triggers (that is, with BEGIN ATOMIC ... END body):
No way to get separate statistics for them. They are compiled and optimized with the corresponding statement fired them.

INSERT INTO SELECT JOIN returning null from joined table (Postgres)

I'm using the following Knex statement to copy data from two tables into another table:
const insert = knex.from(knex.raw('?? (??, ??, ??, ??, ??, ??, ??)', ['carrier', 'docket_number', 'dot_number', 'legal_name', 'dba_name', 'nbr_power_unit', 'rating', 'carrier_operation']))
.insert(knex('carrier_temp as ct').leftJoin('carrier_census_temp as cen', 'ct.dot_number', 'cen.DOT_NUMBER')
.select(['ct.docket_number as docket_number',
'ct.dot_number as dot_number',
'ct.legal_name as legal_name',
'ct.dba_name as dba_name',
'cen.tot_pwr as nbr_power_unit',
'cen.RATING as rating',
knex.raw('CASE WHEN cen.crrinter = \'A\' THEN \'INTERSTATE\' ELSE \'INTRASTATE\' END as "carrier_operation"')])).toString()
const conflict = knex.raw('ON CONFLICT (docket_number) DO NOTHING;').toString()
const q = insert + conflict
await knex.raw(q).debug()
The generated sql is:
INSERT INTO "carrier"
(
"docket_number",
"dot_number",
"legal_name",
"dba_name",
"nbr_power_unit",
"rating",
"carrier_operation"
)
SELECT "ct"."docket_number" AS "docket_number",
"ct"."dot_number" AS "dot_number",
"ct"."legal_name" AS "legal_name",
"ct"."dba_name" AS "dba_name",
"cen"."tot_pwr" AS "nbr_power_unit",
"cen"."RATING" AS "rating",
CASE
WHEN cen.crrinter = 'A' THEN 'INTERSTATE'
ELSE 'INTRASTATE'
END AS "carrier_operation"
FROM "carrier_temp" AS "ct"
left join "carrier_census_temp" AS "cen"
ON "ct"."dot_number" = "cen"."DOT_NUMBER" ON conflict (docket_number) DO nothing;
The carrier table receives all the columns that are referenced from carrier_temp or ct correctly, but the columns pulled from carrier_census_temp or cen are all ending up as NULL (nbr_power_unit, rating, and carrier_operation). That is, except for the case statement, which is setting every row's carrier_operation to INTRASTATE. If I instead equate NULL in the case statement, it still sets every row to INTRASTATE. Does anyone have any idea why this is?
See comments on question. I totally missed something wrong in my data that led to nothing ever being joined, which just leads everything to always be NULL.

Unable to update rows individually

I am trying to update our patient table within our system, but due to a connection we have with the state that sends modifications to that table to an external system I'm unable to do mass updates due to several triggers in our system (Microsoft SQL Server 2008 R2). The main piece of code in the trigger that is preventing
IF (#numrows > 1)
BEGIN
IF ##TRANCOUNT > 0 ROLLBACK TRANSACTION
SELECT #errmsg = OBJECT_NAME(##PROCID) + ' : more than one row is updated in table Patient'
RAISERROR(#errmsg,16,21)
RETURN
END
I cannot simply shut these triggers off where it would break a lot of things, so to do what would be a simple act of
update patient set security_level = '2'
where security_level = '1'
I used the following code which used to work in prior versions
declare #tmp_table table(
PRG int identity(1,1) Primary Key,
patient_id int
)
declare #start_value int = 1,
#finish_value int,
#patient_id int
Insert Into #tmp_table(patient_id ) Select patient_id From patient where security_level = '1'
Select #finish_value = max(PRG) From #tmp_table
While #start_value <= #finish_value
Begin
--now get a key for patient and store in variables
Select #patient_id = patient_id
From #tmp_table
Where PRG = #start_value
--.. and now update by key
Update patient
set security_level = '2'
Where patient_id = #patient_id
Set #start_value = #start_value + 1
End
I get the following error upon running that code
Msg 50000, Level 16, State 21, Procedure tU_Patient_HL7, Line 64
tU_Patient_HL7 : more than one row is updated in table Patient
Msg 3609, Level 16, State 1, Line 22
The transaction ended in the trigger. The batch has been aborted.
Any idea how I could tweak this or recode this to update the security level of all patients who have a security level set at 1 and switch it to 2?
Update
Would there be any way I could loop
Update top (1) patient
set security_level = '2'
where security_level = '1'
Until all rows are affected? That would work as well.
With out full code ,it is hard .I am guessing your update statement is conflicting with below peice of code..
IF (#numrows > 1)
even though you use
Update patient
set security_level = '2'
Where patient_id = #patient_id
Your update query may affect more than one row.So my best bet would be to tweak your update query to below or change trigger if you can which is desirable
Update top (1) patient
set security_level = '2'
Where patient_id = #patient_id
If you add to your update code a "GO 100", that should do the trick. You may need to put a delay in there as well if it updates too fast for the trigger.
Update top (1) patient
set security_level = '2'
where security_level = '1'
GO 100
The number of executions (i.e. 100 in my example) is up to you.

How can I combine these two statements?

I'm currently trying to insert data into a database from a text boxes, $enter / $enter2 being where the text is being written.
The database consists of three columns ID, name and nametwo
ID is auto incrementing and works fine
Both statements work fine on their own, but because they are being issued separately the first leaves nametwo blank and the second leaves name blank.
I've tried combining both but haven't had much luck, hope someone can help.
$dbh->do("INSERT INTO $table(name) VALUES ('".$enter."')");
$dbh->do("INSERT INTO $table(nametwo) VALUES ('".$enter2."')");
To paraphrase what others have said:
my $sth = $dbh->prepare("INSERT INTO $table(name,nametwo) values (?,?)");
$sth->execute($enter, $enter2);
So you don't have to worry about quoting.
You should read database manual.
The query should be:
$dbh->do("INSERT INTO $table(name,nametwo) VALUES ('".$enter."', '".$enter2."')");
The SQL syntax is
INSERT INTO MyTable (
name_one,
name_two
) VALUES (
"value_one",
"value_two"
)
Your way of generating SQL statements is very fragile. For example, it will fail if the table name is Values or the value is Jester's.
Solution 1:
$dbh->do("
INSERT INTO ".$dbh->quote_identifier($table_name)."
name_one,
name_two
) VALUES (
".$dbh->quote($value_one).",
".$dbh->quote($value_two)."
)
");
Solution 2: Placeholders
$dbh->do(
" INSERT INTO ".$dbh->quote_identifier($table_name)."
name_one,
name_two
) VALUES (
?, ?
)
",
undef,
$value_one,
$value_two,
);

Entity Framework executes both INSERT and UPDATE stored procedures when you do INSERT

I have this stored procedure, which is mapped in an Entity Framework 4.1 object. The call is made within the
using (TransactionScope transaction = new TransactionScope())
{
try
{
DbEntity.Car.AddObject(CarInfo);
DbEntity.SaveChanges();
/* Other object savings */
transaction.Complete();
DbEntity.AcceptAllChanges();
}
catch (Exception exp)
{
throw exp;
}
finally
{
DbEntity.Dispose();
}
}
I see the stored procedure mapping done currently. If I execute the stored procedure alone on MS SQL server, it executes it correctly.
Here is the stored procedure
ALTER PROCEDURE [dbo].[Carinsert] #Qty INT
,#StyleID INT
,#TFee MONEY
,#HWayTax MONEY
,#OFees MONEY
,#OFeesDescription NTEXT
,#MUp DECIMAL(18, 4)
,#BAss MONEY
,#PriceMSRP MONEY
,#PriceSpecial MONEY
AS
BEGIN
SET nocount ON
DECLARE #PTotal MONEY
DECLARE #TaxFeesNet MONEY
DECLARE #CarID INT
SET #TaxFeesNet = Isnull(#TFee, 0) + Isnull(#HWayTax, 0)
+ Isnull(#OFees, 0)
IF( #PriceSpecial IS NULL )
BEGIN
SET #PTotal = #PriceMSRP + #TaxFeesNet
END
ELSE
BEGIN
SET #PTotal = #PriceSpecial + #TaxFeesNet
END
INSERT INTO Car
(Qty
,StyleID
,MUp
,BAss
,PriceMSRP
,PriceSpecial
,TFee
,HWayTax
,OFees
,OFeesDescription
,PriceTotal)
VALUES (#Qty
,#StyleID
,#MUp
,#BAss
,#PriceMSRP
,#PriceSpecial
,#TFee
,#HWayTax
,#OFees
,#OFeesDescription
,#PTotal)
SELECT Scope_identity() AS CarID
END
If I execute this like on MS SQL it calculates the PriceTotal column in the table as 3444.00, which is correct.
#Qty= 5,
#StyleID = 331410,
#TFee = NULL,
#HWayTax = NULL,
#OFees = NULL,
#OFeesDescription = NULL,
#MUp = 4,
#BAss = 10000,
#PriceMSRP = 20120,
#PriceSpecial = 3444
When I run the MVC web application, and I debug & see these are the values passed and the PriceTotal comes to 20120.00
I couldn't figure out why it does not do the IF ELSE calculation & use the price.
Does anybody else see something weird? This has been daunting for few days now. Any help appreciated. Thanks
Update
I updated the title to better guide others
After few minutes of posting the question, I figured it all out.
There was actually 2 bug.
Entity framework used the UPDATE stored procedure even when I try to INSERT new records. Just for records, the UPDATE stored procedure required the CarID [primary key]. May be EF first does the INSERT and then does the UPDATE right away, even for creating new records?
The UPDATE sproc had a bug checking for NULL using <>. It should have been IS NOT NULL
In anycase, now This is a bigger issue. How to force EF to use INSERT sproc and not the UPDATE when I only want to do is create a new record?
I tried
DbEntityContext.ObjectStateManager.ChangeObjectState(carInfo, EntityState.Added);
and still EF kept on calling the UPDATE sproc.