How to organize WebOS SQL code that depends on previous results? - database

I want to do a simple WebOS Mojo app that adds dates to a database, but before that it needs to check few conditions by interrogating the database. Given the asynchronous mode of accessing the database in WebOS I'm wondering what is the most efficient and short way of writing such code.
For example I need to make sure the new date is not already in the database. Then I need to get the closest date so that I can compute the difference in days and throw an error if the difference is too small. Then I need to insert the new date and then compute an average.
This would be easy to do in a synchronous way of accessing the db, but I don't really like the idea of writing parts of the code in multiple success handlers of the different sql statements executed. Is there a more elegant solution?

You can use inline callbacks to the HTML 5 relational database functions:
function createProject(project, onSuccess) {
if (project.projectId)
throw new StorageError("project already exists");
if (project.path)
throw new StorageError("project already has a path");
project.projectId = ++Tracker.maxLocalId * 4096;
project.path = calcNextProjectPath();
project.normalize();
Tracker.db.transaction(
function (transaction) {
transaction.executeSql(
"INSERT OR ROLLBACK INTO item (dbId, path, hasChildren, kind, summaryText, place, work, responsible, responsibleClass) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
[project.projectId, project.path, project.hasChildren, project.kind, project.title, project.place, project.work, project.responsible, project.responsibleClass],
function (transaction, resultSet) {
Mojo.Log.info("DB: inserted new project item", resultSet.insertId, project.title);
transaction.executeSql(
"INSERT OR ROLLBACK INTO project (projectId, accountId, title, backendKind, backendStatus, backendLastChanged, lastSuccessfulDown) \
VALUES (?, ?, ?, ?, ?, ?, ?)",
[project.projectId, project.accountId, project.title, project.backendKind, project.backendStatus, project.backendLastChanged, project.lastSuccessfulDown],
function (transaction, resultSet) {
Warn.logInfo("created new project", "projectId=" + resultSet.insertId, project.title);
if (onSuccess)
onSuccess();
},
function (transaction, sqlError) {
Warn.bannerError("create", $L("Quit and reset your phone."), "project row insertion failed: ", sqlError.message, sqlError.code, project);
return true; // abort whole transaction
}
);
},
function (transaction, sqlError) { // failure of insert project item
if (sqlError.code === 1 && sqlError.message === "constraint failed" && Mojo.appInfo.id !== "com.outlinetracker.outlinetracker") {
upgradeAlert(true);
} else {
Warn.bannerError("create", $L("Quit and reset your phone."), "project item insertion failed: ", sqlError.message, sqlError.code);
}
return true; // abort whole transaction
}
);
}, // end transaction function
function (sqlError) { // seems to only be called for exceptions in callbacks
Warn.logError($L("Quit and reset your phone."), "transaction 'insert project' failed", sqlError.message, sqlError.code);
}
); // end transaction call
}

Related

SqfliteDatabaseException when trying to insert into a database

I am trying to insert a new note into a database with the following flutter code. final noteId = await db.insert(noteTable, { userIDColumn: owner.id, textColumn: text, isSyncedWithCloudColumn: 1, });
I get the following exception Exception has occurred. SqfliteDatabaseException (DatabaseException(NOT NULL constraint failed: note.id (code 1299 SQLITE_CONSTRAINT_NOTNULL)) sql 'INSERT INTO note (user_id, text, is_synced_with_cloud) VALUES (?, ?, ?)' args [1, , 1])
I tried the code described above and got the exception instead of a successful result.

Sales force trigger INVALID_FIELD_FOR_INSERT_UPDATE

Below code works fine when updating/inserting on Visual Force Page one record at a time, receive error 'Insert failed....INVALID_FIELD_FOR_INSERT_UPDATE, cannot specify Id in an insert call' when using data loader (error pointing to code, 'insert amcRecord'). Would anyone know how to fix?
trigger Status on Cl__c (after insert, after update) 
{
List<AMC__c> amcRecord = new List<AMC__c>();
for (Cl__c cls: Trigger.new ) 
{
    Cl__c oldcls = Trigger.oldMap.get(cls.Id);
    if (cls.Status__c == 'Completed' && (oldcls.Status__c != 'Completed'  )) 
{
     AMC__c newAMC = new AMC__c();
     newAMC.Cl__c = cls.ID;
     newAMC.Default__c = true;  
     amcRecord.add(newAMC); 
     insert amcRecord;
}
  }
}
amcRecord is a list, not a single item, but you're calling insert for every item in the request [which would only be 1 for the UI, but upto 200 with the data loader. You need to move the insert amcRecord line to after the for (... Trigger.new) loop has finished, so that its only called once, e.g.
trigger Status on Cl__c (after insert, after update)
{
List<AMC__c> amcRecord = new List<AMC__c>();
for (Cl__c cls: Trigger.new )
{
Cl__c oldcls = Trigger.oldMap.get(cls.Id);
if (cls.Status__c == 'Completed' && (oldcls.Status__c != 'Completed' ))
{
AMC__c newAMC = new AMC__c();
newAMC.Cl__c = cls.ID;
newAMC.Default__c = true;
amcRecord.add(newAMC);
}
}
insert amcRecord;
}
You shouldn't be performing DML inside a loop.This exception comes if you try to insert already inserted record.
Account a =new Account();
a.name='Hello';
insert a;
insert a;
Changed
insert amcRecord;
to
upsert amcRecord;
It seems to be working now.

SQLite prepare method fails due to syntax error

So I want to create a database for Users and insert values into the fields using variable. Initially I tried using it calling the do function, but it wasn't reading the variables properly so I decided to just use prepare and execute separately. This is my code:
$dbh->do("DROP TABLE IF EXISTS Users");
$dbh->do("CREATE TABLE Users(
zid TEXT,
Name TEXT,
Email TEXT,
password TEXT,
Mates TEXT,
Program TEXT,
Courses TEXT,
Suburb TEXT,
Birthday TEXT)");
$zid = "z33432523";
$name = "John Doe";
$email = "email#gmail.com";
$password = "alien";
$mates = "z3459148 z3458291";
$program = "";
$courses = "";
$suburb = "";
$birthday = "13/5/1992";
$sth = $dbh->prepare('INSERT INTO Users VALUES (?, ?, ?, ?, ?. ?, ?, ?, ?)');
$sth->execute($zid, $name, $email, $password, $mates, $program, $courses, $suburb, $birthday);
$dbh->disconnect();
However, if I try running this code I get the following error:
DBD::SQLite::db prepare failed: near ".": syntax error at ./dbm.pl line 35.
I'm not sure exactly what the problem is?
near ".": syntax error
INSERT INTO Users VALUES (?, ?, ?, ?, ?. ?, ?, ?, ?)
^

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

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) {
...
}

CompositeId and Identity_Insert

I have a class mapped like the following:
public class FooMap : ClassMap<Foo>
{
public FooMap()
{
Table("Foo");
LazyLoad();
CompositeId().KeyProperty(x => x.ID,
kp => kp.ColumnName("Id")
.Type(typeof(long)))
.KeyProperty(x => x.ValidFrom);
}
}
On the MSSQL side, Id is identity column and the table's PK is composed of Id and ValidFrom.
Here's the code I use to save:
ISession session = SessionService.GetSession();
new SqlCommand("SET IDENTITY_INSERT Foo ON",
session.Connection as SqlConnection)
.ExecuteNonQuery();
try
{
// performs various versioning checks,
// then saves using transaction.
// The session is the same as above
GenericDataService.Save(myFoo);
}
finally
{
new SqlCommand("SET IDENTITY_INSERT Foo OFF",
session.Connection as SqlConnection)
.ExecuteNonQuery();
}
Although I set Identity_Insert to ON, I get the following exception (when keeping ID and setting new ValidFrom):
Cannot insert explicit value for identity column in table 'Foo' when IDENTITY_INSERT is set to OFF.
This is the SQL executed:
INSERT INTO Foo (C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, Id, ValidFrom)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Can anyone explain why I still get that exception?
If the problem has to do with separate transactions like Nathan Fisher suggested, then NHibernate's ITransaction.Enlist(IDbCommand) method should fix it. Try something like this:
using (var trx = session.BeginTransaction())
{
ExecuteInNHTransaction(session, "SET IDENTITY_INSERT Foo ON");
session.Save(myFoo);
ExecuteInNHTransaction(session, "SET IDENTITY_INSERT Foo OFF");
trx.Commit();
}
private static void ExecuteInNHTransaction(ISession session, string commandText)
{
var command = new SqlCommand(commandText,
(SqlConnection) session.Connection);
session.Transaction.Enlist(command);
command.ExecuteNonQuery();
}

Resources