2

This is a strange one. I have a simple toggle update statement that when ran in TOAD works just fine (the test record's ID is 10000244999201)...

update myTable set
hasbeenread = case when (hasbeenread = 0) then 1 else 0 end
where id = 10000244999201;

This update statement is also in a package/procedure that can be called from ColdFusion and when it's called this way it does not work. The procedure runs and I get success back but the update doesn't toggle the hasbeenread column.

procedure toggleRead(p_webSession number, p_data lib.jsonclob, result out lib.jsonclob) is

    ws websession%rowtype := lib.getWebSession(p_webSession);
    pin lib.paramArray := lib.jsonToArray(p_data);

begin
    --(1) Do perm checks here
    --(2) Do data validation here
    --(3) Code your process here
    --(4) Send back a proper JSON/XML response.

    delete from debuglog where title = 'gtest';
    insert into debuglog ( username, seqno, title, cfd01, insertdate )
    values ( 'GADMIN', 555, 'gtest', pin('id'), sysdate );
    commit;

    update myTable set
        hasbeenread = case when (hasbeenread = 0) then 1 else 0 end
    where id = pin('id');

    result := lib.response(true,null,null);

    exception
        when others then
            err.logAndEmailError( ws.fullName, gbody_version, 'toggleRead - p_data: '||p_data||', SQLERRM: '||sqlerrm );

end toggleRead;

I have verified the pin('id') value by looking at the debug log that happens right before the update, it is the correct id. I have even replaced pin('id') and hardcoded 10000244999201 into the where clause, that still didn't work. I tried putting a commit; after the update (which I shouldn't have to do because ColdFusion will commit when it comes back since I'm not using a cftransaction tag around it), that still didn't work. But when I remove the CASE statement and hardocde it to hasbeenread = 0 or hasbeenread = 1 it then works. So the problems looks like it has to do with the CASE statement. But like I said, it works fine when I run that update in TOAD. What am I missing?

Thanks!

Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production

ColdFusion version: 11,0,0,289974

UPDATE: Here is the ColdFusion call...

<cfstoredproc procedure="lib.getJson" datasource="#session.sv.ds#" returncode="no">
    <cfprocparam type="in" cfsqltype="cf_sql_decimal" variable="webSession_in" value="#session.sv.csid#">
    <cfprocparam type="in" cfsqltype="cf_sql_clob" variable="data" value="#z.data#">
    <!---
    How to get back a clob
    Here they say to use CF_SQL_LONGVARCHAR
    http://stackoverflow.com/questions/11053539/getting-clob-data-from-coldfusion-8
    <cfprocparam type="out" cfsqltype="cf_sql_longvarchar" variable="result">
    But instead we use CF_SQL_CLOB but then do the ArrayToList part you see below.
    --->
    <cfprocparam type="out" cfsqltype="cf_sql_clob" variable="z.result">
</cfstoredproc>
<cfif notnull(z.result)>
    <cfset z.result = ArrayToList(z.result,"")>
</cfif>
<cfreturn z.result />

UPDATE: When I call the proc from TOAD it works, the update works and the column value toggles...

declare
    r clob;
begin
    c3.toggleread(146992,'{"ID":10000244999201}',r);
    dbms_output.put_line(r);
end;
/
gfrobenius
  • 3,987
  • 8
  • 34
  • 66
  • Can you please post the CF code that is failing? Is it using cfstoredproc? Or is it called within a cfquery? – Mark A Kruger Oct 23 '14 at 14:53
  • Does `decode(hasbeenread, 0, 1, 0)` work? Not saying `case` shouldn't, or that you should have to work around it, just curious. Also just a thought, is it feasible that it's being executed twice, which would toggle back to the original value? – Alex Poole Oct 23 '14 at 14:57
  • Just tried decode, no joy. – gfrobenius Oct 23 '14 at 14:59
  • @AlexPoole Good thought Alex - like if it was called via custom tag with no executionmode. Show the CF code please ;) Also, you say it works when you use TOAD - does that mean you are calling the procedure using TOAD, or are you still referring to the plain update statement. – Mark A Kruger Oct 23 '14 at 15:00
  • I posted the cfstoredproc call. When I run it in TOAD I'm just running the update statement. I'm not calling the proc. I'll grab the websession id and try calling the proc in TOAD now... – gfrobenius Oct 23 '14 at 15:02
  • `hasbeenread ` is `NUMBER` and is it `NULL`, for your case? – Maheswaran Ravisankar Oct 23 '14 at 15:09
  • @gfrobenius - one thought - double check in the CF Admin that you have enabled clob in your datasource settings. It is under "advanced settings" - something like "enable long text retrieval (clob)". Are you calling this stored proc from within a custom tag or a CFC? – Mark A Kruger Oct 23 '14 at 15:10
  • One other thought - have you tried using longvarchar? How big is your CLOB string? – Mark A Kruger Oct 23 '14 at 15:11
  • It is never null, clob is enabled. I just added an UPDATE to the OP. Calling the proc from within TOAD works. The update works and the column toggles. Still mystified. – gfrobenius Oct 23 '14 at 15:11
  • 2
    Can you temporarily remove the delete to check if you get two log records when called from CF? And one from Toad? – Alex Poole Oct 23 '14 at 15:22
  • Wow. I removed the delete and it is firing twice, I get two debuglog recs. We ran into this issue before with another process, we never figured it out. But I'm only clicking the link once. And the F12 Chrome network viewer shows only 1 post happening. Very strange. Have not clue as to why this thing is firing twice. – gfrobenius Oct 23 '14 at 15:40
  • Finally figured it out. Sorry for wasting everyone's time but thanks so much for helping me narrow it down. In case you are curious, IE, FireFox, Chrome all showed a single POST. Apache access log showed a single POST also. So then I knew it had to be our "tunnel". All DB calls go thru the same pkg/proc (lib.getJson). lib.getJson does some perm checks then calls the real pkg/proc you want, in this case c3.toggleRead. Well recently made some changes to the "tunnel" and there were two calls to the real proc left in place. So everything has been running twice for a few days now. Ugh. – gfrobenius Oct 23 '14 at 16:39

1 Answers1

2

One common way it can fire twice is the use of a custom tag. For example if you put your stored proc in a custom tag and called it like this:

<Cf_toggleuser z="#mydata#"/>

Custom tags have 2 "execution modes" - start and end. They are referenced as attributes of the "thistag" scope within the contents of the tag. The tag (by design) runs two times - a start and and end. This is so you can run them with content inbetween - commonly done for altering layout or display content as in:

<cf_layout>

...some content here

</cf_layout>

But it also means if you intend to ONLY run the contents of the tag one time you need to include a check and only run it for one of the modes as in:

<cfif thistag.executionmode IS 'Start'>
...run the procedure
</cfif>

This may not be your problem but it is one nuance that occurs that is easy to miss. In your case the results were an error in data.

NOTE: you can also pull out the final slash in your tag (or the end tag) to cause it to execute only once. To illustrate:

This call only executes one time:

<Cf_toggleuser z="#mydata#">

While this call executes twice:

<Cf_toggleuser z="#mydata#"/>
halfer
  • 19,824
  • 17
  • 99
  • 186
Mark A Kruger
  • 7,183
  • 20
  • 21
  • Understood. There are no custom tags in play here. That call is inside a cfc function. We've experienced this in the past. And I believe some users here could replicate it and some could not. One user here I think never had the code fire twice when using IE. Since we have discovered this is not a Oracle PL/SQL CASE UPDATE issue maybe I should close out this question and start a new question geared towards this "firing twice" issue. Or should we continue using this question? – gfrobenius Oct 23 '14 at 16:14