Forum OpenACS Development: Schedule proc

Collapse
Posted by Carlos Valencia Lopez on
Hi,

I've got the following error with a scheduled proc:

[-sched-] Error: Tcl exception:
expected integer but got ""
while executing
"upvar $level_up "$var_name:rowcount" counter"
(procedure "db_multirow" line 37)
invoked from within
"db_multirow get_recent_rating_ids get_recent_rating_ids {select recent_ratings_id from recent_ratings} {
db_exec_plsql delete_acs_object {select a..."
(procedure "rating::rate::free" line 2)
invoked from within
"rating::rate::free"
("eval" body line 1)
invoked from withinyy
"eval [concat [list $proc] $args]"
(procedure "ad_run_scheduled_proc" line 46)
invoked from within
"ad_run_scheduled_proc {f f 60 rating::rate::free {} 1229705918 0 f}"

The proc is the following:
ad_proc -public rating::rate::free {} {
db_multirow get_recent_rating_ids get_recent_rating_ids {select * from recent_ratings} {
db_exec_plsql delete_acs_object {select acs_object__delete (:recent_ratings_id)}
}
}

Thanks in advance for any help you can give me.

Carlos

Collapse
2: Re: Schedule proc (response to 1)
Posted by Iuri Sampaio on
Reading the error.log it seems the proc was supposed to return an integer value but it returned null while executed the multirow

Btw, this proc rating::rate::free isn't listed on openacs/api-doc website. So i couldn't look at its source to point out where the error can be.

My advice is to take a look at the select queries. Try to test them separately using psql-shell or pgadmin.
That's one way to debug errors.

Collapse
3: Re: Schedule proc (response to 1)
Posted by Brian Fenton on
Hi Carlos,

What happens when you run the proc in the developer shell?

Are you using a xql file? You seem to have a different query appearing in the error than the one you give in the proc definition:

select recent_ratings_id from recent_ratings
vs
select * from recent_ratings

(As a matter of style, I prefer not to use "select *" in queries, but instead to always name the columns I want. You might get a few surprises with "select *")

Brian

Collapse
4: Re: Schedule proc (response to 1)
Posted by Derick Leony on
AFAIK, multirows created at the ADP level, since this is a scheduled proc there is no such level.

In this case, since your proc doesn't depend on multirow functionalities, you should use db_foreach instead of db_multirow.

Derick

Collapse
5: Re: Schedule proc (response to 4)
Posted by Dave Bauer on
I just ran into this too. I am surprised db_multirow doesn't work in a schedule proc, but the logic is clear. The ADP level is not prepared so it just doesn't work.

In generaly I don't advise using db_foreach, especially if you need to call any procedure that does a database query within the db_foreach code block, there doesn't seem to be a better solution.

Collapse
6: Re: Schedule proc (response to 5)
Posted by Ryan Gallimore on
To get around the db_foreach nesting problem, build a list with db_foreach first and then loop through that.
Collapse
7: Re: Schedule proc (response to 5)
Posted by Brian Fenton on
Michael Hinds wrote a version of db_foreach that supports nesting.

ad_proc -public db_foreach_no_handle {{ -dbn "" } statement_name sql args } {

  Like db_foreach, but nest as much as you like
  MJH

} {

    # MJH - ripped out of db_list_of_lists
    ad_arg_parser { bind column_array column_set args } $args

    # Query Dispatcher (OpenACS - SDW)
    set full_statement_name [db_qd_get_fullname $statement_name]

    # Do some syntax checking.
    set arglength [llength $args]
    if { $arglength == 1 } {
        # Have only a code block.
        set code_block [lindex $args 0]
    } elseif { $arglength == 3 } {
        # Should have code block + if_no_rows + code block.
        if { ![string equal [lindex $args 1] "if_no_rows"] && ![string equal [lindex $args 1] "else"] } {
            return -code error "Expected if_no_rows as second-to-last argument"
        }
        set code_block [lindex $args 0]
        set if_no_rows_code_block [lindex $args 2]
    } else {
        return -code error "Expected 1 or 3 arguments after switches"
    }

    if { [info exists column_array] } {
        upvar 1 $column_array array_val
    }

    # Can't use db_foreach here, since we need to use the ns_set directly.
    db_with_handle -dbn $dbn db {
        set selection [db_exec select $db $full_statement_name $sql]

        set result [list]

        while { [db_getrow $db $selection] } {
            set this_result [list]
            for { set i 0 } { $i < [ns_set size $selection] } { incr i } {
                lappend this_result [ns_set value $selection $i]
            }
            lappend result $this_result
        }
    }

    set column_names [ad_ns_set_keys $selection]
    set num_columns [llength $column_names]

    for {set i 0} {$i < $num_columns} {incr i} {
        upvar 1 [lindex $column_names $i] column_value$i
    }

    foreach row $result {
        if { [info exists array_val] } {
            unset array_val
        }
        for {set i 0} {$i < $num_columns} {incr i} {
            if { [info exists column_array] } {
                set array_val([lindex $column_names $i]) [lindex $row $i]
            } else {
                set column_value$i [lindex $row $i]
            }
        }
        set errno [catch { uplevel 1 $code_block } error]
        switch $errno {
            0 {
                # TCL_OK
            }
            1 {
                # TCL_ERROR
                global errorInfo errorCode
                error $error $errorInfo $errorCode
            }
            2 {
                # TCL_RETURN
                error "Cannot return from inside a db_foreach_no_handle loop (yet)"
            }
            3 {
                # TCL_BREAK
                #cjke: no db anymore# ns_db flush $db
                break
            }
            4 {
                # TCL_CONTINUE - just ignore and continue looping.
            }
            default {
                error "Unknown return code: $errno"
            }
        }
    }

} ;# end db_foreach_no_handle