Couldnโ€™t find an adobe doc for `exceptionKeyExists...
# documentation
f
Couldnโ€™t find an adobe doc for
exceptionKeyExists()
it appears to have worked since CF2016: https://cfdocs.org/exceptionkeyexists hereโ€™s how I assume it work (and it does):
Copy code
try {
    x = 5/0;
} catch (any err) {
    if (exceptionKeyExists(err, "message")) {
        writeOutput("Error has message key");
    }
}
The real question is why have this function instead of just using
structKeyExists()
d
That's what we use. Maybe at some point exceptions weren't struct-like enough?
f
yeah, but it appears to have been added in CF2016, exceptions have been structs since CF6 at least
well I guess exceptions are not technically structs is probably the reason
d
Acts-as-if...
๐Ÿ’ฏ 1
b
Weird, that was my first idea-- why would you need this?
On an interesting related note, Lucee and Adobe wrap up exceptions differenlty
Lucee puts native exceptions (coming from somewhere other than cfthrow, or the CF runtime) in a wrapper class that delegates to them and gives them their stucty-ness. Adobe passes them around naked (which has some very nice benefits, especially when dealing with a java library that expects you to pass an exception object)
I can't see Adobe's code, but they appear to just have special handling when dereferencing an exception to treat it as a struct.
BoxLang followed Adobe's lead there as I prefer just having the raw Java exceptions without any wrapper. Our dynamicObject class recognizes when a
Throwable
is being dereferenced, and has special handling for the known keys.
d
Just curious, does BL follow the recent Adobe behavior of showing multiple layers of internal SQL stack frames when dumping SQL exceptions? This is new-ish in ACF, and not appreciated, but according to Mr Takata, a consequence of some other desired behavior, I think.
b
you mean when there is more than one SQL exception (since SQL just keeps executing unless exact abort is on)
And adobe nests the exceptions together?
It's not THAT recent. Here's my Lucee ticket from 2 years ago for it https://luceeserver.atlassian.net/browse/LDEV-4140
and here's an older Lucee one about it from 4 years ago ๐Ÿ˜• https://luceeserver.atlassian.net/browse/LDEV-3127
Regarding BoxLang, I actually don't know because I haven't been working on the JDBC portions, but I can tell you we 100% need to be doing that, lol
@elpete @mborn or @lmajano may know off the top of their head what we've done with JDBC error handling
But perhaps I'm misunderstanding what you're describing since you say it's "not appreciated", lol
because the behavior I'm thinking of is 100% appreciated
What I'm think of is a SQL query like this
Copy code
<cfquery datasource="MyDSN" name="foo">
    SELECT 1;
    RAISERROR (15600, -1, -1, 'Boom1');
    RAISERROR (15600, -1, -1, 'Boom2');
    RAISERROR (15600, -1, -1, 'Boom3');
</cfquery>
which gives you an exception like this (example taken from my Lucee ticket)
Where all the juicy error details of the separate exceptions are nested into the cause of the exception that gets thrown since you can only throw one exception at a time, even if the JDBC statement returned 15 exceptions!)
m
@bdw429s without testing it, I'd bet a fiver exceptions "raised" from a SQL query will indeed throw. However, I don't actually know, as I haven't tried this with multiple statements in a single query. I'll add a test for this.
๐Ÿ‘ 1
With that said, that really doesn't sound (to me) like what Dave asked:
... the recent Adobe behavior of showing multiple layers of internal SQL stack frames when dumping SQL exceptions?
b
Cool, I assume JDBC is giving back some list of exceptions or something, but I'm not famliar with the result object
Perhaps not-- I mean, I can't imagine what else he'd be referring to since it sounds like exactly what I'm thinking of, but that's why I included the example to be clear
m
> Cool, I assume JDBC is giving back some list of exceptions or something, but I'm not famliar with the result object No, currently we're not using any JDBC batching API. This means 1. each statement is executed as a standalone
statement.execute(...)
call 2. each statement as the potential to throw an exception and prevent any further iteration over statements.
Multi-statement especially is something we can improve on, but I would like to wait until we have a decent SQL parser we can use to split the statements without accidentally splitting statements where there are none. e.g.
Copy code
INSERT INTO foo(id, description) VALUES (123, 'a description; savvy?' );
โ˜๏ธ our current implementation blows up on the semicolon in the description value.
d
Sorry to go dark there, I'm mostly offline now. It's not the multiple exceptions you showed, it's see multiple stack layers inside the SQL implementation. I don't see the original thread where I asked about this and @Mark Takata (Adobe) said it was intentional. I'm on the free Slack plan, so it probably scrolled out of my universe. Maybe someone with that PowerUp can find it. If not I'll try to gin up an example when I get a chance.
b
Hmm, I'm not following what you mean by the words "multiple stack layers". That just makes no sense to me, lol
I guess I'd need to see an example of what you're referring to
This entire Slack team is on the free plan, so no one, not even the admins, can access the history
c
The complete Slack history is backed up at https://cfml.linen.dev/
๐Ÿ‘ 2
d
I tried to find that thread in linen, didn't so far, search tools are pretty bare bones. Will try again later, and/or try to repro a simple case.
Here's the first of these exceptions I found. Unfortunately it's not very isolatable, or reproducible outside our environment, but it's typical of the crash logging behavior we sometimes see in CF2021.
Copy code
java.sql.SQLNonTransientConnectionException: [Macromedia][SQLServer JDBC Driver]A problem occurred when attempting to contact the server (Server returned: Connection reset). Please ensure that the server parameters passed to the driver are correct and that the server is running. Also ensure that the maximum number of connections have not been exceeded for this server.
at macromedia.jdbc.sqlserver.base.BaseExceptions.b(|SQLServer|6.0.0.1282|:1048)
at macromedia.jdbc.sqlserver.base.BaseExceptions.a(|SQLServer|6.0.0.1282|:980)
at macromedia.jdbc.sqlserver.base.BaseExceptions.b(|SQLServer|6.0.0.1282|:1132)
at macromedia.jdbc.sqlserver.base.BaseExceptions.a(|SQLServer|6.0.0.1282|:840)
at macromedia.jdbc.sqlserver.base.BaseExceptions.b(|SQLServer|6.0.0.1282|:727)
at macromedia.jdbc.sqlserver.base.BaseConnection.a(|SQLServer|6.0.0.1282|:1772)
at macromedia.jdbc.sqlserver.tds.g.b(|SQLServer|6.0.0.1282|:155)
at macromedia.jdbc.sqlserver.tds.s.a(|SQLServer|6.0.0.1282|:4600)
at macromedia.jdbc.sqlserver.SQLServerImplStatement.cb(|SQLServer|6.0.0.1282|:1376)
at macromedia.jdbc.sqlserver.base.gr.nT(|SQLServer|6.0.0.1282|:2505)
at macromedia.jdbc.sqlserver.base.gr.nM(|SQLServer|6.0.0.1282|:1358)
at macromedia.jdbc.sqlserver.base.gr.$fr$execute(|SQLServer|6.0.0.1282|:4478)
at macromedia.jdbc.sqlserver.base.gr.execute(|SQLServer|6.0.0.1282|)
at coldfusion.server.j2ee.sql.JRunStatement.execute(JRunStatement.java:359)
at coldfusion.sql.Executive.executeQuery(Executive.java:1613)
at coldfusion.sql.Executive.executeQuery(Executive.java:1355)
at coldfusion.sql.Executive.executeQuery(Executive.java:1285)
at coldfusion.sql.SqlImpl.execute(SqlImpl.java:425)
at coldfusion.tagext.sql.QueryTag.executeQuery(QueryTag.java:1247)
at coldfusion.tagext.sql.QueryTag.startQueryExecution(QueryTag.java:876)
at coldfusion.tagext.sql.QueryTag.doEndTag(QueryTag.java:821)
at cfSOME_CF_PAGE2ecfc814878529$funcSOME_METHOD.runFunction(SOME_CFC_PATH.cfc:57)
Note all the exception layers that appear to be inside the SQL Server driver. macromedia.jdbc.sqlserver.base.BaseExceptions.a macromedia.jdbc.sqlserver.base.BaseExceptions.b macromedia.jdbc.sqlserver.tds.g.a macromedia.jdbc.sqlserver.tds.g.b etc The first CF call is 20-something layers down in the exception. The outer layers before that aren't helpful to CF devs, and I think this behavior is relatively new. That's what I think @Mark Takata (Adobe) said was new-ish, and is somewhat intentional, because it came along with capturing some other more valuable info.
m
Yes, we started exposing exception stacks in slightly different ways in... I wanna say 2018? Maybe 2021... essentially to give deeper access for testing. Off the top of my head I don't have a good specific reason why it was done, but I believe it was because some of the newer features would have been more difficult to debug had we not done it this way. Personally it is... annoying lol. It makes it so I have to do a bit more delving when I dump stuff, but I know it is for the greater good. Maybe @nimitsharma can comment here on why we did this specifically. And obviously we're always looking for feedback on how to improve things like this, so I'm glad you posted this Dave.
๐Ÿ‘ 1
b
I'll be honest, I don't see anything wrong with that ๐Ÿ™‚ You're using a JVM language on the JVM that utilizing Java libraries. All exceptions go back to a Java stack trace, and whether or not those details are helpful to you, they are still important to the engineers. Even as a CF dev, I look at the top part of stack traces all the time (The java calls between my last line of CF code and the actual exception) to gain insight on what exactly went wrong. Now, it wouldn't look so greek if they hadn't obfuscated their old macromedia JDBC wrappers, which rewrites all the method names a single letter alphabet chars, etc. And of course, the stack trace is less helpful to you when the library in question is closed source. If you just want the CF bits in your stack, that's what CF's tag context is for-- it's just the rows of the stack that map to a CF file, with the file name translated back to what it was on disk. If I were Adobe, I wouldn't change anything (other than maybe stop obfuscating their JDBC library).
d
I get what you're saying Brad. FWIW TagContext shows the same thing:
b
Ahh, well that's an entirely different thing, lol
It's perfectly normal for them to be in the Java stack, but they don't belong in the tag context
Tag context should only map to CF lines of code
The core question you asked however doesn't really even apply to BoxLang. No one but Adobe obviously uses their proprietary Macromedia JDBC wrappers, so the manner in which those wrappers handle exceptions are moot on Lucee or Boxlang
d
Agree, seeing all that in TagContext what I think is new. The only reason I sent the text version was that the full TagContext pic would have been 3 feet tall ;) And I don't think the intent according to @Mark Takata (Adobe) was to show that per se, it was an (unavoidable?) side effect of some info they DID want to show. In any case, if TagContext is clean on BoxLang I'm happy ๐Ÿ™‚
b
Yeah, I don't buy the "unavoidable part", lol
CF has basically no control over the stack trace
but it has 100% control over the tag context
It's not something Java touches, it's a complete creation by the CF engine
Seems more likely they added it on purpose because it was convenient for some debugging at the time and didn't remove it.
d
I gather it doesn't look like that on BL?
โœ… 1
r
i skimmed this - but is the net result that we dont 100% know why this is needed yet?
d
@raymondcamden Which thread are you replying to, exceptionKeyExists(), or SQL exception reporting?
r
exceptionKeyExists
d
Right, we think it may be a historical anachronism that's now covered by structKeyExists().
r
gotcha. my immediate concern for stuff like this is... lets get it off Slack, officially noted and deprecated (if it makes sense to), and if not, it obviously needs more docs. in other words, @Mark Takata (Adobe) - make sure we note this down ๐Ÿ™‚
d
Well presumably exceptionKeyExists() does work. They're not going to remove every now-unnecessary function there is I bet.
r
well, that's the rub then - right? did we confirm it's needed over structKeyExists?
d
We/I currently think it doesn't do anything structKeyExists() doesn't do, at least if the struct is an exception. I haven't tried every possible permutation of everything, and don't plan to. I also plan to forget that that this function exists ๐Ÿ™‚
๐Ÿ˜† 2
r
heh, well, thats why i want to firm this up.