Can anyone explain the concept of restoring the exception environment simply and smoothly.
It is said that when we use the exception handler in the try...endtry statementØWhen the program reaches the endtry, it restores the exception environment, but if it suddenly encounters a break command, for example, this recovery does not take place.
And the program even after exiting the try.......endtry command thinks that it is in the previous exception environment, and if another error occurs, it returns to the previous try......endtry command.
Like the following code snippet:
program testBadInput3;
#include( "stdlib.hhf" )
static
input: int32;
begin testBadInput3;
// This forever loop repeats
//until the user enters
// a good integer and the
break
//statement below
// exits the loop.
forever
try
stdout.put( "Enter an integer
value: " );
stdin.get( input );
stdout.put( "The first input
value was: ", input, nl );
break;
exception( ex.ValueOutOfRange
)
stdout.put( "The value was too
large, re-enter." nl );
exception( ex.ConversionError
)
stdout.put( "The input
contained illegal characters,
re-enter." nl );
endtry;
endfor;
// Note that the following
code //is outside the loop and
there
// is no try..endtry statement
//protecting this code.
stdout.put( "Enter another
number: " );
stdin.get( input );
stdout.put( "The new number
is:
", input, nl );
end testBadInput3;
Related
This try catches the exception:
try die X::AdHoc;
say "Got to the end";
The output shows that the program continues:
Got to the end
If I attempt it with shell and a command that doesn't exit with 0, the try doesn't catch it:
try shell('/usr/bin/false');
say "Got to the end";
The output doesn't look like an exception:
The spawned command '/usr/bin/false' exited unsuccessfully (exit code: 1)
in block <unit> at ... line ...
What's going on that this makes it through the try?
The answer is really provided by Jonathan Worthington:
https://irclog.perlgeek.de/perl6-dev/2017-04-04#i_14372945
In short, shell() returns a Proc object. The moment that object is sunk, it will throw the exception that it has internally if running the program failed.
$ 6 'dd shell("/usr/bin/false")'
Proc.new(in => IO::Pipe, out => IO::Pipe, err => IO::Pipe, exitcode => 1, signal => 0, command => ["/usr/bin/false"])
So, what you need to do is catch the Proc object in a variable, to prevent it from being sunk:
$ 6 'my $result = shell("/usr/bin/false"); say "Got to the end"'
Got to the end
And then you can use $result.exitcode to see whether it was successful or not.
How can I rewrite these 2 commands, which work fine in a mapping, so that they will work in a function?
:if has_key(glos,#g)==1<cr>:let #j=eval('glos.'.#g)<cr>
The function concerned is executed by vim without comment, but #j remains unchanged, as if they had failed, but no message/error is generated.
Here is the complete code involved, the command that loads the dictionary, the function that does not work, and the mapping from that function that does.
" read the glossary into the dictionary, glos
let glos=eval(join(readfile("glossary.dict")))
" 2click item of interest and this will
" send image filepath to xv
" if item all-caps find same at start of its line
" If capitalized at eol find same at start of its line
" if all lower-case at eol find next occurrence of same
" look lower-case or capitalized word up in glossary.txt
" find _\d\+ (page no.) alone on its line in text
com! F call F()
function! F()
normal "ayiw"cyE"by$
let #c=substitute(#c,"[,.?':;!]\+","","g")
if #c=~'images\/ss\d\d\d*'
let #i='!display -geometry +0+0 '.#c.' &'
pkill display
#i
elseif #c==toupper(#c)
let #n=search('^'.#c,'sw')
elseif #c!=#b
let #f=3
let #g=tolower(#c)
while #f>0
try
let #j=eval('glos.'.#g)
catch
let #f=#f-1
let #g=strpart(#g,0,strlen(#g)-1)
continue
endtry
break
endwh
if #f>0
let #h=substitute(#j," glosimgs.*",'','')
if #h!=#j
let #i='!xv -geometry +0+380 '.substitute(#j,'^.\{-}\( glosimgs.*\)$','\1','').' &'
!pkill xv
#i
endif
echo #h
else
echo 'No matching entry for '.#c
endif
elseif #c=~'\u\l\+$'
let #n=search('^'.#c,'sw')
elseif #c=~'\l\+$'
norm *
elseif #c=~'^_\w\+$'
let #/='^'.#c.'$'
norm nzz
endif
endfunction
map <silent> <2-LeftMouse> "ayiw"cyE"by$:let #c=substitute(#c,"[,.?':;!]\+","","g")<cr>:if #c=~'images\/ss\d\d\d*'<cr>:let #i='!display -geometry +0+0 '.#c.' &'<cr>:pkill display<cr>:#i<cr>:elseif #c==toupper(#c)<cr>:let #n=search('^'.#c,'sw')<cr>:elseif #c!=#b<cr>:let #f=3<cr>:let #g=tolower(#c)<cr>:while #f>0<cr>:try<cr>:let #j=eval('glos["'.#g.'"]')<cr>:catch<cr>:let #f=#f-1<cr>:let #g=strpart(#g,0,strlen(#g)-1)<cr>:continue<cr>:endtry<cr>:break<cr>:endwh<cr>:if #f>0<cr>:let #h=substitute(#j," glosimgs.*",'','')<cr>:if #h!=#j<cr>:let #i='!xv -geometry +0+380 '.substitute(#j,'^.\{-}\( glosimgs.*\)$','\1','').' &'<cr>:!pkill xv<cr>:#i<cr>:endif<cr><cr<cr>>:echo #h<cr>:else<cr>:echo 'No matching entry for '.#c<cr>:endif<cr>:elseif #c=~'\u\l\+$'<cr>:let #n=search('^'.#c,'sw')<cr>:elseif #c=~'\l\+$'<cr>:norm *<cr>:elseif #c=~'^_\w\+$'<cr>:let #/='^'.#c.'$'<cr>:norm nzz<cr>:endif<cr>
Specifically, I should have written:
:if has_key(**g:**glos,#g)==1:let #j=eval('**g:**glos.'.#g)
:h g: goes straight to the heart of the matter; in a function all references are local to that function, so references to any variable outside the function must be global, by prepending 'g:' to the variable name. As I created the dictionary independent of the function, the function must reference it as a global item.
Of course, if you are not aware of 'g:', it is rather difficult to find that help reference, but that's a frequent problem using help.
And, of course, the ** surrounding g: aren't required, that's what this site gives you in lieu of bolded text, apparently.
I can't seem to catch an exception when using json.loads even though I specifically call it out. I largely see this when trying to stress my server with lots of client connection sending data very quickly. See my error below:
(I've replaced my IP address with X's in the error code)
EX: Unterminated string starting at: line 1 column 49 (char 48) Data:
'{"ap-hdop":0.55,"rtcmin":"38","ap-latdec":3.134,"a' error: uncaptured
python exception, closing channel
(:Unterminated string
starting at: line 1 column 49 (char 48)
[//faraday_server_handler.py|collect_incoming_data|34]
[/usr/lib/python2.7/json/init.py|loads|338]
[/usr/lib/python2.7/json/decoder.py|decode|366]
[/usr/lib/python2.7/json/decoder.py|raw_decode|382])
I understand this that the code fails because I simply miss a double quotes on the line:
'{"ap-hdop":0.55,"rtcmin":"38","ap-latdec":3.134,"a'
This line is usually a LOT longer so that "a.... was supposed to keep going and complete it's quotes.
Here's my relevant code:
def collect_incoming_data(self, data):
"""Read an incoming message from the client, place JSON message data into buffer"""
#self.logger.debug('collect_fing_data() -> (%d bytes)\n"""%s"""', len(data), data)
try:
loaded_data = json.loads(data)
except ValueError, ex:
self.handle_error()
type,value,traceback = sys.exc_info()
print type
#print "Collect Incoming Data: " . time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime())
print "EX: ", ex
print "Data: ",repr(data)
Any ideas? I scoured the internet to see if I can find this issue, but I appear to be setting up to capture the exception which everyone else having this issue with loads seems to suggest to do.
EDIT 3/1/2016 - Evening
Commenting out my exception handle_error() let me see more of the error:
except ValueError, ex:
self.handle_error()
type,value,traceback = sys.exc_info()
print type
#print "Collect Incoming Data: " . time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime())
print "EX: ", ex
print "Data: ",repr(data)
Below is my new error, I've commented out personal data. It's apparent that the issue I really have now is in-fact the unterminated string
EX: Unterminated string starting at:
line 1 column 49 (char 48) Data:
'{"ap-hdop":0.55,"rtcmin":"31","ap-latdec":XX.XXX,"a' EX: No JSON object could be decoded Data:
'p-latdeg":34,"adc6":2006,"adc7":2007,"adc4":2004,"adc5":2005,"adc2":2002,"adc3":2003,"adc0":2000,"adc1":2001,"gpio-0":30,"gpio-1":50,"gpio-2":70,"speed":5.0,"adc8":2008,"rtcday":"01","longdeg":118,"longdec":XX.XXX,"altitude":31.0,"ap-speed":0.0,"ap-pdop":0.77,"lat-dir":"N","long-dir":"W","hdop":0.01,"ap-rf":0,"alt-units":"M","rtcdow":"2","callsign":"XXXXX","ap-callsign":"XXXXX","id":1,"ap-id":1,"rtcyear":"2016","rtcmon":"03","ap-vdop":0.66,"ap-lat-dir":"N","vdop":0.02,"rtchour":"22","latdec":XX.XXX,"latdeg":34,"ap-longdeg":118,"ap-longdec":XX.XXX,"rtcsec":"15","ap-altitude":86.0,"ap-long-dir":"W","pdop":0.01,"ap-alt-units":"M","faraday-port":0}'
OK my original question was answered which was "Why am I not catching the ValueError exception even though I am providing code to do just that?"
#tadhg McDonald-jensen was correct with his comment to remove my call to handle_error().
I still have some other issues but they are a different question. Thanks!
I just want to confirm what I'm seeing. Below is a small proof of concept Stored Proc I wrote that illustrates an issue I was having in a much bigger one.
ALTER PROCEDURE TestErrorHandling
#Param1 varchar(1) = ''
AS
BEGIN
/*
Unit test:
DECLARE #returnStatus nvarchar(15);
Exec #returnStatus = TestErrorHandling
print #returnStatus
*/
BEGIN TRY
print 'Start'
IF #Param1 = '' raiserror( '#Param1 is missing', 18, 1 );
print 'Should not see this'
END TRY
BEGIN CATCH
print error_message()
print error_state()
print error_number()
INSERT INTO [FlightOrderUploadFailedLog]
(EvtTyp)
VALUES ('max size of EvtType is only varchar(15) so this should cause truncation')
print 'after insert '
print error_message()
print error_state()
print error_number()
return -- added in second version (after original post)
END CATCH
END
GO
Output:
Start
#Param1 is missing
1
50000
Msg 8152, Level 16, State 4, Procedure TestErrorHandling, Line 30
String or binary data would be truncated.
The statement has been terminated.
after insert
#Param1 is missing
1
50000
-8
The surprising thing to me is that the program doesn't blow up on the "string or binary data would be truncated". In other words, the code after that still runs. Also, the error_message is not changed by a SQL error inside the catch block.
So the question is - what is the best practice for handling unexpected errors in the "BEGIN CATCH" section? Should I have another nested TRY/CATCH?
NOTE: This was my original question, but I thought to put this question there would get it off topic and confuse the issue. After this one gets answered, I'll go back and update that one: T-SQL Clear Errors
Part 2 - added later:
DECLARE #returnStatus nvarchar(15);
Exec #returnStatus = TestErrorHandling
print #returnStatus
This returns a -8. Where the heck does -8 come from?
I'm also experiementing with adding a "return" vs a "return 0". When BizTalk calls the stored proc, I want him to think it completed successfully, so as not to do the 3 retries every 5 minutes.
Added: I think this is mostly the answer I'm looking for:
SQL try-catch statement not handling error (SQL Server 2008)
But it does not discuss the best practice question I asked in this question.
UPDATE: Here is program to demo Allan's response:
ALTER PROCEDURE TestErrorHandling2
#Param1 varchar(1) = ''
AS
BEGIN
/*
Unit test:
DECLARE #returnStatus nvarchar(15);
Exec #returnStatus = TestErrorHandling2
print #returnStatus
This is proof of concept on error handling.
See question: https://stackoverflow.com/questions/20245900/t-sql-is-error-handling-totally-turned-off-in-a-begin-catch-block
Testing to see if Truncation error stops or not.
*/
print 'Start'
INSERT INTO [FlightOrderUploadFailedLog]
(EvtTyp)
VALUES ('max size of EvtType is only varchar(15) so this should cause truncation')
print 'after insert #1'
print 'Message=' + IsNull(error_message(),'null')
print 'State=' + IsNull(convert(varchar(4),error_state()),'null')
print 'ErrorNumber=' + IsNull(convert(varchar(8),error_number()),'null')
BEGIN TRY
print 'Start - Begin Try'
INSERT INTO [FlightOrderUploadFailedLog]
(EvtTyp)
VALUES ('max size of EvtType is only varchar(15) so this should cause truncation')
print 'after insert #2 '
print 'Message=' + IsNull(error_message(),'null')
print 'State=' + IsNull(convert(varchar(4),error_state()),'null')
print 'ErrorNumber=' + IsNull(convert(varchar(8),error_number()),'null')
print 'The End'
END TRY
BEGIN CATCH
print 'Catch'
print 'Message=' + error_message()
print 'State=' + convert(varchar(4),error_state())
print 'ErrorNumber=' + convert(varchar(8),error_number())
return -- error has been theoretically handled by writing it to a database
END CATCH
END
GO
Result:
Start
Msg 8152, Level 16, State 4, Procedure TestErrorHandling2, Line 21
String or binary data would be truncated.
The statement has been terminated.
after insert #1
Message=null
State=null
ErrorNumber=null
Start - Begin Try
(0 row(s) affected)
Catch
Message=String or binary data would be truncated.
State=4
ErrorNumber=8152
-6
Well, let me try for what I can.
"Best practice" - I hate that phrase because 9 times out of 10 it's purely subjective because somebody somewhere read something.
So my subjective answer is that seeing as you can nest try/catch and put a try/catch within the catch block - then I'd consider it good error handling to put a try/catch within the catch - IF what you have can throw an error and is severe enough that you wish to handle it yourself.
So IMO - best practice is yes, nest try/catch for better error handling.
Secondly - the reason your "catch" doesn't blow up is that the truncating error is not a batch terminating error. It's error level isn't high enough, so subsequent statements will be executed.
Simply try it out with a print statement:
PRINT 'something'
--do your insert here
PRINT 'somethingelse'
Then you'll see you should get both print statements.
You can even suppress truncate errors if you wanted to by changing ANSI_WARNINGS to OFF. Not that I would recommend, but well ... :)
If you had a try/catch within your catch, that should catch your truncate error because the severity is enough to trigger catch.
I try to capture lines with calculations in my text document
and execute them.
I use this in my function:
for i in range(startline,endline)
let calculation = getline(i)
...
let out = eval(calculation)
...
endfor
sometimes something goes wrong and I receive this message:
Error detected while processing function....
Line ...
E488: Trailing Characters
Line .. is the line-nr in my function.
I would like to know also which calculation it concerns (which line in my text doc):
If Error detected = echo calculation
How can I check if there is an error message and echo the variable "calculation"?
There are two ways to handle script errors inside a function:
The first is suppressing the error via :silent!. Two downsides: You have to manually check for success, and any normal output from the evaluated script is suppressed, too (unless you do contortions with :unsilent).
let v:errmsg = ''
silent! let out = eval(calculation)
if v:errmsg != ''
" error
endif
I would recommend the second way via try...catch, which avoids the issues with the output and having to explicitly check for an error:
try
let out = eval(calculation)
catch /^Vim\%((\a\+)\)\=:E/
" v:exception contains what is normally in v:errmsg, but with extra
" exception source info prepended, which we cut away.
let v:errmsg = printf("Line: %d\nCalculation: %s\nError: %s", i, calculation, substitute(v:exception, '^Vim\%((\a\+)\)\=:', '', ''))
echohl ErrorMsg
echomsg v:errmsg
echohl None
endtry