<field reporter:label="Query type" name="type" reporter:datatype="text"/>
<field reporter:label="Use ALL" name="use_all" reporter:datatype="bool"/>
<field reporter:label="Use DISTINCT" name="use_distinct" reporter:datatype="bool"/>
- <field reporter:label="FROM Clause" name="from_clause" reporter:datatype="int"/>
- <field reporter:label="WHERE Clause" name="where_clause" reporter:datatype="int"/>
- <field reporter:label="HAVING Clause" name="having_clause" reporter:datatype="int"/>
- <field reporter:label="LIMIT count" name="limit_count" reporter:datatype="int"/>
- <field reporter:label="OFFSET count" name="offset_count" reporter:datatype="int"/>
- </fields>
- <links>
+ <field reporter:label="FROM Clause" name="from_clause" reporter:datatype="link"/>
+ <field reporter:label="WHERE Clause" name="where_clause" reporter:datatype="link"/>
+ <field reporter:label="HAVING Clause" name="having_clause" reporter:datatype="link"/>
+ <field reporter:label="LIMIT count" name="limit_count" reporter:datatype="link"/>
+ <field reporter:label="OFFSET count" name="offset_count" reporter:datatype="link"/>
+ </fields>
+ <links>
+ <link field="from_clause" reltype="has_a" key="id" map="" class="qfr"/>
+ <link field="having_clause" reltype="has_a" key="id" map="" class="qxp"/>
+ <link field="where_clause" reltype="has_a" key="id" map="" class="qxp"/>
+ <link field="limit_count" reltype="has_a" key="id" map="" class="qxp"/>
+ <link field="offset_count" reltype="has_a" key="id" map="" class="qxp"/>
</links>
<permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
</permacrud>
QSeq* child_list;
Expression* having_clause;
OrderItem* order_by_list;
+ Expression* limit_count;
+ Expression* offset_count;
};
typedef enum {
static void buildOrderBy( BuildSQLState* state, const OrderItem* ord_list );
static void buildCase( BuildSQLState* state, const Expression* expr );
static void buildExpression( BuildSQLState* state, const Expression* expr );
+
static void buildFunction( BuildSQLState* state, const Expression* exp );
static int subexp_count( const Expression* expr );
static void buildTypicalFunction( BuildSQLState* state, const Expression* expr );
static void buildExtract( BuildSQLState* state, const Expression* expr );
+
static void buildSeries( BuildSQLState* state, const Expression* subexp_list, const char* op );
static void buildBindVar( BuildSQLState* state, const BindVar* bind );
static void buildScalar( BuildSQLState* state, int numeric, const jsonObject* obj );
return;
}
- // To do: get SELECT list; just a stub here
+ // Get SELECT list
buffer_add( state->sql, "SELECT" );
incr_indent( state );
buildSelectList( state, query->select_list );
}
}
- // To do: Build LIMIT clause, if there is one
+ // Build LIMIT clause, if there is one
+ if( query->limit_count ) {
+ add_newline( state );
+ buffer_add( state->sql, "LIMIT " );
+ buildExpression( state, query->limit_count );
+ }
- // To do: Build OFFSET clause, if there is one
+ // Build OFFSET clause, if there is one
+ if( query->offset_count ) {
+ add_newline( state );
+ buffer_add( state->sql, "OFFSET " );
+ buildExpression( state, query->offset_count );
+ }
state->error = 0;
}
buffer_add( state->sql, "LOCALTIME " );
else if( !strcasecmp( expr->function_name, "LOCALTIMESTAMP" ) && ! expr->subexp_list )
buffer_add( state->sql, "LOCALTIMESTAMP " );
- else
+ else if( !strcasecmp( expr->function_name, "TRIM" )) {
+ int arg_count = subexp_count( expr );
+
+ if( (arg_count != 2 && arg_count != 3 ) || expr->subexp_list->type != EXP_STRING )
+ buildTypicalFunction( state, expr );
+ else {
+ sqlAddMsg( state,
+ "TRIM function not supported in expr # %d; use ltrim() and/or rtrim()",
+ expr->id );
+ state->error = 1;
+ return;
+ }
+ } else
buildTypicalFunction( state, expr ); // Not a special exception.
if( expr->column_name ) {
@return The number of subexpressions.
*/
static int subexp_count( const Expression* expr ) {
+ if( !expr )
+ return 0;
+
int count = 0;
const Expression* sub = expr->subexp_list;
while( sub ) {
StoredQ* sq = NULL;
dbi_result result = dbi_conn_queryf( state->dbhandle,
- "SELECT id, type, use_all, use_distinct, from_clause, where_clause, having_clause "
- "FROM query.stored_query WHERE id = %d;", query_id );
+ "SELECT id, type, use_all, use_distinct, from_clause, where_clause, having_clause, "
+ "limit_count, offset_count FROM query.stored_query WHERE id = %d;", query_id );
if( result ) {
if( dbi_result_first_row( result ) ) {
sq = constructStoredQ( state, result );
else
having_clause_id = dbi_result_get_int_idx( result, 7 );
+ int limit_count_id;
+ if( dbi_result_field_is_null_idx( result, 8 ) )
+ limit_count_id = -1;
+ else
+ limit_count_id = dbi_result_get_int_idx( result, 8 );
+
+ int offset_count_id;
+ if( dbi_result_field_is_null_idx( result, 9 ) )
+ offset_count_id = -1;
+ else
+ offset_count_id = dbi_result_get_int_idx( result, 9 );
+
FromRelation* from_clause = NULL;
if( QT_SELECT == type ) {
// A SELECT query needs a FROM clause; go get it
}
}
+ // Get the HAVING clause, if there is one
Expression* having_clause = NULL;
if( having_clause_id != -1 ) {
having_clause = getExpression( state, having_clause_id );
"Unable to fetch HAVING expression for query id = %d", id ));
expressionFree( where_clause );
freeQSeqList( child_list );
- fromRelationFree( from_clause );
selectListFree( select_list );
+ fromRelationFree( from_clause );
state->error = 1;
return NULL;
}
expressionFree( having_clause );
expressionFree( where_clause );
freeQSeqList( child_list );
- fromRelationFree( from_clause );
selectListFree( select_list );
+ fromRelationFree( from_clause );
return NULL;
}
+ // Get the LIMIT clause, if there is one
+ Expression* limit_count = NULL;
+ if( limit_count_id != -1 ) {
+ limit_count = getExpression( state, limit_count_id );
+ if( ! limit_count ) {
+ // shouldn't happen due to foreign key constraint
+ osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
+ "Unable to fetch LIMIT expression for query id = %d", id ));
+ orderItemListFree( order_by_list );
+ freeQSeqList( child_list );
+ selectListFree( select_list );
+ fromRelationFree( from_clause );
+ state->error = 1;
+ return NULL;
+ }
+ }
+
+ // Get the OFFSET clause, if there is one
+ Expression* offset_count = NULL;
+ if( offset_count_id != -1 ) {
+ offset_count = getExpression( state, offset_count_id );
+ if( ! offset_count ) {
+ // shouldn't happen due to foreign key constraint
+ osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
+ "Unable to fetch OFFSET expression for query id = %d", id ));
+ expressionFree( limit_count );
+ orderItemListFree( order_by_list );
+ freeQSeqList( child_list );
+ selectListFree( select_list );
+ fromRelationFree( from_clause );
+ state->error = 1;
+ return NULL;
+ }
+ }
+
// Allocate a StoredQ: from the free list if possible, from the heap if necessary
StoredQ* sq;
sq->child_list = child_list;
sq->having_clause = having_clause;
sq->order_by_list = order_by_list;
+ sq->limit_count = limit_count;
+ sq->offset_count = offset_count;
return sq;
}
orderItemListFree( sq->order_by_list );
sq->order_by_list = NULL;
}
- if( sq->having_clause )
+ if( sq->having_clause ) {
expressionFree( sq->having_clause );
+ sq->having_clause = NULL;
+ }
+ if( sq->limit_count ) {
+ expressionFree( sq->limit_count );
+ sq->limit_count = NULL;
+ }
+ if( sq->offset_count ) {
+ expressionFree( sq->offset_count );
+ sq->offset_count = NULL;
+ }
// Stick the empty husk on the free list for potential reuse
sq->next = free_storedq_list;
install_date TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);
-INSERT INTO config.upgrade_log (version) VALUES ('0335'); -- dbs
+INSERT INTO config.upgrade_log (version) VALUES ('0336'); -- Scott McKellar
CREATE TABLE config.bib_source (
id SERIAL PRIMARY KEY,
where_clause INT, --REFERENCES query.expression
--DEFERRABLE INITIALLY DEFERRED,
having_clause INT, --REFERENCES query.expression
+ --DEFERRABLE INITIALLY DEFERRED,
+ limit_count INT, --REFERENCES query.expression
+ --DEFERRABLE INITIALLY DEFERRED,
+ offset_count INT --REFERENCES query.expression
--DEFERRABLE INITIALLY DEFERRED
- limit_count INT,
- offset_count INT
);
-- (Foreign keys to be defined later after other tables are created)
REFERENCES query.expression( id )
DEFERRABLE INITIALLY DEFERRED;
+ALTER TABLE query.stored_query
+ ADD FOREIGN KEY ( limit_count )
+ REFERENCES query.expression( id )
+ DEFERRABLE INITIALLY DEFERRED;
+
+ALTER TABLE query.stored_query
+ ADD FOREIGN KEY ( offset_count )
+ REFERENCES query.expression( id )
+ DEFERRABLE INITIALLY DEFERRED;
+
CREATE TABLE query.case_branch (
id SERIAL PRIMARY KEY,
parent_expr INT NOT NULL REFERENCES query.expression
--- /dev/null
+BEGIN;
+
+INSERT INTO config.upgrade_log (version) VALUES ('0336'); -- Scott McKellar
+
+ALTER TABLE query.stored_query
+ ADD FOREIGN KEY ( limit_count )
+ REFERENCES query.expression( id )
+ DEFERRABLE INITIALLY DEFERRED;
+
+ALTER TABLE query.stored_query
+ ADD FOREIGN KEY ( offset_count )
+ REFERENCES query.expression( id )
+ DEFERRABLE INITIALLY DEFERRED;
+
+COMMIT;