db_multirow_helper (private)

 db_multirow_helper

Defined in packages/acs-tcl/tcl/01-database-procs.tcl

Helper function for db_multirow, performing the actual DB queries.

Partial Call Graph (max 5 caller/called nodes):
%3 db_multirow db_multirow (public) db_multirow_helper db_multirow_helper db_multirow->db_multirow_helper

Testcases:
No testcase defined.
Source code:
    uplevel 1 {
        if { !$append_p || ![info exists counter]} {
            set counter 0
        }

        set local_counter -1
        #
        # Make sure 'next_row' dict doesn't exist.
        #
        # The variables 'this_row' and 'next_row' are used to always
        # execute the code block one result set row behind, so that we
        # have the opportunity to peek ahead, which allows us to do
        # group by's inside the multirow generation.
        #
        # Also make the 'next_row' dict available as a magic __db_multirow__next_row variable
        #
        upvar 1 __db_multirow__next_row next_row
        unset -nocomplain next_row

        #
        # Execute the query in one sweep, similar to 'db_foreach'.
        #
        upvar 1 __db_multirow__local_columns local_columns
        set __selections [uplevel 1 [list db_list_of_lists -dbn $dbn  -subst $subst  -columns_var __db_multirow__local_columns  $full_statement_name $sql]]

        lappend local_columns {*}$extend

        if { !$append_p || ![info exists columns] } {
            # store the list of columns in the var_name:columns variable
            set columns $local_columns
        } else {
            # Check that the columns match, if not throw an error
            if { [join [lsort -ascii $local_columns]] ne [join [lsort -ascii $columns]] } {
                error "Appending to a multirow with differing columns.
    Original columns     : [join [lsort -ascii $columns] ""].
    Columns in this query: [join [lsort -ascii $local_columns] ""]" "" "ACS_MULTIROW_APPEND_COLUMNS_MISMATCH"
            }
        }

        if {[llength $__selections] == 0} {
            return
        }

        set more_rows_p 1
        while { 1 } {
            incr local_counter

            if { $more_rows_p } {
                set more_rows_p [expr {$local_counter < [llength $__selections]}]
                set selection [lindex $__selections $local_counter]
            } else {
                break
            }
            #ns_log notice "$local_counter: $selection"

            #
            # Setup the 'columns' part, now that we know the columns
            # in the result set in the first iteration (when
            # $local_counter == 0).
            #
            if { $local_counter == 0 } {

                # In case the '-unclobber' switch is specified, save
                # variables which we might clobber.
                #
                if { $unclobber_p && $code_block ne "" } {
                    foreach col $columns {
                        upvar 1 $col column_value __saved_$col column_save

                        if { [info exists column_value] } {
                            if { [array exists column_value] } {
                                array set column_save [array get column_value]
                            } else {
                                set column_save $column_value
                            }

                            # Clear the variable
                            unset column_value
                        }
                    }
                }
            }

            if { $code_block eq "" } {
                #
                # There is no code block - pull values directly into
                # the var_name array.
                #
                # The extra loop after the last row is only for when
                # there's a code block.
                #
                if { !$more_rows_p } {
                    break
                }

                incr counter
                upvar $level_up "$var_name:$counter" array_val
                set array_val(rownum) $counter
                array set array_val [join [lmap __column $local_columns __value $selection {
                    list $__column $__value
                }]]
            } else {
                #
                # There is a code block to execute.
                # Copy next_row to this_row, if it exists
                #
                unset -nocomplain this_row
                if {[info exists next_row]} {
                    set this_row $next_row
                }

                # Pull values from the query into next_row
                unset -nocomplain next_row
                if { $more_rows_p } {
                    set next_row $selection
                }

                # Process the row
                if { [info exists this_row] } {
                    # Pull values from this_row into local variables
                    foreach name $local_columns __value $this_row {
                        upvar 1 $name column_value
                        set column_value $__value
                        # ns_log notice "... [list set $name $__value]"
                    }

                    # Initialize the "extend" columns to the empty string
                    foreach column_name $extend {
                        upvar 1 $column_name column_value
                        set column_value ""
                    }

                    # Execute the code block
                    set errno [catch { uplevel 1 $code_block } error]
                    #ns_log notice ".... code block returns errno $errno"

                    # Handle or propagate the error. Can't use the usual
                    # "return -code $errno..." trick due to the db_with_handle
                    # wrapped around this loop, so propagate it explicitly.
                    #
                    switch -- $errno {
                        0 {
                            # TCL_OK
                        }
                        1 {
                            # TCL_ERROR
                            error $error $::errorInfo $::errorCode
                        }
                        2 {
                            # TCL_RETURN
                            error "Cannot return from inside a db_multirow loop"
                        }
                        3 {
                            # TCL_BREAK
                            #### CHECK? #ns_db flush $db
                            break
                        }
                        4 {
                            # TCL_CONTINUE
                            continue
                        }
                        default {
                            error "Unknown return code: $errno"
                        }
                    }

                    # Pull the local variables back out and into the array.
                    incr counter
                    upvar $level_up "$var_name:$counter" array_val
                    set array_val(rownum) $counter
                    foreach column_name $columns {
                        upvar 1 $column_name column_value
                        set array_val($column_name$column_value
                    }
                }
            }
        }

        # Restore values of columns which we've saved
        if { $unclobber_p && $code_block ne "" && $local_counter > 0 } {
            foreach col $columns {
                upvar 1 $col column_value __saved_$col column_save

                # Unset it first, so the road's paved to restoring
                unset -nocomplain column_value

                # Restore it
                if { [info exists column_save] } {
                    if { [array exists column_save] } {
                        array set column_value [array get column_save]
                    } else {
                        set column_value $column_save
                    }

                    # And then remove the saved col
                    unset column_save
                }
            }
        }
        # Unset the next_row variable, just in case
        unset -nocomplain next_row
    }
XQL Not present:
Generic, PostgreSQL, Oracle
[ hide source ] | [ make this the default ]
Show another procedure: