not inserting data into tables with form trigger failure - oracle

I put a code on key next item which work partly I don't know why please help me if anyone knows about this using form 10g with oracle database 11g code is this
IF
:BUNDLE_NUM = :USER_ID
THEN INSERT INTO
PROD_CUT_ISSU_DTL
(TRANS_ID,TRNAS_DET_ID,ORDER_NUM,ARTICLE_ID,QTY,PROD_OPEN_ID,OPER_CODE)
VALUES
(:PAY_IN_OUT.ISS_T_ID, :PAY_IN_OUT.ISS_TRNAS_DET_ID, A,
B, :PROD_STCH_PROD_EMP_DET.ISS_TOT, 1 , :PROD_STCH_PROD_EMP_DET.OPER_CODE);
RAISE FORM_TRIGGER_FAILURE;
GO_ITEM('PAY_IN_OUT.USER_ID');
CLEAR_FORM(NO_VALIDATE);
END IF;
works fine when doing separate separate portion like if I run only this code it will work
IF
:BUNDLE_NUM = :USER_ID
THEN INSERT INTO
PROD_CUT_ISSU_DTL
(TRANS_ID,TRNAS_DET_ID,ORDER_NUM,ARTICLE_ID,QTY,PROD_OPEN_ID,OPER_CODE)
VALUES
(:PAY_IN_OUT.ISS_T_ID, :PAY_IN_OUT.ISS_TRNAS_DET_ID, A,
B, :PROD_STCH_PROD_EMP_DET.ISS_TOT, 1 , :PROD_STCH_PROD_EMP_DET.OPER_CODE);
END IF;
Or just run this code its working
IF
:BUNDLE_NUM = :USER_ID
THEN
RAISE FORM_TRIGGER_FAILURE;
GO_ITEM('PAY_IN_OUT.USER_ID');
CLEAR_FORM(NO_VALIDATE);
END IF;
Please if any one know where I am doing wrong please correct me Respects

This
RAISE FORM_TRIGGER_FAILURE;
looks terribly wrong. Basically, you're doing something (inserting a row) and then immediately raise an error. That just won't work.
Raise an error when you want to prevent something to happen (e.g. in exception handling section).
I suggest you remove it.
Also, note that KEY-NEXT-ITEM won't work if someone navigates through the form using a mouse.

Related

How to Write mock of method using with to send params

Hi I want to know how can I write rspec for the following
def find_user(content)
user = User.find(content.to_i) ||
User.find(email: content) rescue
nil
end
I tried writing
It "user with user name" do
expect(User).to receive(:find).with(email: "test#a.com").and_return(user)
End
But I am gettig error saying
Argument Error
Block not Passed
Can someone please tell what am i missing
I may look first at your code here.
def find_user(content)
user = User.find(content.to_i) ||
User.find(email: content) rescue
nil
end
What is content? I looks like you're expecting either a user_id or an email address.
Doing this from the console:
irb(main):080:0> User.find("email#email.com".to_i)
=> ActiveRecord::RecordNotFound (Couldn't find User with 'id'=0)
So it seems as if having a generic find_user method may be contributing to some of the test writing confusion.
Many times, overly complex tests point to overly complex code.
Perhaps you need one method
find_user_by_email(email)
and another
find_user_by_id(id)
Also, refer to https://api.rubyonrails.org/v6.1.3.2/classes/ActiveRecord/FinderMethods.html#method-i-find_by
It will automatically return nil if nothing is found.
Start there, And then like the other commenters, then post your class, and the spec and we can go from there.

Unable to close sqlite3 database with ruby

begin
db = SQLite3::Database.open "dbfile.db"
dbins = db.prepare("INSERT INTO table(a,b,c) VALUES (?,?,?);")
dbins.execute(vala,valb,valc)
rescue SQLite3::Exception => e
puts("Something went wrong: " + e)
ensure
db.close if db
end
So that would be the code I use to open an SQLite3 database and write data to it.
My problem is that this code always gives me the following error:
unable to close due to unfinalized statements or unfinished backups
If I remove the db.close if db part it works, but after several hours of the script running I get the too many open files error. Please do not advise me to raise my inode file limit, that would only be a temporary solution to a greater problem.
I do not want the script to just keep the database open forever, whenever an event happens I want it to open the db, write the data, and close it again, just how it's expected to work.
Note that this answer isn't helping because of the reason in the comment, which is true.
What do I have to do to "finish" the statement so I can close the database? I have tried to just add a sleep(5) before closing the database, but that had no effect.
I've found this Q suggesting to use finalize on the statement, but that seems to be only relevant for the C/C++ interface and not for ruby's sqlite3.
Reading the source code for the ruby gem helped. Specifically the file statement.c's following codeblock:
/* call-seq: stmt.close
*
* Closes the statement by finalizing the underlying statement
* handle. The statement must not be used after being closed.
*/
static VALUE sqlite3_rb_close(VALUE self)
{
sqlite3StmtRubyPtr ctx;
Data_Get_Struct(self, sqlite3StmtRuby, ctx);
REQUIRE_OPEN_STMT(ctx);
sqlite3_finalize(ctx->st);
ctx->st = NULL;
return self;
}
So using .close on the statement (e.g. dbins.close after the .execute in my code) will finalize the statement and make me able to close the database file.

Progress 4GL Exclusive Lock Not Releasing

I'm using proserve to enable multiple-user session.
This is my code in a mouse double-click trigger on my browse:
DO WITH FRAME MAIN-FRAME:
IF EMP-BROWSE:NUM-SELECTED-ROWS > 0 THEN
DO:
EMP-BROWSE:FETCH-SELECTED-ROW(1).
FIND CURRENT EMPLOYEE NO-ERROR NO-WAIT.
IF AVAILABLE (EMPLOYEE) THEN
DO:
DO TRANSACTION ON ERROR UNDO, LEAVE:
C-Win:SENSITIVE = NO.
FIND CURRENT EMPLOYEE EXCLUSIVE-LOCK.
MESSAGE STRING(EMPLOYEE.emp-num) + " locked.".
C-Win:SENSITIVE = YES.
END.
RELEASE EMPLOYEE.
END.
ELSE IF NOT AVAILABLE (EMPLOYEE) THEN
DO:
MESSAGE "The employee details is currently in-use in another session. Please try again later." VIEW-AS ALERT-BOX TITLE "System Message".
RETURN NO-APPLY.
END.
ELSE
DO:
MESSAGE "The record has been deleted in another session.".
RETURN NO-APPLY.
END.
END.
END.
SCENARIO:
Session A double clicks on browse record 1. It will then message something like "2001 locked." after that Session B double clicks on browse record 1 and it will fire the message at the IF NOT AVAILABLE (EMPLOYEE) block.
My question is shouldn't the RELEASE EMPLOYEE code enable session B to access the same record?
I have also tried FIND CURRENT EMPLOYEE NO-LOCK and putting either of the code inside and outside the DO TRANSACTION block but nothing happens.
EDIT:
I applied these changes but in the same scenario, Session B gets the message on the ELSE block which is MESSAGE "The record has been deleted in another session.". What am I doing wrong here?
When I add a call to a new window RUN newWindow.w. after MESSAGE STRING(EMPLOYEE.emp-num) + "locked."., with the same scenario while not closing the new window on Session A I get a proper response of the record being used in another session in Session B.
DO WITH FRAME MAIN-FRAME:
IF EMP-BROWSE:NUM-SELECTED-ROWS > 0 THEN
DO:
EMP-BROWSE:FETCH-SELECTED-ROW(1).
FIND CURRENT EMPLOYEE NO-LOCK NO-ERROR NO-WAIT.
DEFINE VARIABLE iOk AS LOGICAL NO-UNDO.
DEFINE BUFFER myEMPLOYEE FOR EMPLOYEE.
iOk = NO.
DO FOR myEMPLOYEE TRANSACTION:
FIND myEMPLOYEE WHERE myEMPLOYEE.emp-num = EMPLOYEE.emp-num EXCLUSIVE-LOCK NO-ERROR NO-WAIT.
IF AVAILABLE (myEMPLOYEE) THEN
DO:
IF LOCKED (myEMPLOYEE) THEN
DO:
MESSAGE "The employee details is currently in-use in another session. Please try again later." VIEW-AS ALERT-BOX TITLE "System Message".
RETURN NO-APPLY.
END.
ELSE
DO:
C-Win:SENSITIVE = NO.
MESSAGE STRING(EMPLOYEE.emp-num) + " locked.".
C-Win:SENSITIVE = YES.
END.
END.
ELSE
DO:
MESSAGE "The record has been deleted in another session.".
RETURN NO-APPLY.
END.
END.
END.
END.
RELEASE does not do what you think it does. Use of RELEASE is a red flag. It almost always means that the coder does not have a firm grasp of record and transaction scoping issues.
From the docs:
RELEASE
Verifies that a record complies with mandatory field and unique index definitions. It clears the record from the buffer and unites it to the database if it has been changed.
Notice how the definition says nothing about locks?
Embedding user interface within a transaction is a major mistake -- doing that essentially guarantees that you will have lock contention issues and scalability problems going forward.
As Jens points out your whole approach needs rethinking.
In order to properly control the record and transaction scope the best practice is to be very explicit about it and confine the update to a very tight block of code. Ideally you encapsulate it in a procedure or function like so:
function updEmpName returns character ( input empNum as character, input newName as character ):
define buffer employee for employee.
do for employee transaction:
find employee exclsuive lock where employee.employeeNum = empNum no-error.
if locked employee then
return "locked".
else if available employee then
do:
assign
employee.name = newName.
.
return "updated".
end.
else
return "no such employee".
end.
end.
If you cannot put the update in a function or procedure then you need to "strong scope" the buffer being used to update the record:
define variable ok as logical no-undo.
define buffer updEmployee for employee.
ok = no.
do for updEmployee transaction:
find updEmployee exclusive-lock where updEmployee.employeeNum = empNum no-error.
if available updEmployee then
assign
/* update whatever fields are needed */
ok = yes
.
end.
The "DO FOR updEmployee" is called "strong scope". That means that there cannot be "free references" to the updEmployee buffer outside that block. If the compiler complains that there is a problem then you need to fix it becuase your scope f not what you think it is.
I think you have some things to reconsider here.
This row:
FIND CURRENT EMPLOYEE NO-ERROR NO-WAIT.
Will result in a SHARE-LOCK. Some people (including me) tend to avoid those. I would change into:
FIND CURRENT EMPLOYEE EXCLUSIVE-LOCK NO-ERROR NO-WAIT.
The row after:
IF AVAILABLE (EMPLOYEE) THEN
Will only deal with the existence of the record - not it's locking status. All in all, consider the online (F1) help:
LOCKED function
Returns a TRUE value if a record is not available to a prior FIND . . . NO-WAIT statement because another user has locked a record.
AVAILABLE function
Returns a TRUE value if the record buffer you name contains a record and returns a FALSE value if the record buffer is empty.
FIND...NO-ERROR
Suppresses ABL errors or error messages that would otherwise occur and diverts them to the ERROR-STATUS system handle. If an error occurs, the action of the statement is not done and execution continues with the next statement. If the statement fails, any persistent side-effects of the statement are backed out. If the statement includes an expression that contains other executable elements, like methods, the work performed by these elements may or may not be done, depending on the order the AVM resolves the expression elements and the occurrence of the error.
FIND...NO-WAIT
Causes FIND to return immediately and raise an error condition if the record is locked by another user (unless you use the NO-ERROR option on the same FIND statement). For example:
You could change this into (and the ELSE statement to something like):
FIND CURRENT EMPLOYEE EXCLUSIVE-LOCK NO-ERROR NO-WAIT.
IF LOCKED(EMPLOYEE) THEN DO:
MESSAGE "Locked by another user".
END.
ELSE DO:
IF AVAILABLE (EMPLOYEE) THEN DO:
MESSAGE "Go ahead and change".
END.
ELSE DO:
MESSAGE "Not available".
END.
END.
Have in mind that you are writing code that's a mix between GUI, data access and business logic. This is a bad practice. You can do it for smaller examples, tests and things like that but you should actually avoid it. Even if you're not using AppServer right now you will most likely want to do that in the future - if the code already have nice separation of concern (for instance GUI, business logic and data access) future modernization will be so much easier.
The command FETCH-SELECTED-ROW() already put the selected record in browse into the record buffer using the LOCK that's defined within BROWSE definition, then you don't need to use a FIND statement to do so. Anyway, when I need to do things like you trying to do I use a code like this one :
DO WITH FRAME {&FRAME-NAME}:
DO iCount = 1 TO brEmployee:NUM-SELECTED-ROWS:
brEmployee:FETCH-SELECTED-ROW(iCount).
IF AVAIL Employee THEN DO:
FIND CURRENT Employee EXCLUSIVE-LOCK.
/* Do whatever I need */
FIND CURRENT Employee NO-LOCK.
END.
ELSE DO:
IF LOCKED(Employee) THEN DO:
MESSAGE 'Record locked!'
VIEW-AS ALERT-BOX INFO BUTTONS OK.
END.
ELSE DO:
MESSAGE 'Record deleted!'
VIEW-AS ALERT-BOX INFO BUTTONS OK.
END.
END.
END.
END.
In this example, the FETCH-SELECTED-ROW() aways return the record. If it isn't available you can check LOCKED condition. To avoid the browse to return records that doesn't exist in database you can use -rereadnolock session parameter.
But you're using the code within MOUSE-SELECT-DBLCLICK event of your browse. Then, you can replace the code with something like this :
DO WITH FRAME {&FRAME-NAME}:
brEmployee:SELECT-FOCUSED-ROW() NO-ERROR.
IF AVAIL Employee THEN DO:
FIND CURRENT Employee EXCLUSIVE-LOCK.
/* Do whatever I need */
FIND CURRENT Employee NO-LOCK.
END.
ELSE DO:
IF LOCKED(Employee) THEN DO:
MESSAGE 'Record locked!'
VIEW-AS ALERT-BOX INFO BUTTONS OK.
END.
ELSE DO:
MESSAGE 'Record deleted!'
VIEW-AS ALERT-BOX INFO BUTTONS OK.
END.
END.
END.
Hope it helps.

Datamapper: report why I can't destroy record

I'm setting up my db model using datamapper and dm-contraints. I have two models which have a many to many relationship but when I try to destroy one, the only message I get is false.
Is it possible to get datamapper to give me more feedback one which relationship is exactly causing the problem?
With datamapper 1.2.1:
def why_you_no_destroy? model
preventing = []
model.send(:relationships).each do |relationship|
next unless relationship.respond_to?(:enforce_destroy_constraint)
preventing << relationship.name unless relationship.enforce_destroy_constraint(model)
end
preventing
end
Unfortunately DM doesn't provide a way to report why destroy failed.
Most of time the destroy failed because of its associations. DM have a mechanism to avoid orphan records.
To avoid this kind of destroy failed, you can Use dm-constraints(https://github.com/datamapper/dm-constraints ) to set up true database level foreign key references, which default to protect, but can be set to cascade deletes instead.
class List
has n, :todos, :constraint => :destroy (or :destroy!)
end
Sadly, Currently dm-constraints only supports PostgreSQL and MySQL.
For other database, you can check all the associations manually and delete them first, then delete the model。
You can get information on DataMapper errors from
model.destroy
if model
model.errors.each do |error|
p error
end
end
Sometimes that doesn't tell you anything though, in which case you can put your code inside of a begin/rescue block e.g.
begin
model.destroy
rescue Exception => exc
p exc
end

AWS S3 NoSuchBucket Exception Not Caught in Rescue Clause

I'm trying to get a bucket in Ruby using the AWS SDK, and trying to catch a NoSuchBucket error. Problem is, my rescue block is not catching the error, and so my app crashes. Here is the relevant code:
begin
b = s3.buckets[bucket_name]
rescue AWS::S3::Errors::NoSuchBucket
puts Invalid bucket name.
exit 1
end
and the error message is:
C:/Ruby193/lib/ruby/gems/1.9.1/gems/aws-sdk-1.5.6/lib/aws/core/client.rb:277:in
`return_or_raise': The specified bucket does not exist (AWS::S3::Errors::NoSuchBucket)
Am I just making a stupid beginner syntax error, or is there a bug in the AWS code that's not actually throwing the error? I've also tried catching all errors and still no dice.
b = s3.buckets[bucket_name]
Doesn't actually make any requests and won't ever through exceptions like NoSuchBucket.
It just returns a bucket object that knows what its name is. A request only happens when you actually try to do something with the bucket (list its contents, add a file to it) and it is at this point that NoSuchBucket is raised. This is outside of your begin block and so your rescue doesn't handle it. If you need to rescue that exception, you need to be putting your begin/rescue around the places that you actually use the bucket.
If you are just trying to validate that it actually exists you could do something like
s3.buckets[bucket_name].exists?

Resources