From a66ff4de2151b3177abb4537e42b1740b5d73b03 Mon Sep 17 00:00:00 2001 From: scottmk Date: Fri, 21 May 2010 14:00:03 +0000 Subject: [PATCH 1/1] Support IS NULL and IS NOT NULL expressions. 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@16470 dcc99617-32d9-48b4-a31d-7c20da2025e4 --- Open-ILS/include/openils/oils_buildq.h | 1 + Open-ILS/src/c-apps/buildSQL.c | 15 ++++++++++++ Open-ILS/src/c-apps/oils_storedq.c | 34 +++++++++++++++++++++++++- 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/Open-ILS/include/openils/oils_buildq.h b/Open-ILS/include/openils/oils_buildq.h index 1d18fc57a3..42ea5f1533 100644 --- a/Open-ILS/include/openils/oils_buildq.h +++ b/Open-ILS/include/openils/oils_buildq.h @@ -154,6 +154,7 @@ typedef enum { EXP_FIELD, EXP_FUNCTION, EXP_IN, + EXP_ISNULL, EXP_NULL, EXP_NUMBER, EXP_OPERATOR, diff --git a/Open-ILS/src/c-apps/buildSQL.c b/Open-ILS/src/c-apps/buildSQL.c index 34b277a851..0951074cf9 100644 --- a/Open-ILS/src/c-apps/buildSQL.c +++ b/Open-ILS/src/c-apps/buildSQL.c @@ -674,6 +674,21 @@ static void buildExpression( BuildSQLState* state, Expression* expr ) { } } break; + case EXP_ISNULL : + if( expr->left_operand ) { + buildExpression( state, expr->left_operand ); + if( state->error ) { + sqlAddMsg( state, "Unable to emit left operand in IS NULL expression # %d", + expr->id ); + break; + } + } + + if( expr->negate ) + buffer_add( state->sql, " IS NOT NULL" ); + else + buffer_add( state->sql, " IS NULL" ); + break; case EXP_NULL : if( expr->negate ) buffer_add( state->sql, "NOT " ); diff --git a/Open-ILS/src/c-apps/oils_storedq.c b/Open-ILS/src/c-apps/oils_storedq.c index 6eac1326eb..6fb97694fc 100644 --- a/Open-ILS/src/c-apps/oils_storedq.c +++ b/Open-ILS/src/c-apps/oils_storedq.c @@ -392,6 +392,12 @@ static QSeq* constructQSeq( BuildSQLState* state, dbi_result result ) { return seq; } +/** + @brief Free a list of QSeq's. + @param seq Pointer to the first in a linked list of QSeq's to be freed. + + Each QSeq goes onto a free list for potential reuse. +*/ static void freeQSeqList( QSeq* seq ) { if( !seq ) return; @@ -1018,6 +1024,12 @@ static void bindVarFree( char* key, void* p ) { } } +/** + @brief Given an id for a row in query.expression, build an Expression struct. + @param Pointer to the query-building context. + @param id ID of a row in query.expression. + @return Pointer to a newly-created Expression if successful, or NULL if not. +*/ static Expression* getExpression( BuildSQLState* state, int id ) { // Check the stack to see if the current expression is nested inside itself. If it is, @@ -1096,6 +1108,8 @@ static Expression* constructExpression( BuildSQLState* state, dbi_result result type = EXP_FUNCTION; else if( !strcmp( type_str, "xin" )) type = EXP_IN; + else if( !strcmp( type_str, "xisnull" )) + type = EXP_ISNULL; else if( !strcmp( type_str, "xnull" )) type = EXP_NULL; else if( !strcmp( type_str, "xnum" )) @@ -1222,6 +1236,23 @@ static Expression* constructExpression( BuildSQLState* state, dbi_result result return NULL; } } + } else if( EXP_ISNULL == type ) { + if( -1 == left_operand_id ) { + osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state, + "Expression # %d IS NULL has no left operand", id )); + state->error = 1; + return NULL; + } + + if( left_operand_id != -1 ) { + left_operand = getExpression( state, left_operand_id ); + if( !left_operand ) { + osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state, + "Unable to get left operand in expression # %d", id )); + state->error = 1; + return NULL; + } + } } else if( EXP_EXIST == type ) { if( -1 == subquery_id ) { osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state, @@ -1481,8 +1512,9 @@ jsonObject* oilsGetColNames( BuildSQLState* state, StoredQ* query ) { // Save the outermost query id for possible use in an error message int id = query->id; - // Find the first SELECT, from which we will take the column names while( query->type != QT_SELECT ) { + // If the query is a UNION, INTERSECT, or EXCEPT, there must be a SELECT in + // there somewhere. Find the first one, and use the SELECT list from that. QSeq* child_list = query->child_list; if( !child_list ) { query = NULL; -- 2.43.2