Index: openacs-4/packages/acs-core-docs/www/xml/developers-guide/db-api.xml =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-core-docs/www/xml/developers-guide/db-api.xml,v diff -u -r1.2 -r1.3 --- openacs-4/packages/acs-core-docs/www/xml/developers-guide/db-api.xml 24 Dec 2001 19:31:42 -0000 1.2 +++ openacs-4/packages/acs-core-docs/www/xml/developers-guide/db-api.xml 2 Feb 2002 03:47:32 -0000 1.3 @@ -10,10 +10,10 @@ Overview - One of ACS's great strengths is that code written for it is very close to - the database. It is very easy to interact with the database from anywhere - within ACS. Our goal is to develop a coherent API for database access which - makes this even easier. + One of OpenACS's great strengths is that code written for it is + very close to the database. It is very easy to interact with the + database from anywhere within OpenACS. Our goal is to develop a + coherent API for database access which makes this even easier. @@ -22,7 +22,7 @@ The Old Way - Here's a typical block of code from an ACS 3.x dynamic page: + Here's a typical block of code from an OpenACS 3.x dynamic page: @@ -153,15 +153,18 @@ - The new command db_transaction makes the scope of a - transaction clear. db_transaction takes the code block - argument and automatically runs it in the context of a transaction. + The new command db_transaction + makes the scope of a transaction + clear. db_transaction takes the + code block argument and automatically runs it in the context of a + transaction. - The new command db_foreach writes our old while loop for us. + The new command db_foreach writes + our old while loop for us. @@ -188,7 +191,6 @@ Bind Variables - Bind variables are placeholders for literal values in an SQL query being sent to the server. Take the example query above: in the old way, data was generally passed to Oracle directly, via Tcl string @@ -501,7 +503,7 @@ Therefore, the Database Access API provides a database-independent way to represent null (instead of the Oracle-specific idiom of the - empty string): db_null. + empty string): db_null. Use it instead of the empty string whenever you want to set a column value explicitly to null, e.g.: @@ -584,17 +586,15 @@ - db_abort_transaction - -db_abort_transaction +db_abort_transaction Aborts all levels of a transaction. That is if this is called within @@ -608,17 +608,17 @@ - + db_null - + -db_null +db_null @@ -633,16 +633,16 @@ - + db_foreach - + -db_foreach statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \ +db_foreach statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \ [ -column_array array_name | -column_set set_name ] \ code_block [ if_no_rows if_no_rows_block ] @@ -684,16 +684,16 @@ - + db_1row - + -db_1row statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \ +db_1row statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \ [ -column_array array_name | -column_set set_name ] @@ -719,16 +719,16 @@ - + db_0or1row - + -db_0or1row statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \ +db_0or1row statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \ [ -column_array array_name | -column_set set_name ] @@ -744,11 +744,11 @@ - db_nextval + db_nextval -db_nextval sequence-name +db_nextval sequence-name @@ -764,17 +764,17 @@ - + db_register_pooled_sequence - + -db_register_pooled_sequence sequence-name pool-size +db_register_pooled_sequence sequence-name pool-size Registers the sequence sequence-name to be pooled, with a pool @@ -786,11 +786,11 @@ - db_string + db_string -db_string statement-name sql [ -default default ] [ -bind bind_set_id | -bind bind_value_list ] +db_string statement-name sql [ -default default ] [ -bind bind_set_id | -bind bind_value_list ] Returns the first column of the result of SQL query @@ -808,11 +808,11 @@ - db_list + db_list -db_list statement-name sql [ -bind bind_set_id | -bind bind_value_list ] +db_list statement-name sql [ -bind bind_set_id | -bind bind_value_list ] Returns a Tcl list of the values in the first column of the result of SQL @@ -827,11 +827,11 @@ - db_list_of_lists + db_list_of_lists -db_list_of_lists statement-name sql [ -bind bind_set_id | -bind bind_value_list ] +db_list_of_lists statement-name sql [ -bind bind_set_id | -bind bind_value_list ] Returns a Tcl list, each element of which is a list of all column values @@ -844,11 +844,11 @@ - db_dml + db_dml -db_dml statement-name sql \ +db_dml statement-name sql \ [ -bind bind_set_id | -bind bind_value_list ] \ [ -blobs blob_list | -clobs clob_list | -blob_files blob_file_list | -clob_files clob_file_list ] @@ -892,18 +892,18 @@ - db_write_clob, - db_write_blob, - db_blob_get_file + db_write_clob, + db_write_blob, + db_blob_get_file -db_write_clob statement-name sql [ -bind bind_set_id | -bind bind_value_list ] +db_write_clob statement-name sql [ -bind bind_set_id | -bind bind_value_list ] -db_write_blob statement-name sql [ -bind bind_set_id | -bind bind_value_list ] +db_write_blob statement-name sql [ -bind bind_set_id | -bind bind_value_list ] -db_blob_get_file statement-name sql [ -bind bind_set_id | -bind bind_value_list ] +db_blob_get_file statement-name sql [ -bind bind_set_id | -bind bind_value_list ] Analagous to ns_ora write_clob/write_blob/blob_get_file. @@ -914,10 +914,10 @@ - db_release_unused_handles + db_release_unused_handles - db_release_unused_handles + db_release_unused_handles Releases any allocated, unused database handles. @@ -926,11 +926,11 @@ - db_transaction + db_transaction -db_transaction code_block [ on_error { code_block } ] +db_transaction code_block [ on_error { code_block } ] Executes code_block transactionally. Nested @@ -981,12 +981,12 @@ - db_resultrows + db_resultrows -db_resultrows +db_resultrows Returns the number of rows affected or returned by the previous @@ -997,10 +997,10 @@ - db_with_handle + db_with_handle -db_with_handle var code_block +db_with_handle var code_block @@ -1037,20 +1037,20 @@ - + db_nullify_empty_string - + -db_nullify_empty_string string +db_nullify_empty_string string For true SQL purists, we provide the convenience function - db_nullify_empty_string, which returns + db_nullify_empty_string, which returns [db_null] if its string argument is the empty string and can be used to encapsulate another Oracle quirk: @@ -1088,134 +1088,7 @@ - Implementation Design (work in progress) - - The ideas here are preliminary, so please send feedback to michael@arsdigita.com. There may well - be a much simpler, superior design that I (Michael) am just missing right - now. If so, please let me know! - - - The basic idea is to translate the logical - statement-name into an actual SQL statement, written in - the appropriate SQL dialect for the RDBMS that is in use. The - sql argument is essentially a convenience that enables - the SQL for the "default dialect" to be written inline. For 3.4, we - will probably use configuration parameters to tell the Database Access API - what the default dialect is and what dialect is actually in use: - - - -[ns/server/server_name/acs] -... -DefaultSQLDialect=oracle8 -SQLDialect=postgres7 - - - - - (An alternative approach would be to use the ACS Package Manager, i.e., - install a "pseudo-package" with no actual code to indicate what - RDBMS is installed. Then, the Database Access API could query the APM to - figure what SQL dialect to employ.) - - - For instructing the Database Access API to translate a named statement in - a specific SQL dialect, we may define a new API call: - - -statement_location statement_name sql_dialect sql - - - - - which would be called at server initialization time. The Database Access API - will then know to use the SQL statement appropriate for the specified - SQLDialect. (The name db_implement_statement is - very tentative.) - - Issues: - - - - - Is making the caller of db_implement_statement explicitly - specify the statement location (e.g., "/bboard/q-and-a") too much - of a pain? Can we make this more convenient somehow? - - - - - - In the case that the inline SQL is not in the specified - SQLDialect, reading the rewritten SQL into memory for the life - of the server may not be a good idea. The three basic approaches I can think - of to implement the - db_implement_statement API are: - - - - - Cache the rewritten SQL for the appropriate SQL dialect in an - nsv array - - - - - Cache the rewritten SQL for the appropriate SQL dialect in a special - database table that we keep pinned in memory - - - - - Cache the rewritten SQL for the appropriate SQL dialect in a special - file, maybe even a DBM file - - - - - - - Given the above two issues, should we rethink the - db_implement_statement API - altogether? - - - - One possibility is a file-based approach, where the alternative SQL - statements would live in conventionally named and located files, e.g., - /bboard/q-and-a.postgres7 would contain Postgres 7 versions of - the SQL statements in /bboard/q-and-a.tcl.) A potential con of - this approach is that the Database Access API would have to perform file I/O - for every SQL statement that's been rewritten. This may be a non-issue; I - don't actually know. (We could augment this approach with caching too, - perhaps a fixed-size LRU cache.) - - Another similar approach would be just to have one massive, magic file for - each SQL dialect that maps each statement identifier (location plus name) to - the corresponding statement. - - - - Another larger problem is the fact that this design does not work for - instances where we build a SQL statement based on control flow logic, e.g., - we sometimes join in an extra table based on the user input. This problem - doesn't mean that the design as a whole is broken; it just means that - this design alone does not get us all the way to full SQL abstraction. - - - - Version 2.1 of the ArsDigita Oracle - Driver adds a set of ns_ora analogs for the following - ns_db calls: - 0or1row, 1row, - select, and - dml. - (It also adds ns_ora - array_dml.) Thus, the groundwork for implementing the above API for - ACS/Oracle is already established. - - ($Id$)