Index: openacs-4/packages/acs-content-repository/acs-content-repository.info
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-content-repository/acs-content-repository.info,v
diff -u -r1.2 -r1.3
--- openacs-4/packages/acs-content-repository/acs-content-repository.info 5 Apr 2001 18:23:38 -0000 1.2
+++ openacs-4/packages/acs-content-repository/acs-content-repository.info 27 Apr 2001 02:27:09 -0000 1.3
@@ -83,8 +83,15 @@
+
+
+
+
+
+
+
Index: openacs-4/packages/acs-content-repository/sql/postgresql/content-revision.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-content-repository/sql/postgresql/content-revision.sql,v
diff -u -r1.11 -r1.12
--- openacs-4/packages/acs-content-repository/sql/postgresql/content-revision.sql 18 Apr 2001 23:27:46 -0000 1.11
+++ openacs-4/packages/acs-content-repository/sql/postgresql/content-revision.sql 27 Apr 2001 02:27:09 -0000 1.12
@@ -64,10 +64,10 @@
create function content_revision__new(varchar,varchar,timestamp,varchar,text,integer) returns integer as '
declare
new__title alias for $1;
- new__description alias for $2;
- new__publish_date alias for $3;
- new__mime_type alias for $4;
- new__text alias for $5;
+ new__description alias for $2; -- default null
+ new__publish_date alias for $3; -- default now()
+ new__mime_type alias for $4; -- default ''text/plain''
+ new__text alias for $5; -- default '' ''
new__item_id alias for $6;
begin
return content_revision__new(new__title,
Index: openacs-4/packages/acs-content-repository/tcl/doc-procs-oracle.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-content-repository/tcl/doc-procs-oracle.xql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/acs-content-repository/tcl/doc-procs-oracle.xql 27 Apr 2001 02:27:09 -0000 1.1
@@ -0,0 +1,81 @@
+
+
+ oracle8.1.6
+
+
+
+
+ select doc.get_package_header(:package_name) from dual
+
+
+
+
+
+
+
+ select doc.get_proc_header(:proc_name, :package_name) from dual
+
+
+
+
+
+
+
+ select distinct
+ lower(name) as label,
+ lower(name) as value
+ from
+ user_source
+ where
+ type='PACKAGE'
+ and
+ line=1
+ order by label
+
+
+
+
+
+
+
+ select distinct
+ lower(text) as line_header
+ from
+ user_source
+ where
+ type='PACKAGE'
+ and
+ lower(name) = lower(:package_name)
+ and (
+ lower(text) like '%procedure%'
+ or
+ lower(text) like '%function%'
+ )
+ order by line_header"
+
+
+
+
+
+
+
+ select distinct
+ lower(text) as line_header
+ from
+ user_source
+ where
+ type='PACKAGE'
+ and
+ lower(name) = lower(:package_name)
+ and (
+ lower(text) like '%procedure%'
+ or
+ lower(text) like '%function%'
+ )
+ order by line_header" -eval {
+
+
+
+
+
+
Index: openacs-4/packages/acs-content-repository/tcl/doc-procs-postgresql.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-content-repository/tcl/doc-procs-postgresql.xql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/acs-content-repository/tcl/doc-procs-postgresql.xql 27 Apr 2001 02:27:09 -0000 1.1
@@ -0,0 +1,68 @@
+
+
+ postgresql7.1
+
+
+
+
+ select doc__get_package_header(:package_name) from dual
+
+
+
+
+
+
+
+ select doc__get_proc_header(:proc_name, :package_name) from dual
+
+
+
+
+
+
+
+ select distinct
+ substr(proname,1,position('__' in proname)-1) as label,
+ substr(proname,1,position('__' in proname)-1) as value
+ from
+ pg_proc
+ where
+ proname like '%\\\_\\\_%'
+ order by
+ label
+
+
+
+
+
+
+
+ select
+ proname as line_header
+ from
+ pg_proc
+ where
+ proname like lower(:package_name) || '\\\_\\\_%'
+ order by
+ line_header
+
+
+
+
+
+
+
+ select
+ proname as line_header
+ from
+ pg_proc
+ where
+ proname like lower(:package_name) || '\\\_\\\_%'
+ order by
+ line_header
+
+
+
+
+
+
Index: openacs-4/packages/acs-content-repository/tcl/doc-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-content-repository/tcl/doc-procs.tcl,v
diff -u -r1.1 -r1.2
--- openacs-4/packages/acs-content-repository/tcl/doc-procs.tcl 13 Mar 2001 22:59:26 -0000 1.1
+++ openacs-4/packages/acs-content-repository/tcl/doc-procs.tcl 27 Apr 2001 02:27:09 -0000 1.2
@@ -11,7 +11,7 @@
upvar $info_ref info
- template::query info_source onevalue "
+ template::query get_info info_source onevalue "
select doc.get_package_header(:package_name) from dual
"
@@ -44,16 +44,9 @@
upvar $doc_ref doc
upvar $code_ref code
- if { [template::util::is_nil db] } {
- set db [ns_db gethandle]
- set free_db 1
- } else {
- set free_db 0
- }
-
- template::query header onevalue "
+ template::query get_header header onevalue "
select doc.get_proc_header(:proc_name, :package_name) from dual
- " -db $db
+ "
# Get JavaDoc block, if any
if { [regexp {/\*\*(.*)\*/} $header match] } {
@@ -65,10 +58,6 @@
set doc ""
set code $header
}
-
- if { $free_db } {
- ns_db releasehandle $db
- }
}
# Parse the header block and prepare the datasources:
@@ -163,14 +152,7 @@
# { {label value} {label value} ... }
proc package_list { {db ""} } {
- if { [template::util::is_nil db] } {
- set db [ns_db gethandle]
- set free_db 1
- } else {
- set free_db 0
- }
-
- template::query result multilist "
+ template::query get_packages result multilist "
select distinct
lower(name) as label,
lower(name) as value
@@ -180,11 +162,7 @@
type='PACKAGE'
and
line=1
- order by label" -db $db
-
- if { $free_db } {
- ns_db releasehandle $db
- }
+ order by label"
return $result
}
@@ -193,14 +171,7 @@
# { value value ... }
proc func_list { package_name {db ""} } {
- if { [template::util::is_nil db] } {
- set db [ns_db gethandle]
- set free_db 1
- } else {
- set free_db 0
- }
-
- template::query result multilist "
+ template::query get_funcs result multilist "
select distinct
lower(text) as line_header
from
@@ -214,12 +185,8 @@
or
lower(text) like '%function%'
)
- order by line_header" -db $db
+ order by line_header"
- if { $free_db } {
- ns_db releasehandle $db
- }
-
set line_opts [list]
foreach line $result {
# Only get lines in form "procedure proc_name..." or "function func_name..."
@@ -237,20 +204,13 @@
# { value value ... }
proc func_multirow { package_name result_ref {db ""} } {
- if { [template::util::is_nil db] } {
- set db [ns_db gethandle]
- set free_db 1
- } else {
- set free_db 0
- }
-
upvar "${result_ref}:rowcount" result_rowcount
set result_rowcount 0
# Get each line that contains "procedure" or "function" in it
# Pretty risky... The like query should be improved to return
# less false matches
- template::query result multirow "
+ template::query get_functions result multirow "
select distinct
lower(text) as line_header
from
@@ -264,7 +224,7 @@
or
lower(text) like '%function%'
)
- order by line_header" -db $db -eval {
+ order by line_header" -eval {
# Only insert a row into the datasource if it looks like a procedure
# or function definition
@@ -279,9 +239,5 @@
set result_row(name) [string tolower $name]
}
}
-
- if { $free_db } {
- ns_db releasehandle $db
- }
}
}
Index: openacs-4/packages/acs-content-repository/tcl/filter-procs-oracle.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-content-repository/tcl/filter-procs-oracle.xql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/acs-content-repository/tcl/filter-procs-oracle.xql 27 Apr 2001 02:27:09 -0000 1.1
@@ -0,0 +1,60 @@
+
+
+ oracle8.1.6
+
+
+
+
+ select
+ 0 as tree_level, '' as name , 'Home' as title
+ from
+ dual
+ UNION
+ select
+ t.tree_level, i.name, content_item.get_title(t.context_id) as title
+ from (
+ select
+ context_id, level as tree_level
+ from
+ acs_objects
+ where
+ context_id <> content_item.get_root_folder
+ connect by
+ prior context_id = object_id
+ start with
+ object_id = :item_id
+ ) t, cr_items i
+ where
+ i.item_id = t.context_id
+ order by
+ tree_level
+
+
+
+
+
+
+
+ select
+ item_id, content_type
+ from
+ cr_items
+ where
+ item_id = content_item.get_id(:url, :content_root)
+
+
+
+
+
+
+
+ select
+ content_template.get_path(
+ content_item.get_template(:item_id, :context),:template_root) as template_url
+ from
+ dual
+
+
+
+
+
Index: openacs-4/packages/acs-content-repository/tcl/filter-procs-postgresql.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-content-repository/tcl/filter-procs-postgresql.xql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/acs-content-repository/tcl/filter-procs-postgresql.xql 27 Apr 2001 02:27:09 -0000 1.1
@@ -0,0 +1,61 @@
+
+
+ postgresql7.1
+
+
+
+
+ select
+ 0 as tree_level, '' as name , 'Home' as title
+ from
+ dual
+ UNION
+ select
+ t.tree_level, i.name, content_item.get_title(t.context_id) as title
+ from (
+ select
+ o2.context_id, tree_level(o2.tree_sortkey) as tree_level
+ from
+ (select * from acs_objects where object_id = :item_id) o1,
+ acs_objects o2
+ where
+ context_id <> content_item__get_root_folder()
+ and
+ o2.tree_sortkey <= o1.tree_sortkey
+ and
+ o1.tree_sortkey like (o2.tree_sortkey || '%')
+ ) t, cr_items i
+ where
+ i.item_id = t.context_id
+ order by
+ tree_level
+
+
+
+
+
+
+
+ select
+ item_id, content_type
+ from
+ cr_items
+ where
+ item_id = content_item__get_id(:url, :content_root)
+
+
+
+
+
+
+
+ select
+ content_template__get_path(
+ content_item__get_template(:item_id, :context),:template_root) as template_url
+ from
+ dual
+
+
+
+
+
Index: openacs-4/packages/acs-content-repository/tcl/filter-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-content-repository/tcl/filter-procs.tcl,v
diff -u -r1.1 -r1.2
--- openacs-4/packages/acs-content-repository/tcl/filter-procs.tcl 13 Mar 2001 22:59:26 -0000 1.1
+++ openacs-4/packages/acs-content-repository/tcl/filter-procs.tcl 27 Apr 2001 02:27:09 -0000 1.2
@@ -73,7 +73,7 @@
}
# Get the live revision
- template::query revision_id onevalue "
+ template::query get_revision revision_id onevalue "
select live_revision from cr_items where item_id = :item_id
" -cache "item_live_revision $item_id"
@@ -83,7 +83,7 @@
}
# Get the mime type, decide if we want the text
- template::query mime_type onevalue "
+ template::query get_mime_type mime_type onevalue "
select mime_type from cr_revisions
where revision_id = :revision_id
" -cache "revision_mime_type $revision_id" -persistent \
@@ -101,14 +101,14 @@
}
# Get the content type
- template::query content_type onevalue "
+ template::query get_content_type content_type onevalue "
select content_type from cr_items
where item_id = :item_id
" -cache "item_content_type $item_id" -persistent \
-timeout 3600
# Get the table name
- template::query table_name onevalue "
+ template::query get_table_name table_name onevalue "
select table_name from acs_object_types
where object_type = :content_type
" -cache "type_table_name $content_type" -persistent \
@@ -117,7 +117,7 @@
upvar content content
# Get (all) the content (note this is really dependent on file type)
- template::query content onerow "select
+ template::query get_content content onerow "select
x.*,
:item_id as item_id $text_sql,
:content_type as content_type
@@ -183,7 +183,7 @@
set url ""
# build the folder URL out as we iterate over the query
- template::query $varname multirow $query -uplevel -eval {
+ template::query get_url $varname multirow $query -uplevel -eval {
append url "$row(name)/"
set row(url) ${url}index.acs
}
@@ -211,7 +211,7 @@
item_id = content_item.get_id(:url, :content_root)"
# cache this query persistently for 1 hour
- template::query item_info onerow $query \
+ template::query get_item_info item_info onerow $query \
-cache "get_id_filter $url $content_root" \
-persistent -timeout 216000
@@ -228,7 +228,7 @@
set content_type $item_info(content_type)
# Make sure that a live revision exists
- template::query live_revision onevalue "
+ template::query get_live_revision live_revision onevalue "
select live_revision from cr_items where item_id = :item_id
" -cache "item_live_revision $item_id"
@@ -256,7 +256,7 @@
dual"
- template::query template_url onevalue $query
+ template::query get_template_url template_url onevalue $query
if { [string equal $template_url {}] } {
ns_log Notice "No template found to render content item $item_id in context '$context'"
@@ -284,4 +284,4 @@
# end of content namespace
-}
\ No newline at end of file
+}
Index: openacs-4/packages/acs-content-repository/tcl/filter-procs.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-content-repository/tcl/filter-procs.xql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/acs-content-repository/tcl/filter-procs.xql 27 Apr 2001 02:27:09 -0000 1.1
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+ select live_revision from cr_items where item_id = :item_id
+
+
+
+
+
+
+
+ select mime_type from cr_revisions
+ where revision_id = :revision_id
+
+
+
+
+
+
+
+ select content_type from cr_items
+ where item_id = :item_id
+
+
+
+
+
+
+
+ select table_name from acs_object_types
+ where object_type = :content_type
+
+
+
+
+
+
+
+ select
+ x.*,
+ :item_id as item_id $text_sql,
+ :content_type as content_type
+ from
+ cr_revisions r, ${table_name}x x
+ where
+ r.revision_id = :revision_id
+ and
+ x.revision_id = r.revision_id
+
+
+
+
+
+
+
+ select live_revision from cr_items where item_id = :item_id
+
+
+
+
+
Index: openacs-4/packages/acs-content-repository/tcl/revision-procs-oracle.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-content-repository/tcl/revision-procs-oracle.xql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/acs-content-repository/tcl/revision-procs-oracle.xql 27 Apr 2001 02:27:09 -0000 1.1
@@ -0,0 +1,31 @@
+
+
+ oracle8.1.6
+
+
+
+
+ begin
+ :1 := content_revision.new(title => :title,
+ item_id => :item_id,
+ v_content => null);
+ end;
+
+
+
+
+
+
+
+ update
+ cr_revisions
+ set
+ content = empty_blob()
+ where
+ revision_id = :revision_id
+ returning content into :1
+
+
+
+
+
Index: openacs-4/packages/acs-content-repository/tcl/revision-procs-postgresql.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-content-repository/tcl/revision-procs-postgresql.xql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/acs-content-repository/tcl/revision-procs-postgresql.xql 27 Apr 2001 02:27:09 -0000 1.1
@@ -0,0 +1,34 @@
+
+
+ postgresql7.1
+
+
+
+
+ select content_revision__new(:title,
+ null,
+ now(),
+ 'text/plain',
+ ' ',
+ :item_id
+ )
+
+
+
+
+
+
+
+ FIXME: need to handle this blob
+ update
+ cr_revisions
+ set
+ content = empty_lob()
+ where
+ revision_id = :revision_id
+ returning content into :1
+
+
+
+
+
Index: openacs-4/packages/acs-content-repository/tcl/revision-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-content-repository/tcl/revision-procs.tcl,v
diff -u -r1.1 -r1.2
--- openacs-4/packages/acs-content-repository/tcl/revision-procs.tcl 13 Mar 2001 22:59:26 -0000 1.1
+++ openacs-4/packages/acs-content-repository/tcl/revision-procs.tcl 27 Apr 2001 02:27:09 -0000 1.2
@@ -2,21 +2,19 @@
proc cr_revision_upload { title item_id path } {
- set db [ns_db gethandle]
+ set revision_id [db_exec_plsql get_revision_id "begin
+ :1 := content_revision.new(title => :title,
+ item_id => :item_id,
+ v_content => null);
+ end;"]
- ns_ora exec_plsql_bind $db "begin
- :revision_id := content_revision.new(title => :title,
- item_id => :item_id,
- v_content => null);
- end;" revision_id
+ dml_file dml_revision_from_file "update
+ cr_revisions
+ set
+ content = empty_blob()
+ where
+ revision_id = :revision_id
+ returning content into :1" -blob_files [list $path]
- ns_ora blob_dml_file_bind $db "update cr_revisions set
- content = empty_blob()
- where
- revision_id = :revision_id
- returning content into :1" [list 1] $path
-
- ns_db releasehandle $db
-
return $revision_id
-}
\ No newline at end of file
+}
Index: openacs-4/packages/acs-templating/acs-templating.info
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/acs-templating.info,v
diff -u -r1.2 -r1.3
--- openacs-4/packages/acs-templating/acs-templating.info 5 Apr 2001 18:23:38 -0000 1.2
+++ openacs-4/packages/acs-templating/acs-templating.info 27 Apr 2001 02:27:09 -0000 1.3
@@ -42,13 +42,14 @@
+
+
+
+
-
-
-
Index: openacs-4/packages/acs-templating/sql/postgresql/acs-templating-create.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/sql/postgresql/acs-templating-create.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/acs-templating/sql/postgresql/acs-templating-create.sql 27 Apr 2001 02:27:09 -0000 1.1
@@ -0,0 +1,12 @@
+-- Data model to support content ACS Templating System
+
+-- Copyright (C) 1999-2000 ArsDigita Corporation
+-- Author: Karl Goldstein (karlg@arsdigita.com)
+
+-- $Id: acs-templating-create.sql,v 1.1 2001/04/27 02:27:09 danw Exp $
+
+-- This is free software distributed under the terms of the GNU Public
+-- License. Full text of the license is available from the GNU Project:
+-- http://www.fsf.org/copyleft/gpl.html
+
+\i demo-create.sql
Index: openacs-4/packages/acs-templating/sql/postgresql/acs-templating-drop.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/sql/postgresql/acs-templating-drop.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/acs-templating/sql/postgresql/acs-templating-drop.sql 27 Apr 2001 02:27:09 -0000 1.1
@@ -0,0 +1,9 @@
+-- Uninstall file for the data model created by 'acs-templating-create.sql'
+-- (This file created automatically by create-sql-uninst.pl.)
+--
+-- brech (Mon Aug 28 11:04:55 2000)
+--
+-- $Id: acs-templating-drop.sql,v 1.1 2001/04/27 02:27:09 danw Exp $
+--
+
+\i demo-drop.sql
Index: openacs-4/packages/acs-templating/sql/postgresql/demo-create.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/sql/postgresql/demo-create.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/acs-templating/sql/postgresql/demo-create.sql 27 Apr 2001 02:27:09 -0000 1.1
@@ -0,0 +1,26 @@
+create sequence ad_template_sample_users_seq start 5 increment 1;
+
+create table ad_template_sample_users (
+ user_id integer primary key,
+ first_name varchar(20),
+ last_name varchar(20),
+ address1 varchar(40),
+ address2 varchar(40),
+ city varchar(40),
+ state varchar(2)
+);
+
+
+insert into ad_template_sample_users values
+ (1, 'Fred', 'Jones', '101 Main St.', NULL, 'Orange', 'CA');
+
+insert into ad_template_sample_users values
+ (2, 'Frieda', 'Mae', 'Lexington Hospital', '102 Central St.',
+ 'Orange', 'CA');
+
+insert into ad_template_sample_users values
+ (3, 'Sally', 'Saxberg', 'Board of Supervisors', '1933 Fruitvale St.',
+ 'Woodstock', 'CA');
+
+insert into ad_template_sample_users values
+ (4, 'Yoruba', 'Diaz', '12 Magic Ave.', NULL, 'Lariot', 'WY');
Index: openacs-4/packages/acs-templating/sql/postgresql/demo-drop.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/sql/postgresql/demo-drop.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/acs-templating/sql/postgresql/demo-drop.sql 27 Apr 2001 02:27:09 -0000 1.1
@@ -0,0 +1,10 @@
+-- Uninstall file for the data model created by 'demo-create.sql'
+-- (This file created automatically by create-sql-uninst.pl.)
+--
+-- brech (Mon Aug 28 11:06:33 2000)
+--
+-- $Id: demo-drop.sql,v 1.1 2001/04/27 02:27:09 danw Exp $
+--
+
+drop table ad_template_sample_users;
+drop sequence ad_template_sample_users_seq;
Index: openacs-4/packages/acs-templating/tcl/paginator-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/tcl/paginator-procs.tcl,v
diff -u -r1.1 -r1.2
--- openacs-4/packages/acs-templating/tcl/paginator-procs.tcl 13 Mar 2001 22:59:27 -0000 1.1
+++ openacs-4/packages/acs-templating/tcl/paginator-procs.tcl 27 Apr 2001 02:27:09 -0000 1.2
@@ -35,7 +35,7 @@
# page number,, such as the first few
# letters of a title or date.
-proc template::paginator::create { name query args } {
+proc template::paginator::create { statement_name name query args } {
set level [template::adp_level]
variable parse_level
@@ -52,7 +52,7 @@
set row_ids [cache get $cache_key:row_ids]
if { [string equal $row_ids {}] } {
- init $name $query
+ init $statement_name $name $query
} else {
set opts(row_ids) $row_ids
set opts(context_ids) [cache get $cache_key:context_ids]
@@ -67,7 +67,7 @@
# Initialize a paginated query. Only called by create.
-proc template::paginator::init { name query } {
+proc template::paginator::init { statement_name result_name query } {
get_reference
@@ -79,7 +79,7 @@
if { [info exists properties(contextual)] } {
# query contains two columns, one for ID and one for context cue
- uplevel 3 "template::query __paginator_ids multilist \"$query\""
+ uplevel 3 "template::query $statement_name __paginator_ids multilist \"$query\""
set i 0
set page_size $properties(pagesize)
@@ -96,24 +96,24 @@
}
set properties(context_ids) $context_ids
- cache set $name:$query:context_ids $context_ids $properties(timeout)
+ cache set $result_name:$query:context_ids $context_ids $properties(timeout)
if { [template::util::is_nil row_ids] } {
set row_ids ""
}
set properties(row_ids) $row_ids
- cache set $name:$query:row_ids $row_ids $properties(timeout)
+ cache set $result_name:$query:row_ids $row_ids $properties(timeout)
} else {
# no extra column specified for paging by contextual cues
- uplevel 3 "template::query __paginator_ids onelist \"$query\""
+ uplevel 3 "template::query $statement_name __paginator_ids onelist \"$query\""
set properties(row_ids) $ids
- cache set $name:$query:row_ids $ids $properties(timeout)
+ cache set $result_name:$query:row_ids $ids $properties(timeout)
}
}
@@ -423,7 +423,7 @@
# @param id_column The name of the ID column in the display query (required
# to order rows properly).
-proc template::paginator::get_data { name datasource query id_column page } {
+proc template::paginator::get_data { statement_name name datasource query id_column page } {
set ids [get_row_ids $name $page]
@@ -456,7 +456,7 @@
uplevel 2 "
- template::query __page_data multirow \"$query\" -eval {
+ template::query $statement_name __page_data multirow \"$query\" -eval {
set i \$__page_order(\$row($id_column))
upvar 0 $datasource:\$i __page_sorted_row
array set __page_sorted_row \[array get row\]
Index: openacs-4/packages/acs-templating/tcl/query-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/tcl/query-procs.tcl,v
diff -u -r1.1 -r1.2
--- openacs-4/packages/acs-templating/tcl/query-procs.tcl 13 Mar 2001 22:59:27 -0000 1.1
+++ openacs-4/packages/acs-templating/tcl/query-procs.tcl 27 Apr 2001 02:27:09 -0000 1.2
@@ -10,13 +10,497 @@
# http://www.fsf.org/copyleft/gpl.html
-# Supplied options are "oracle" and "generic"
+# (DCW - Openacs) converted template db api to use standard api and hooked it
+# into the query-dispatcher. This ties into the standard db api's
+# transaction control and handle allocation into the templating query interface
+# allowing the two db api's to be mixed together.
-set path "ns/server/[ns_info server]/ats"
-set db [ns_config $path DatabaseInterface oracle]
+# Todo - convert caching to use ns_cache.
-source "[file dirname [info script]]/database-procs/$db.tcl"
+nsv_set __template_query_persistent_cache . .
+nsv_set __template_query_persistent_timeout . .
+
+# @public query
+
+# Perform a database query
+
+# @option maxrows Limits the query results of a multirow query
+# to a fixed number of rows.
+# @option cache Cache the query results keyed on an identifier
+# that is unique for both the query and the bind variables
+# used in the query. The cached result reflects
+# any initial specification of maxrows and startrows.
+# @option refresh Force a query to be performed even if it is cached,
+# and refresh the cache.
+# Only applicable if the cache option is specified as well.
+# Does not affect a previously specified timeout period.
+# @option timeout The maximum period of time for which the cached results
+# are valid in seconds. Only applicable for
+# persistently cached results.
+# @option persistent Cache the query results persistently, so that
+# all subsequent requests use the results.
+
+proc template::query { statement_name result_name type sql args } {
+
+ #set beginTime [clock clicks]
+
+ template::util::get_opts $args
+
+ if { ! [info exists opts(uplevel)] } {
+ set opts(uplevel) 2
+ } else {
+ set opts(uplevel) [expr 2 + $opts(uplevel)]
+ }
+
+ # check the cache for a valid cached query result and return if so
+ # otherwise continue to perform the query and cache the results afterwards
+
+ if { [info exists opts(cache)] && [get_cached_result $result_name $type] } {
+ return $opts(result)
+ }
+
+ if { ! [info exists opts(maxrows)] } {
+ set opts(maxrows) 10000
+ }
+
+ db_with_handle db {
+ set ret_code [template::query::$type $statement_name $db $result_name \
+ $sql]
+ }
+
+ if { [info exists opts(cache)] } {
+
+ # cache the query result
+ set_cached_result
+ }
+
+ #set timeElapsed [expr ([clock clicks] - $beginTime) / 1000]
+ #ns_log Notice "Query performed in: $timeElapsed ms"
+
+ return $ret_code
+}
+
+# @private onevalue
+
+# Process a onevalue query. Use a single array to store the results.
+
+proc template::query::onevalue { statement_name db result_name sql } {
+
+ set full_statement_name [db_qd_get_fullname $statement_name]
+
+ upvar opts opts
+
+ upvar $opts(uplevel) $result_name result
+ set result ""
+
+ uplevel "set __row \[db_exec 0or1row $db $full_statement_name $sql\]"
+ upvar __row row
+
+ if { $row != "" } {
+
+ # Set the result in the calling frame.
+ set result [ns_set value $row 0]
+
+ if { [info exists opts(cache)] } {
+ set opts(result) $result
+ }
+ }
+}
+
+# @private onerow
+
+# Process a onerow query. Use a single array to store the results.
+
+proc template::query::onerow { statement_name db result_name sql } {
+
+ set full_statement_name [db_qd_get_fullname $statement_name]
+
+ upvar opts opts
+
+ uplevel "set __row \[db_exec 0or1row $db $full_statement_name $sql\]"
+ upvar __row row
+
+ if { $row != "" } {
+
+ # Set the results in the calling frame.
+ upvar $opts(uplevel) $result_name result
+
+ set size [ns_set size $row]
+
+ for { set i 0 } { $i < $size } { incr i } {
+
+ set column [ns_set key $row $i]
+ set result($column) [ns_set value $row $i]
+ }
+
+ if { [info exists opts(cache)] } {
+ set opts(result) [array get result]
+ }
+
+ return 1
+
+ } else {
+
+ return 0
+ }
+}
+
+# @private multirow
+
+# Process a multirow query. Use an array for each row row in the
+# result. Arrays are named name0, name1, name2 etc. The variable
+# name.rowcount is also defined for checking and iteration.
+
+proc template::query::multirow { statement_name db result_name sql } {
+
+ set full_statement_name [db_qd_get_fullname $statement_name]
+
+ upvar opts opts
+
+ uplevel "set __row \[db_exec select $db $full_statement_name $sql\]"
+ upvar __row row
+
+ upvar $opts(uplevel) $result_name:rowcount rowcount \
+ $result_name:columns column_list
+
+ # set a local variable as to whether we are cacheing or not
+ if { [info exists opts(cache)] } {
+ set is_cached 1
+ set cached_result [list]
+ } else {
+ set is_cached 0
+ }
+
+ set rowcount 0
+
+ if { [info exists opts(eval)] } {
+ # figure out the level at which to reference the row
+ set ref_level [expr $opts(uplevel) - 2]
+ }
+
+ while { [ns_db getrow $db $row] } {
+
+ incr rowcount
+
+ # break if maxrows has been reached
+ if { $rowcount > $opts(maxrows) } {
+ ns_db flush $db
+ upvar $opts(uplevel) $name:has_more_rows has_more_rows
+ set has_more_rows 1
+ incr rowcount -1
+ break
+ }
+
+ # set the results in the calling frame
+ upvar $opts(uplevel) ${name}:$rowcount result
+
+ set result(rownum) $rowcount
+
+ set size [ns_set size $row]
+
+ for { set i 0 } { $i < $size } { incr i } {
+
+ set column [ns_set key $row $i]
+ set result($column) [ns_set value $row $i]
+
+ if {$rowcount == 1 } {
+ lappend column_list $column
+ }
+ }
+
+ # Execute custom code for each row
+ if { [info exists opts(eval)] } {
+ uplevel $opts(uplevel) "
+ upvar 0 ${name}:$rowcount row; $opts(eval)
+ "
+ }
+
+ if { $is_cached } {
+ lappend cached_result [array get result]
+ }
+ }
+
+ if { $is_cached } {
+ set opts(result) $cached_result
+ }
+}
+
+proc template::query::multilist { statement_name db result_name sql } {
+
+ set full_statement_name [db_qd_get_fullname $statement_name]
+
+ upvar opts opts
+
+ uplevel "set __row \[db_exec select $db $full_statement_name $sql\]"
+ upvar __row row
+
+ upvar $opts(uplevel) $result_name rows
+
+ set rows [list]
+
+ while { [ns_db getrow $db $row] } {
+
+ set values [list]
+ set size [ns_set size $row]
+
+ for { set i 0 } { $i < $size } { incr i } {
+
+ lappend values [ns_set value $row $i]
+ }
+
+ lappend rows $values
+ }
+
+ if { [info exists opts(cache)] } {
+ set opts(result) $rows
+ }
+
+ return $rows
+}
+
+# Creates a data source where the values for each row
+# are returned as a list. Rows are grouped according
+# to the column values specified in the -groupby option
+# See template::util::lnest for more details.
+
+proc template::query::nestedlist { statement_name db result_name sql } {
+
+ set full_statement_name [db_qd_get_fullname $statement_name]
+
+ upvar opts opts
+
+ uplevel "set __row \[db_exec select $db $full_statement_name $sql\]"
+ upvar __row row
+
+ upvar $opts(uplevel) $result_name rows
+
+ set groups $opts(groupby)
+
+ set rows [list]
+
+ while { [ns_db getrow $db $row] } {
+
+ set values [list]
+ set size [ns_set size $row]
+
+ for { set i 0 } { $i < $size } { incr i } {
+
+ lappend values [ns_set value $row $i]
+ }
+
+ # build the values on which to group
+ set group_values [list]
+ foreach group $groups {
+ lappend group_values [ns_set get $row $group]
+ }
+
+ eval template::util::lnest rows [list $values] $group_values
+ }
+
+ if { [info exists opts(cache)] } {
+ set opts(result) $rows
+ }
+
+ return $rows
+}
+
+proc template::query::onelist { statement_name db result_name sql } {
+
+ set full_statement_name [db_qd_get_fullname $statement_name]
+
+ upvar opts opts
+
+ uplevel "set __row \[db_exec select $db $full_statement_name $sql\]"
+ upvar __row row
+
+ upvar $opts(uplevel) $result_name rows
+
+ set rows [list]
+
+ while { [ns_db getrow $db $row] } {
+
+ set values [list]
+ lappend rows [ns_set value $row 0]
+ }
+
+ if { [info exists opts(cache)] } {
+ set opts(result) $rows
+ }
+}
+
+proc template::query::dml { statement_name db name sql } {
+
+ set full_statement_name [db_qd_get_fullname $statement_name]
+
+ upvar opts opts
+
+ uplevel "db_exec dml $db $full_statement_name \"$sql\""
+}
+
+# @private get_cached_result
+
+# Looks in the appropriate cache for the named query result
+# If a valid result is found, then sets the result in the returning
+# stack frame.
+
+# @return 1 if result was successfully retrieved, 0 if failed
+
+proc get_cached_result { name type } {
+
+ upvar opts opts
+ set cache_key $opts(cache)
+ set success 0
+
+ if { [info exists opts(persistent)] } {
+
+ if { [nsv_exists __template_query_persistent_cache $cache_key] } {
+
+ # check the timeout
+
+ set timeout [nsv_get __template_query_persistent_timeout $cache_key]
+ if { $timeout > [ns_time] } {
+ set cached_result \
+ [nsv_get __template_query_persistent_cache $cache_key]
+ set success 1
+ }
+ }
+
+ } else {
+
+ global __template_query_request_cache
+
+ if { [info exists __template_query_request_cache($cache_key)] } {
+
+ set cached_result $__template_query_request_cache($cache_key)
+ set success 1
+ }
+ }
+
+ if { $success } {
+
+ switch $type {
+
+ multirow {
+
+ upvar $opts(uplevel) $name:rowcount rowcount
+ set rowcount [llength $cached_result]
+ set rownum 1
+
+ foreach cached_row $cached_result {
+ upvar $opts(uplevel) $name:$rownum row
+ array set row $cached_row
+ incr rownum
+ }
+ set opts(result) ""
+ }
+ onerow {
+
+ upvar $opts(uplevel) $name result
+ array set result $cached_result
+ set opts(result) ""
+ }
+ default {
+
+ upvar $opts(uplevel) $name result
+ set result $cached_result
+ set opts(result) $cached_result
+ }
+ }
+ }
+
+ return $success
+}
+
+# @private set_cached_result
+
+# Places a query result in the appropriate cache.
+
+proc set_cached_result {} {
+
+ upvar opts opts
+
+ if { ! [info exists opts(result)] } { return }
+
+ set cache_key $opts(cache)
+
+ if { [info exists opts(persistent)] } {
+
+ # set the result in the persistent cache
+
+ nsv_set __template_query_persistent_cache $cache_key $opts(result)
+
+ if { [info exists opts(timeout)] } {
+ set timeout [expr [ns_time] + $opts(timeout)]
+ } else {
+ set timeout [expr [ns_time] + 60 * 60 * 24 * 7]
+ }
+
+ nsv_set __template_query_persistent_timeout $cache_key $timeout
+
+ } else {
+
+ global __template_query_request_cache
+ set __template_query_request_cache($cache_key) $opts(result)
+ }
+}
+
+# Deprecated!
+
+proc template::query::iterate { statement_name db sql body } {
+
+ set full_statement_name [db_qd_get_fullname $statement_name]
+
+ uplevel "set __result \[db_exec select $db $full_statement_name $sql\]"
+ upvar __result result
+
+ set rowcount 0
+
+ while { [ns_db getrow $db $result] } {
+
+ upvar __query_iterate_row row
+
+ set row(rownum) [incr rowcount]
+
+ set size [ns_set size $result]
+
+ for { set i 0 } { $i < $size } { incr i } {
+
+ set column [ns_set key $result $i]
+ set row($column) [ns_set value $result $i]
+ }
+
+ # Execute custom code for each row
+ uplevel "upvar 0 __query_iterate_row row; $body"
+ }
+}
+
+# Flush the cached queries where the query name matches the
+# specified string match
+
+proc template::query::flush_cache { cache_match } {
+
+ # Flush persistent cache
+ set names [nsv_array names __template_query_persistent_cache]
+ foreach name $names {
+ if { [string match $cache_match $name] } {
+ ns_log notice "FLUSHING QUERY (persistent): $name"
+ nsv_unset __template_query_persistent_cache $name
+ }
+ }
+
+ # Flush temporary cache
+ global __template_query_request_cache
+ set names [array names __template_query_persistent_cache]
+ foreach name $names {
+ if { [string match $cache_match $name] } {
+ ns_log notice "FLUSHING QUERY (request): $name"
+ unset __template_query_persistent_cache($name)
+ }
+ }
+
+}
+
# Perform get/set operations on a multirow datasource
proc template::multirow { op name args } {
Index: openacs-4/packages/acs-templating/tcl/table-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/tcl/table-procs.tcl,v
diff -u -r1.1 -r1.2
--- openacs-4/packages/acs-templating/tcl/table-procs.tcl 13 Mar 2001 22:59:27 -0000 1.1
+++ openacs-4/packages/acs-templating/tcl/table-procs.tcl 27 Apr 2001 02:27:09 -0000 1.2
@@ -45,23 +45,14 @@
# Create the widget data structure
-proc template::widget::table::create { name args } {
+proc template::widget::table::create { statement_name name args } {
upvar "tablewidget:${name}" widget
set widget(name) $name
-
- upvar 0 widget opts
- template::util::get_opts $args
-
- if { [info exists opts(db)] } {
- set db $opts(db)
- } else {
- set db ""
- }
template::widget::table::get_params $name 2
- template::widget::table::prepare $name $db 2
+ template::widget::table::prepare $statment_name $name 2
}
# Get the order by clause for the widget, other parameters (?)
@@ -93,9 +84,8 @@
}
# Compose the query, if neccessary, and define the datasources
-proc template::widget::table::prepare { name { db ""} {level 1} } {
+proc template::widget::table::prepare { statement_name name {level 1} } {
- set free_db 0
upvar $level "tablewidget:${name}" widget
# Get the rows
@@ -104,6 +94,7 @@
error "No row datasource available for tablewidget $name"
}
+ # fixme - need to get a statement name here
set sql_query $widget(query)
# Append the order by clause, if any
@@ -114,12 +105,6 @@
append sql_query " $widget(orderby)"
}
- # Get database handle
- if { [template::util::is_nil db] } {
- set db [ns_db gethandle]
- set free_db 1
- }
-
if { ![template::util::is_nil widget(column_def)] } {
# Convert the column def list to an array for extra speed
upvar $level "tablewidget:${name}_column_def" column_arr
@@ -160,7 +145,7 @@
}
uplevel $level "
- template::query tw_${name}_rows multirow \{$sql_query\} -db \{$db\} \\
+ template::query $statement_name tw_${name}_rows multirow \{$sql_query\} \\
-eval \{$eval_code\}
"
@@ -225,7 +210,6 @@
uplevel $level "uplevel 0 tw_${name}_columns $template(columns_data)"
}
- if { $free_db } { ns_db releasehandle $db }
}
# Register the tag that actually renders the widget
@@ -253,4 +237,4 @@
-
\ No newline at end of file
+
Index: openacs-4/packages/acs-templating/tcl/util-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/tcl/util-procs.tcl,v
diff -u -r1.1 -r1.2
--- openacs-4/packages/acs-templating/tcl/util-procs.tcl 13 Mar 2001 22:59:27 -0000 1.1
+++ openacs-4/packages/acs-templating/tcl/util-procs.tcl 27 Apr 2001 02:27:09 -0000 1.2
@@ -128,7 +128,7 @@
append query [join $conditions " and "]
- template::query count onevalue $query
+ template::query get_count count onevalue $query
return [expr $count == 0]
}
Index: openacs-4/packages/acs-templating/tcl/widget-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/tcl/widget-procs.tcl,v
diff -u -r1.1 -r1.2
--- openacs-4/packages/acs-templating/tcl/widget-procs.tcl 13 Mar 2001 22:59:27 -0000 1.1
+++ openacs-4/packages/acs-templating/tcl/widget-procs.tcl 27 Apr 2001 02:27:09 -0000 1.2
@@ -365,9 +365,10 @@
error "No search query specified for search widget"
}
+ # FIXME: need to get a statement name here
set query $element(search_query)
- template::query options multilist $query
+ template::query get_options options multilist $query
set option_count [llength $options]
Index: openacs-4/packages/acs-templating/www/doc/demo/form.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/doc/demo/form.tcl,v
diff -u -r1.1 -r1.2
--- openacs-4/packages/acs-templating/www/doc/demo/form.tcl 13 Mar 2001 22:59:27 -0000 1.1
+++ openacs-4/packages/acs-templating/www/doc/demo/form.tcl 27 Apr 2001 02:27:09 -0000 1.2
@@ -16,28 +16,21 @@
if { [form is_request add_user] } {
- set db [ns_db gethandle]
-
set query "select ad_template_sample_users_seq.nextval from dual"
- template::query user_id onevalue $query -db $db
+ template::query get_user_id user_id onevalue $query
- ns_db releasehandle $db
-
element set_properties add_user user_id -value $user_id
}
if { [form is_valid add_user] } {
- set db [ns_db gethandle]
- ns_ora dml $db -bind [ns_getform] "
+ db_dml insert_sample -bind [ns_getform] "
insert into
ad_template_sample_users
values (
:user_id, :first_name, :last_name, :address1, :address2, :city, :state
)"
- ns_db releasehandle $db
-
template::forward index.html
}
Index: openacs-4/packages/acs-templating/www/doc/demo/multiaccess.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/doc/demo/multiaccess.tcl,v
diff -u -r1.1 -r1.2
--- openacs-4/packages/acs-templating/www/doc/demo/multiaccess.tcl 13 Mar 2001 22:59:27 -0000 1.1
+++ openacs-4/packages/acs-templating/www/doc/demo/multiaccess.tcl 27 Apr 2001 02:27:09 -0000 1.2
@@ -8,13 +8,9 @@
from
ad_template_sample_users"
-set db [ns_db gethandle]
-
-template::query users multirow $query -db $db \
+template::query get_users users multirow $query \
-eval { set row(full_name) "$row(last_name), $row(first_name)" }
-ns_db releasehandle $db
-
# Manually access the datasource
# Get the size
Index: openacs-4/packages/acs-templating/www/doc/demo/user-edit.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/doc/demo/user-edit.tcl,v
diff -u -r1.1 -r1.2
--- openacs-4/packages/acs-templating/www/doc/demo/user-edit.tcl 13 Mar 2001 22:59:27 -0000 1.1
+++ openacs-4/packages/acs-templating/www/doc/demo/user-edit.tcl 27 Apr 2001 02:27:09 -0000 1.2
@@ -121,15 +121,11 @@
form get_values user_edit first_name last_name address1 address2 city state
- set db [ns_db gethandle]
-
- ns_ora dml $db "update ad_template_sample_users
+ db_dml update_sample_users "update ad_template_sample_users
set first_name = :first_name, last_name = :last_name,
address1 = :address1, address2 = :address2, city = :city,
state = :state
where user_id = :user_id"
- ns_db releasehandle $db
-
template::forward multiple
-}
\ No newline at end of file
+}
Index: openacs-4/packages/acs-templating/www/doc/exercise/form-sample-revised.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/doc/exercise/form-sample-revised.tcl,v
diff -u -r1.1 -r1.2
--- openacs-4/packages/acs-templating/www/doc/exercise/form-sample-revised.tcl 13 Mar 2001 22:59:27 -0000 1.1
+++ openacs-4/packages/acs-templating/www/doc/exercise/form-sample-revised.tcl 27 Apr 2001 02:27:09 -0000 1.2
@@ -30,19 +30,15 @@
if { [form is_valid add_entry] } {
ns_log error "now we've gotten past the if statement"
- set db [ns_db gethandle]
- ns_ora dml $db -bind [ns_getform] "
+ db_dml insert_address -bind [ns_getform] "
insert into
address_book
values (
:first_names, :last_name, :title, null, :gender, :address, :city, :state, :zip, :country,
:email, :relationship, :primary_phone, :home, :work, :cell, :pager, :fax
)"
-
- ns_db releasehandle $db
template::forward index.html
-
}
Index: openacs-4/packages/acs-templating/www/doc/exercise/form-sample.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/doc/exercise/form-sample.tcl,v
diff -u -r1.1 -r1.2
--- openacs-4/packages/acs-templating/www/doc/exercise/form-sample.tcl 13 Mar 2001 22:59:27 -0000 1.1
+++ openacs-4/packages/acs-templating/www/doc/exercise/form-sample.tcl 27 Apr 2001 02:27:09 -0000 1.2
@@ -97,9 +97,7 @@
[template::form get_values add_entry birthday]
- set db [ns_db gethandle]
-
- ns_ora dml $db -bind [ns_getform] "
+ db_dml insert_form -bind [ns_getform] "
insert into
address_book
values (
@@ -111,13 +109,11 @@
# can't seem to get orable to bind array variables birthday.day, birthday.month and birthday.year
# okay, turns out oracle doesn't support arrays, will have to do this in tcl first
-
- ns_db releasehandle $db
- template::forward form-sample.acs
+ template::forward form-sample.acs
}
-template::query address multirow "select * from address_book order by last_name"
+template::query get_address address multirow "select * from address_book order by last_name"
set rowcount [set address:rowcount]
Index: openacs-4/packages/acs-templating/www/doc/exercise/list-and-var-sample.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/doc/exercise/list-and-var-sample.tcl,v
diff -u -r1.1 -r1.2
--- openacs-4/packages/acs-templating/www/doc/exercise/list-and-var-sample.tcl 13 Mar 2001 22:59:27 -0000 1.1
+++ openacs-4/packages/acs-templating/www/doc/exercise/list-and-var-sample.tcl 27 Apr 2001 02:27:09 -0000 1.2
@@ -68,7 +68,7 @@
"hanging out with my best buds" \
"telling jokes -- my friends say I've got a great sense of humor!"]
-template::query friends multirow "select first_names, last_name, age, gender, address, likes_chocolate_p from best_friends"
+template::query get_friends friends multirow "select first_names, last_name, age, gender, address, likes_chocolate_p from best_friends"
#template::multirow create foo_multirow columns1 columns2 columns3
template::multirow extend friends extra_column