From 0a188f7944cbba5aa0437640af353f370311982c Mon Sep 17 00:00:00 2001
From: scottmk <scottmk@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Date: Tue, 8 Jun 2010 21:01:27 +0000
Subject: [PATCH] 1. Support function calls in the FROM clause.

2. Support wildcards in the SELECT clause.

WARNING: the presence of a wildcard in the SELECT clause
is likely to disrupt a GROUP BY by renumbering the columns.

Also: the "columns" method currently cannot return the
names of the columns into which a wild card is expanded.

M    Open-ILS/include/openils/oils_buildq.h
M    Open-ILS/src/c-apps/oils_storedq.c
M    Open-ILS/src/c-apps/buildSQL.c


git-svn-id: svn://svn.open-ils.org/ILS/trunk@16628 dcc99617-32d9-48b4-a31d-7c20da2025e4
---
 Open-ILS/include/openils/oils_buildq.h |  1 +
 Open-ILS/src/c-apps/buildSQL.c         | 20 ++++++++++---
 Open-ILS/src/c-apps/oils_storedq.c     | 51 ++++++++++++++++++++++++----------
 3 files changed, 54 insertions(+), 18 deletions(-)

diff --git a/Open-ILS/include/openils/oils_buildq.h b/Open-ILS/include/openils/oils_buildq.h
index 78ead41e28..f9cfe79d42 100644
--- a/Open-ILS/include/openils/oils_buildq.h
+++ b/Open-ILS/include/openils/oils_buildq.h
@@ -108,6 +108,7 @@ struct FromRelation_ {
 	int              subquery_id;
 	StoredQ*         subquery;
 	int              function_call_id;
+	Expression*      function_call;
 	char*            table_alias;
 	int              parent_relation_id;
 	int              seq_no;
diff --git a/Open-ILS/src/c-apps/buildSQL.c b/Open-ILS/src/c-apps/buildSQL.c
index 596e0ab8f0..15cc46c552 100644
--- a/Open-ILS/src/c-apps/buildSQL.c
+++ b/Open-ILS/src/c-apps/buildSQL.c
@@ -372,7 +372,18 @@ static void buildFrom( BuildSQLState* state, const FromRelation* core_from ) {
 			buffer_add_char( state->sql, ')' );
 			break;
 		case FRT_FUNCTION :
-			sqlAddMsg( state, "Functions in FROM clause not yet supported" );
+			buildFunction( state, core_from->function_call );
+			if ( state->error ) {
+				sqlAddMsg( state,
+					"Unable to include function call # %d in FROM relation # %d",
+	 				core_from->function_call->id, core_from->id );
+				return;
+			}
+			break;
+		default :
+			osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
+				"Internal error: Invalid type # %d in FROM relation # %d",
+				core_from->type, core_from->id ));
 			state->error = 1;
 			return;
 	}
@@ -683,9 +694,10 @@ static void buildExpression( BuildSQLState* state, const Expression* expr ) {
 			if( expr->column_name ) {
 				buffer_add( state->sql, expr->column_name );
 			} else {
-				osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
-					"Column name not present in expression # %d", expr->id ));
-				state->error = 1;
+				//osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
+				//	"Column name not present in expression # %d", expr->id ));
+				//state->error = 1;
+				buffer_add_char( state->sql, '*' );
 			}
 			break;
 		case EXP_EXIST :
diff --git a/Open-ILS/src/c-apps/oils_storedq.c b/Open-ILS/src/c-apps/oils_storedq.c
index a4bcc98a5e..50e6ab8ae8 100644
--- a/Open-ILS/src/c-apps/oils_storedq.c
+++ b/Open-ILS/src/c-apps/oils_storedq.c
@@ -547,30 +547,31 @@ static FromRelation* constructFromRelation( BuildSQLState* state, dbi_result res
 	else
 		type = FRT_RELATION;     // shouldn't happen due to database constraint
 
-	const char* table_name  = dbi_result_get_string_idx( result, 3 );
-	const char* class_name  = dbi_result_get_string_idx( result, 4 );
+	const char* table_name   = dbi_result_get_string_idx( result, 3 );
+	const char* class_name   = dbi_result_get_string_idx( result, 4 );
 
 	int subquery_id;
 	if( dbi_result_field_is_null_idx( result, 5 ) )
-		subquery_id          = -1;
+		subquery_id           = -1;
 	else
-		subquery_id          = dbi_result_get_int_idx( result, 5 );
+		subquery_id           = dbi_result_get_int_idx( result, 5 );
 
 	int function_call_id;
 	if( dbi_result_field_is_null_idx( result, 6 ) )
-		function_call_id     = -1;
+		function_call_id      = -1;
 	else
-		function_call_id     = dbi_result_get_int_idx( result, 6 );
+		function_call_id      = dbi_result_get_int_idx( result, 6 );
 
-	const char* table_alias  = dbi_result_get_string_idx( result, 7 );
+	Expression* function_call = NULL;
+	const char* table_alias   = dbi_result_get_string_idx( result, 7 );
 
 	int parent_relation_id;
 	if( dbi_result_field_is_null_idx( result, 8 ) )
-		parent_relation_id   = -1;
+		parent_relation_id    = -1;
 	else
-		parent_relation_id   = dbi_result_get_int_idx( result, 8 );
+		parent_relation_id    = dbi_result_get_int_idx( result, 8 );
 
-	int seq_no               = dbi_result_get_int_idx( result, 9 );
+	int seq_no                = dbi_result_get_int_idx( result, 9 );
 
 	JoinType join_type;
 	const char* join_type_str = dbi_result_get_string_idx( result, 10 );
@@ -620,10 +621,27 @@ static FromRelation* constructFromRelation( BuildSQLState* state, dbi_result res
 			}
 			break;
 		case FRT_FUNCTION :
-			osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
-				"Functions in FROM clause not yet supported" ));
-			state->error = 1;
-			return NULL;
+			if( -1 == function_call_id ) {
+				osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
+					"FROM clause # %d purports to reference a function; not identified", id ));
+				state->error = 1;
+				return NULL;
+			}
+
+			function_call = getExpression( state, function_call_id );
+			if( !function_call ) {
+				osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
+					"Unable to build function call # %d in FROM relation # %d",
+					function_call_id, id ));
+				state->error = 1;
+				return NULL;
+			} else if( function_call->type != EXP_FUNCTION ) {
+				osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
+					"In FROM relation # %d: supposed function call expression # %d "
+					"is not a function call", id, function_call_id ));
+				state->error = 1;
+				return NULL;
+			}
 	}
 
 	FromRelation* join_list = getJoinList( state, id );
@@ -666,6 +684,7 @@ static FromRelation* constructFromRelation( BuildSQLState* state, dbi_result res
 	fr->subquery_id = subquery_id;
 	fr->subquery = subquery;
 	fr->function_call_id = function_call_id;
+	fr->function_call = function_call;
 	fr->table_alias = table_alias ? strdup( table_alias ) : NULL;
 	fr->parent_relation_id = parent_relation_id;
 	fr->seq_no = seq_no;
@@ -757,6 +776,10 @@ static void fromRelationFree( FromRelation* fr ) {
 			storedQFree( fr->subquery );
 			fr->subquery = NULL;
 		}
+		if( fr->function_call ) {
+			expressionFree( fr->function_call );
+			fr->function_call = NULL;
+		}
 		free( fr->table_alias );
 		fr->table_alias = NULL;
 		if( fr->on_clause ) {
-- 
2.11.0