template::multirow (public)

 template::multirow [ -ulevel ulevel ] [ -local ] [ -unclobber ] \
    command name [ args... ]

Defined in packages/acs-templating/tcl/query-procs.tcl

Create/Manipulate a multirow datasource (for use with <multiple> tags)

template::multirow create datasourcename column [column ...]
creates a multirow datasource of datasourcename
template::multirow extend datasourcename column [column ...]
extend adds a column to an existing multirow
template::multirow append datasourcename value [value ...]
appends the row to an existing multirow.
template::multirow pop datasourcename
pops a row off an existing multirow, returning a list of the rows keys gand values
template::multirow size datasourcename
returns the rowcount
template::multirow columns datasourcename
returns the columns in the datasource
template::multirow get datasourcename rownum [column]
returns the row of data (or the particular row/column if column is provided)
template::multirow set datasourcename rownum column value
set an element value
template::multirow foreach datasource code
evaluate code block for each row (like db_foreach)
template::multirow upvar datasource [new_name]
upvar the multirow, aliasing to new_name if provided
template::multirow unset datasource
unset multirow
template::multirow sort datasource -lsort-switch col1 col2
Sort the multirow by the column(s) specified. The value sorted by will be the values of the columns specified, separated by the space character. Any switches specified before the columns will be passed directly to the lsort command.
template::multirow exists datasource
Return 1 if the multirow datasource exists, 0 if it doesn't.

Switches:
-ulevel (optional, defaults to "1")
Used in conjunction with the "local" parameter to specify how many levels up the multirow variable resides.
-local (optional, boolean)
If set, the multirow will be looked for in the scope the number of levels up given by ulevel (normally the caller's scope), instead of the [template::adp_level] scope, which is the default.
-unclobber (optional, boolean)
This only applies to the 'foreach' command. If set, will cause the proc to not overwrite local variables. Actually, what happens is that the local variables will be overwritten, so you can access them within the code block. However, if you specify -unclobber, we will revert them to their original state after execution of this proc.
Parameters:
command (required)
Multirow datasource operation: create, extend, append, pop, size, get, set, foreach, upvar
name (required)
Name of the multirow datasource
See Also:

Partial Call Graph (max 5 caller/called nodes):
%3 test_db__transaction_bug_3440 db__transaction_bug_3440 (test acs-tcl) template::multirow template::multirow test_db__transaction_bug_3440->template::multirow test_templates_and_scripts templates_and_scripts (test acs-templating) test_templates_and_scripts->template::multirow test_util_user_messages util_user_messages (test acs-tcl) test_util_user_messages->template::multirow template::adp_level template::adp_level (public) template::multirow->template::adp_level template::util::is_nil template::util::is_nil (public) template::multirow->template::util::is_nil acs_user::demote_user acs_user::demote_user (public) acs_user::demote_user->template::multirow ad_context_bar_multirow ad_context_bar_multirow (public) ad_context_bar_multirow->template::multirow ad_dimensional ad_dimensional (public) ad_dimensional->template::multirow ad_page_contract ad_page_contract (public) ad_page_contract->template::multirow apm_build_repository apm_build_repository (private) apm_build_repository->template::multirow

Testcases:
db__transaction_bug_3440, util_user_messages, templates_and_scripts
Source code:
    if { $local_p } {
        set multirow_level_up $ulevel
    } else {
        set multirow_level_up \#[adp_level]
        if { $multirow_level_up eq "\#" } {
            # in event adp_level not defined we are calling either at install so up 1.
            set multirow_level_up 1
        }
    }

    switch -exact $command {

        create {
            upvar $multirow_level_up $name:rowcount rowcount $name:columns columns
            set rowcount 0
            set columns $args
        }

        unset {
            upvar $multirow_level_up $name:rowcount rowcount $name:columns columns
            for { set i 1 } { $i <= $rowcount } { incr i } {
                upvar $multirow_level_up $name:$i row
                unset row
            }
            unset rowcount columns
        }

        extend {
            upvar $multirow_level_up $name:columns columns
            lappend columns {*}$args
        }

        pop {
            upvar $multirow_level_up $name:rowcount rowcount $name:columns columns
            set r_list [list]
            if {$rowcount > 0} {
                upvar $multirow_level_up $name:$rowcount row
                foreach key $columns {
                    if {[info exists row($key)]} {
                        set value $row($key)
                        lappend r_list $key $value
                    }
                }
                unset -nocomplain row
            }
            incr rowcount -1
            return $r_list
        }

        append {
            upvar $multirow_level_up $name:rowcount rowcount $name:columns columns
            incr rowcount
            upvar $multirow_level_up $name:$rowcount row

            #
            # Note: missing columns are silently empty
            #
            foreach key $columns value $args {
                set row($key$value
            }
            set row(rownum) $rowcount
        }

        size {
            upvar $multirow_level_up $name:rowcount rowcount
            if { [template::util::is_nil rowcount] } {
                return 0
            }
            return $rowcount
        }

        columns {
            upvar $multirow_level_up $name:columns columns
            if { [template::util::is_nil columns] } {
                return {}
            }
            return $columns
        }

        get {

            lassign $args index column
            # Set an array reference if no column is specified
            if {$column eq ""} {

                # If -local was specified, the upvar is done with a relative stack frame
                # index, and we must take into account the fact that the uplevel moves up
                # the frame one level.  If -local was not specified, the an absolute stack
                # frame is passed to upvar, which of course needs no adjustment.

                if { $local_p } {
                    uplevel "upvar [expr { $multirow_level_up - 1 }] $name:$index $name"
                } else {
                    uplevel "upvar $multirow_level_up $name:$index $name"
                }

            } else {
                # If a column is specified, just return the value for it
                upvar $multirow_level_up $name:$index arr
                if {[info exists arr($column)]} {
                    return $arr($column)
                } else {
                    ns_log warning "can't obtain template variable form ${name}:${index}$column"
                    return ""
                }
            }
        }

        set {

            lassign $args index column value

            if {$column eq {}} {
                error "No column specified to template::multirow set"
            }

            # Mutate the value
            upvar $multirow_level_up $name:$index arr
            set arr($column$value
            return $arr($column)

        }

        upvar {
            # upvar from wherever the multirow is to the current stack frame
            if { [llength $args] > 0 } {
                set new_name [lindex $args 0]
            } else {
                set new_name $name
            }
            uplevel "
                upvar $multirow_level_up $name:rowcount $new_name:rowcount $name:columns $new_name:columns
                for { set i 1 } { \$i <= \${$new_name:rowcount} } { incr i } {
                    upvar $multirow_level_up $name:\$i $new_name:\$i
                }
            "
        }

        foreach {
            set code_block [lindex $args 0]
            upvar $multirow_level_up $name:rowcount rowcount $name:columns columns

            if {![info exists rowcount] || ![info exists columns]} {
                return
            }

            # Save values of columns which we might clobber
            if { $unclobber_p } {
                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
                    }
                }
            }

            for { set i 1 } { $i <= $rowcount } { incr i } {
                # Pull values into variables (and into the array - aks),
                # evaluate the code block, and pull values back out to
                # the array.

                upvar $multirow_level_up $name:$i row

                foreach column_name $columns {
                    upvar 1 $column_name column_value
                    if { [info exists row($column_name)] } {
                        set column_value $row($column_name)
                    } else {
                        set column_value ""
                    }
                }

                # Also set the special var __rownum
                upvar 1 __rownum __rownum
                set __rownum $row(rownum)

                set errno [catch { uplevel 1 $code_block } error]

                switch -- $errno {
                    0 {
                        # TCL_OK
                    }
                    1 {
                        # TCL_ERROR
                        error $error $::errorInfo $::errorCode
                    }
                    2 {
                        # TCL_RETURN
                        error "Cannot return from inside template::multirow foreach loop"
                    }
                    3 {
                        # TCL_BREAK
                        break
                    }
                    4 {
                        # TCL_CONTINUE - just ignore and continue looping.
                    }
                    default {
                        error "template::multirow foreach: Unknown return code: $errno"
                    }
                }

                # Pull the variables into the array.
                foreach column_name $columns {
                    upvar 1 $column_name column_value
                    if { [info exists column_value] } {
                        set row($column_name$column_value
                    }
                }
            }

            if { $unclobber_p } {
                foreach col $columns {
                    upvar 1 $col column_value __saved_$col column_save

                    # Unset it first, so the road's paved to restoring
                    if { [info exists column_value] } {
                        unset 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
                    }
                }
            }
        }

        sort {
            # args is a list of names of columns to sort by
            # construct a list which we can lsort

            upvar $multirow_level_up $name:rowcount rowcount

            if { ![info exists rowcount] } {
                error "Multirow $name does not exist"
            }

            # Construct list of (rownum,columns appended with a space)

            # Allow for -ascii, -dictionary, -integer, -real, -command <command>, -increasing, -decreasing, unique switches

            set sort_args {}

            set len [llength $args]
            for { set i 0 } { $i < $len } { incr i } {
                if { [string index [lindex $args $i] 0] eq "-" } {
                    switch -exact [string range [lindex $args $i] 1 end] {
                        command {
                            # command takes an additional argument
                            lappend sort_args [lindex $args $i]
                            incr i
                            lappend sort_args [lindex $args $i]
                        }
                        default {
                            lappend sort_args [lindex $args $i]
                        }
                    }
                } else {
                    break
                }
            }

            set sort_cols [lrange $args $i end]

            set sort_list [list]

            for { set i 1 } { $i <= $rowcount } { incr i } {
                upvar $multirow_level_up $name:$i row

                # Make a copy of the row
                array set copy:$i [array get row]

                # Construct the list
                set sortby {}
                foreach col $sort_cols {
                    append sortby $row($col) " "
                }

                lappend sort_list [list $i $sortby]
            }

            set sort_list [lsort {*}$sort_args -index 1 $sort_list]


            # Now we have a list with two elms, (rownum, sort-by-value), sorted by sort-by-value
            # Rearrange multirow to match the sort order

            set i 0
            foreach elm $sort_list {
                incr i
                upvar $multirow_level_up $name:$i row

                # which rownum in the original list should fill this space in the sorted multirow?
                set org_rownum [lindex $elm 0]

                # Replace the row in the multirow with the row from the copy with the rownum according to the sort
                array set row [array get copy:$org_rownum]

                # Replace the 'rownum' column
                set row(rownum) $i
            }

            # Multirow length may have changed if you said -unique
            set rowcount [llength $sort_list]
        }

        exists {
           upvar $multirow_level_up $name:rowcount rowcount
           return [info exists rowcount]
        }

        default {
            error "Unknown command $command in template::multirow.
            Must be create, extend, append, backup, get, set, size, upvar, sort, exists or foreach."
        }
    }
XQL Not present:
Generic, PostgreSQL, Oracle
[ hide source ] | [ make this the default ]
Show another procedure: