/*******************************************************************************
*                                                                       
*N  {logfile_sample.c}  -- demonstrates usage of logile   
*   
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*P  Purpose:
*    This sample C program demonstrates how to create logfile; how to add IDs 
*    into the logfile; and how to apply logfile in query.
*
*   High-level overview - demostrate "select in selection" using logfile:
*    (1) Prepare a layer with 30 rows;
*    (2) Perform an attribute query and store the selection result into a
*        logfile (Add ROWID's into the logfile ). 
*		 ROW1-ROW20 will be selected
*    (3) Perform a spatial query without using the logfile;
		 ROW11-ROW30 will be selected in this step
*    (4) Perform a spatial query(with the same filter as step 3) on the 
*        selection result of step (2) by using the logfile.
*		 ROW11-ROW20 will be selected in this step
*    
*E                                                                 
*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
* How to compile:: 
*	 Please refer section "Build C Samples" in the SDE sample
*
*E
*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
* Usage:
*     logfile_sample {server} {instance} {database} {user} {password} {keywords}  
*
*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*X  Legalese:
*
* Copyright � 2007 ESRI
*
* All rights reserved under the copyright laws of the United States and 
* applicable international laws, treaties, and conventions.
*
* You may freely redistribute and use this sample code, with or without 
* modification, provided you include the original copyright notice and use 
* restrictions.  
*
* Disclaimer:  THE SAMPLE CODE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 
* WARRANTIES, INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ESRI OR 
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
* OR BUSINESS INTERRUPTION) SUSTAINED BY YOU OR A THIRD PARTY, HOWEVER CAUSED 
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 
* TORT ARISING IN ANY WAY OUT OF THE USE OF THIS SAMPLE CODE, EVEN IF ADVISED 
* OF THE POSSIBILITY OF SUCH DAMAGE.
* 
* For additional information, contact:
* Environmental Systems Research Institute, Inc.
* Attn: Contracts and Legal Services Department
* 380 New York Street
* Redlands, California, 92373
* USA
* 
* email: contracts@esri.com
*
*E
****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include "sdetype.h"
#include "sdeerno.h"

#define INTCOL   "INTCOL"
#define STRCOL   "STRCOL"
#define SHPCOL   "SHPCOL"
#define ROWIDCOL "ROWIDCOL"

#define MAX_ROW  30

typedef enum {
  LOGFILE_USAGE_STORE_RESULT/*Store query result to a logfile*/,
  LOGFILE_USAGE_QUERY_LOGFILE/*Apply a exited logfile to the query*/,
  LOGFILE_USAGE_NONE/*Query without any logfile usage*/
} LOGFILE_USAGE;

/* Function macros */
#define check_rc_return_on_failure(c,s,rc,f) \
	{if(rc!= SE_SUCCESS) {check_rc_(c,s,rc,f,__LINE__,__FILE__);return SE_FAILURE; }}

/* Local Function Prototypes */
void check_rc_(SE_CONNECTION Connection, SE_STREAM Stream, LONG rc, 
				 char *comment, LONG line_no, char* file_name);
static LONG S_create_layer(SE_CONNECTION connection,CHAR *table,CHAR *keyword);
static LONG S_insert_rows(SE_CONNECTION  handle,const CHAR *table,LONG num_of_rows);
static LONG S_query_layer(SE_CONNECTION   connection, 
                          const CHAR      *table,
						  const CHAR	  *where,
						  SE_FILTER       *spfilter,
						  LOGFILE_USAGE   logfile_usage,
						  CHAR			  **logfilename);

LONG main(int argc, char *argv[]){
	CHAR   				*server, 
       	       			*user, 
						*passwd, 
						*database,
						*instance,
						*keyword;
	SE_CONNECTION 		conn;
	SE_ERROR 			error;
	LONG				result;
	CHAR				layername[SE_MAX_TABLE_LEN+1];
	CHAR				where[1024];
	CHAR				*logfilename=NULL;
	SE_LAYERINFO		layer;
	SE_COORDREF			coordref;
    SE_ENVELOPE			env;
	SE_SHAPE			filter_shape;
    SE_FILTER			spfilter;  

	if(argc<7){
		printf("Usage %s <server> <instance> <database> <user> <password> <keyword>",argv[0]);
		exit(1);
	}

	server=argv[1];
	instance=argv[2];
	database=argv[3];
	user=argv[4];
	passwd=argv[5];
	keyword=argv[6];

	strcpy(layername,"logfile_sample");

	//Connect to the sde server 
	result = SE_connection_create( server, instance, database, user, passwd, &error, &conn );
	check_rc_return_on_failure (conn,NULL,result,"SE_connection_create");
	printf("Conn: connected to %s:%s as %s\n",server,instance,user);

	/*Create the sample layer*/
	printf("\nCreating sample layer......\n");
	result=S_create_layer(conn,layername,keyword);
	if(result!=SE_SUCCESS)
		return result;

	/*Insert 30 rows into the sample layer*/
	printf("\nInsert 30 rows into the layer......\n");
	result=S_insert_rows(conn,layername,30);
	if(result!=SE_SUCCESS)
		return result;

    /*
	  Perform an attribute query and store the selection result into a
      logfile: ROW1-ROW20 will be selected
    */
	printf("\nQuery the layer( INTCOL>=1 AND INTCOL<=20) and store the result to a logfile ......\n");
	strcpy(where,"INTCOL>=1 AND INTCOL<=20");
	result=S_query_layer(conn,layername,where,NULL,LOGFILE_USAGE_STORE_RESULT,&logfilename); 
	if(result!=SE_SUCCESS)
		return result;

	/*Prepare a spatial filter*/
	//Prepare the filter shape
	result = SE_layerinfo_create (NULL,&layer);
	check_rc_return_on_failure (conn,NULL,result,"SE_layerinfo_create");
	result = SE_coordref_create (&coordref);
	check_rc_return_on_failure (conn,NULL,result,"SE_coordref_create");
	result = SE_layer_get_info (conn,layername,SHPCOL,layer);
	check_rc_return_on_failure (conn,NULL,result,"SE_layer_get_info");
	result = SE_layerinfo_get_coordref (layer,coordref);
	check_rc_return_on_failure (conn,NULL,result,"SE_layerinfo_get_coordref");
	result = SE_shape_create (coordref,&filter_shape);
	check_rc_return_on_failure (conn,NULL,result,"SE_shape_create");
	env.minx=115.0;
	env.miny=115.0;
	env.maxx=300.0;
	env.maxy=300.0;
    result = SE_shape_generate_rectangle(&env,filter_shape);

	//Init the spatial filter 
	strcpy(spfilter.table,layername);
	strcpy(spfilter.column,SHPCOL);
	spfilter.filter_type = SE_SHAPE_FILTER;
	spfilter.truth = TRUE;
	spfilter.filter.shape = filter_shape;
	spfilter.method=SM_ENVP;

    /*
	  Query with the spatial filter but without using the logfile
      logfile: ROW10-ROW30 will be selected
    */
	printf("\nQuery the layer with a spatial filter......\n");
	strcpy(where,"");
	result=S_query_layer(conn,layername,where,&spfilter,LOGFILE_USAGE_NONE,NULL); 
	if(result!=SE_SUCCESS)
		return result;

    /*
	  Query with the spatial filter with the logfile applied
      logfile: ROW10-ROW20 will be selected
    */
	printf("\nQuery the layer with the same spatial filter using the logfile......\n");
	result=S_query_layer(conn,layername,where,&spfilter,LOGFILE_USAGE_QUERY_LOGFILE,&logfilename); 
	if(result!=SE_SUCCESS)
		return result;

	//Clean up
	if(logfilename!=NULL){
		SE_log_delete (conn,logfilename);
		free(logfilename);
	}
	SE_table_delete(conn,layername);
	SE_connection_free(conn);

	return SE_SUCCESS;
}



/***********************************************************************
*
*N  {S_create_layer}  -  create a test layer with provided specification
*
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
*P  Purpose:
*     Create a sample layer with provided specification
*E
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
*A  Parameters:
*     <connection>  ==  (SE_CONNECTION) The connection handle.
*     <table >      ==  (CHAR*) the base table name
*     <keyword >    ==  (CHAR*) the keyword for table creation
*E
***********************************************************************/
static LONG S_create_layer(SE_CONNECTION connection,CHAR *table,CHAR *keyword)
{
	SE_LAYERINFO        layer;
	SHORT               number_of_columns;
	SE_COLUMN_DEF       column_definitions[3];
	SE_COORDREF         coordref;
	LONG                result;
	SE_REGINFO          registration;
	LONG				layer_type;

	/* Create the base table. */
	number_of_columns = 2;
	strcpy (column_definitions[0].column_name,INTCOL);
	column_definitions[0].sde_type = SE_INT32_TYPE;
	column_definitions[0].size = 0;
	column_definitions[0].decimal_digits = 0;
	column_definitions[0].nulls_allowed = TRUE;

	strcpy(column_definitions[1].column_name,STRCOL);
	column_definitions[1].sde_type = SE_STRING_TYPE;
	column_definitions[1].size = 128;
	column_definitions[1].decimal_digits = -1;
	column_definitions[1].nulls_allowed = FALSE;

	//delete the table if already existed
	result = SE_table_delete(connection,table);
	if(result!=SE_TABLE_NOEXIST)
		check_rc_return_on_failure (connection,NULL,result,"SE_table_delete");
	//create the base table
	result = SE_table_create (connection,table,number_of_columns,
							column_definitions,keyword);
	check_rc_return_on_failure (connection,NULL,result,"SE_table_create");

	/* Alter the registration of the table to have an SDE maintained rowid */
	result = SE_reginfo_create (&registration);
	check_rc_return_on_failure (connection,NULL,result,"SE_reginfo_create");
	result = SE_registration_get_info (connection,table,registration);
	check_rc_return_on_failure (connection,NULL,result,"SE_registration_get_info");
	result = SE_reginfo_set_creation_keyword (registration,keyword);
	check_rc_return_on_failure (connection,NULL,result,"SE_reginfo_set_creation_keyword");
	check_rc_return_on_failure (connection,NULL,result,"SE_reginfo_set_description");
	result = SE_reginfo_set_rowid_column (registration,ROWIDCOL,
							   SE_REGISTRATION_ROW_ID_COLUMN_TYPE_SDE);
	check_rc_return_on_failure (connection,NULL,result,"SE_reginfo_set_rowid_column");
	result = SE_registration_alter (connection,registration);
	check_rc_return_on_failure (connection,NULL,result,"SE_registration_alter");

	/* Add the spatial column to the table that will containt polygons*/
	layer_type=SE_AREA_TYPE_MASK | SE_NIL_TYPE_MASK;
	result = SE_coordref_create (&coordref);
	check_rc_return_on_failure (connection,NULL,result,"SE_coordref_create");
	result = SE_coordref_set_xy (coordref,0.0,0.0,10.0);
	check_rc_return_on_failure (connection,NULL,result,"SE_coordref_set_xy");
	SE_coordref_set_precision (coordref,64); 
	check_rc_return_on_failure (connection,NULL,result,"SE_coordref_set_precision");
	result = SE_layerinfo_create (coordref,&layer);
	check_rc_return_on_failure (connection,NULL,result,"SE_layerinfo_create");
	result = SE_layerinfo_set_grid_sizes (layer,100.0,0.0,0.0);
	check_rc_return_on_failure (connection,NULL,result,"SE_layerinfo_set_grid_sizes");
	check_rc_return_on_failure (connection,NULL,result,"SE_layerinfo_set_description");
	result = SE_layerinfo_set_shape_types (layer,layer_type);
	check_rc_return_on_failure (connection,NULL,result,"SE_layerinfo_set_shape_types");
	result = SE_layerinfo_set_spatial_column (layer,table,SHPCOL);
	check_rc_return_on_failure (connection,NULL,result,"SE_layerinfo_set_spatial_column");
	result = SE_layerinfo_set_creation_keyword (layer,keyword);
	check_rc_return_on_failure (connection,NULL,result,"SE_layerinfo_set_creation_keyword");
	result=SE_layerinfo_set_minimum_id(layer,11);
	check_rc_return_on_failure (connection,NULL,result,"SE_layerinfo_set_minimum_id");

	result = SE_layer_create (connection,layer,100,10);
	check_rc_return_on_failure (connection,NULL,result,"SE_layer_create");

	SE_layerinfo_free(layer);
	SE_coordref_free(coordref);
	return(SE_SUCCESS);
}           

/***********************************************************************
*
*N  {S_insert_rows}  -  insert rows into the table
*
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
*P  Purpose:
*   Insert rows into the sample table. 
*E
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
*A  Parameters:
*     <handle>        ==  (SE_CONNECTION) The connection handle.
*     <table >        ==  (CHAR*) the layer name
*     <num_of_row>    ==  (LONG) number of rows to be inserted
*E
***********************************************************************/
static LONG S_insert_rows(SE_CONNECTION  handle,const CHAR *table,LONG num_of_rows)
{
	SE_STREAM       stream;
	LONG            result,row,i;
	SHORT           number_of_columns;
	CHAR            **base_columns;
	SE_LAYERINFO    layer;
	SE_COORDREF     coordref;
	SE_SHAPE        shape;
	SE_POINT        points[5];
	LONG			part_offsets[1];
	SE_INT32        intval;
	CHAR			strval[128];

	/*Init columns names for insert */
	number_of_columns = 3;
	base_columns = (CHAR **) malloc (number_of_columns * sizeof(CHAR *));
	for(i=0;i<number_of_columns;i++)
		base_columns[i]=(CHAR *) malloc (SE_MAX_COLUMN_LEN * sizeof(CHAR));
	strcpy(	base_columns[0],INTCOL);
	strcpy(	base_columns[1],STRCOL);
	strcpy(	base_columns[2],SHPCOL);
	
	/*Prepare a shape object*/
	result = SE_layerinfo_create (NULL,&layer);
	check_rc_return_on_failure (handle,NULL,result,"SE_layerinfo_create");
	result = SE_coordref_create (&coordref);
	check_rc_return_on_failure (handle,NULL,result,"SE_coordref_create");
	result = SE_layer_get_info (handle,table,SHPCOL,layer);
	check_rc_return_on_failure (handle,NULL,result,"SE_layer_get_info");
	result = SE_layerinfo_get_coordref (layer,coordref);
	check_rc_return_on_failure (handle,NULL,result,"SE_layerinfo_get_coordref");
	result = SE_shape_create (coordref,&shape);
	check_rc_return_on_failure (handle,NULL,result,"SE_shape_create");

	/*Prepare the insert stream*/
	result = SE_stream_create (handle,&stream);
	check_rc_return_on_failure (handle,NULL,result,"SE_stream_create");
	result = SE_stream_insert_table (stream,table,number_of_columns,
								   (const CHAR **)base_columns);
	check_rc_return_on_failure (NULL,stream,result,"SE_stream_insert_table");

	/*Inset num_of_rows rows*/
	for (row = 0;row < num_of_rows ;row++)
	{
		/*prepare values for each column*/
		intval=row+1; 
		sprintf(strval,"Row %d",intval);
		//init the shape
		points[0].x= (row+1)*10;
		points[0].y= (row+1)*10;
		points[1].x= (row+2)*10;
		points[1].y= (row+1)*10;
		points[2].x= (row+2)*10;
		points[2].y= (row+2)*10;
		points[3].x= (row+1)*10;
		points[3].y= (row+2)*10;
		points[4].x= (row+1)*10;
		points[4].y= (row+1)*10;
		result=SE_shape_generate_polygon(5, 1,part_offsets,points,NULL,NULL,shape);
		check_rc_return_on_failure (NULL,NULL,result,"SE_shape_generate_polygon");
		
		/*set value for each column*/
		result = SE_stream_set_integer(stream,1,&intval);
		check_rc_return_on_failure (NULL,stream,result,"SE_stream_set_integer");
		result = SE_stream_set_string(stream,2,strval);
		check_rc_return_on_failure (NULL,stream,result,"SE_stream_set_string");
		result = SE_stream_set_shape(stream,3,shape);
		check_rc_return_on_failure (NULL,stream,result,"SE_stream_set_shape");

		result = SE_stream_execute (stream);
		if(result!=SE_SUCCESS){
			SE_stream_free(stream);
			SE_shape_free(shape);
			SE_layerinfo_free(layer);
			SE_coordref_free(coordref);
			free(base_columns);
			check_rc_return_on_failure (NULL,stream,result,"SE_stream_execute");
		}
	}
	
	//free resources
	result = SE_stream_free(stream);
	check_rc_return_on_failure (NULL,stream,result,"SE_stream_free");
	SE_shape_free(shape);
	SE_layerinfo_free(layer);
	SE_coordref_free(coordref);
	for(i=0;i<number_of_columns;i++)
		free(base_columns[i]);
	free(base_columns);
	return(SE_SUCCESS);
}


/***********************************************************************
*
*N  {S_query_layer}  -  query the sample layer
*
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
*P  Purpose:
*   Query the layer with provided where clause, spatial filter. 
*   If need store the query result into a logfile, a new logfile will be
*   created and IDs in the query result will be added to it.
*
*E
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
*A  Parameters:
*     <handle>        ==  (SE_CONNECTION) The connection handle.
*     <table >        ==  (CHAR*) the layer name
*     <where>         ==  (const CHAR*) the where clause
*     <spfilter>      ==  (SE_FILTER) The spatial filter for query
*     <logfile_usage> ==  (LOGFILE_USAGE) logfile usage:
				LOGFILE_USAGE_STORE_RESULT : Store query result to a logfile;
				LOGFILE_USAGE_QUERY_LOGFILE:Apply a exited logfile to the query;
				LOGFILE_USAGE_NONE         :Query without any logfile usage
*     <logfilename>   ==  (CHAR*) The logfile name
*E
***********************************************************************/
static LONG S_query_layer(SE_CONNECTION   connection, 
                          const CHAR      *table,
						  const CHAR	  *where,
						  SE_FILTER       *spfilter,
						  LOGFILE_USAGE   logfile_usage,
						  CHAR			  **logfilename)
{
	LONG				result,i,fetched_rows=0,rowid,intval;
	CHAR				**columns;
	SE_QUERYINFO		qinfo;
	SE_STREAM			query_stream;
	CHAR				orderby[128];
	SHORT				num_of_column;
	SE_LAYERINFO		layer;
	SE_COORDREF			coordref;
	SE_SHAPE			shape;
	CHAR			    strval[128];
	SE_LOGINFO			loginfo;
	SE_LOG				log;
	LONG				idlist[MAX_ROW];//to simplify, we just use a static array here.

	if(logfile_usage==LOGFILE_USAGE_STORE_RESULT){
		/*Init a logfile if we need store the query result*/
		if(logfilename==NULL){
			printf("\tInvalid parameter name found.\n");
			return SE_FAILURE;
		}
		if(*logfilename==NULL){//make a logfile name as needed

			*logfilename=(CHAR *) malloc ((SE_MAX_LOGFILE_NAME_LEN+1) * sizeof(CHAR));
			result = SE_log_make_name (connection, *logfilename);
			check_rc_return_on_failure (connection,NULL,result,"SE_log_make_name");
		}else{//delete a existed logfile name as needed
			result = SE_log_delete( connection, *logfilename );
			check_rc_return_on_failure (connection,NULL,result,"SE_log_delete");
		}
		/*Prepare the logfile for ID storing*/
		result = SE_loginfo_create (&loginfo);
		check_rc_return_on_failure (connection,NULL,result,"SE_loginfo_create");

		result = SE_loginfo_set_name (loginfo,*logfilename);
		check_rc_return_on_failure (connection,NULL,result,"SE_loginfo_set_name");

		result = SE_loginfo_set_target_object(loginfo, SE_LOG_FOR_TABLE, (CHAR*)table,"SHPCOL");
		check_rc_return_on_failure (connection,NULL,result,"SE_loginfo_set_target_object");

		result = SE_loginfo_set_persistence(loginfo, FALSE);
		check_rc_return_on_failure (connection,NULL,result,"SE_loginfo_set_persistence");

		result = SE_log_open_log (connection, loginfo, SE_OUTPUT_MODE, &log);
		check_rc_return_on_failure (connection,NULL,result,"SE_log_open_log");

		printf("\tLogfile %s is ready for ID storing.\n",*logfilename);
	}else if (logfile_usage==LOGFILE_USAGE_QUERY_LOGFILE){
		if(logfilename!=NULL && *logfilename!=NULL){
			result = SE_loginfo_create (&loginfo);
			check_rc_return_on_failure (connection,NULL,result,"SE_loginfo_create");

			//We will do a logfile retrieve to make sure the logfile existing
			result=SE_log_get_by_name (connection,*logfilename,loginfo);
			check_rc_return_on_failure (connection,NULL,result,"SE_log_get_by_name");

			printf("\tQuerying use logfile %s\n",*logfilename);
		}else{
			printf("\tInvalid logfile name found.\n");
			return SE_FAILURE;
		}

	}else if(logfile_usage!=LOGFILE_USAGE_NONE){
		if(logfilename==NULL){
			printf("\tInvalid LOGFILE_USAGE value provided.\n");
			return SE_FAILURE;
		}		
	}

	/*Prepare the query stream*/
	//Init the columns for the query
	num_of_column = 4;
	columns = (CHAR **) malloc (num_of_column * sizeof(CHAR *));
	for(i=0;i<num_of_column;i++)
		columns[i]=(CHAR *) malloc ((SE_MAX_COLUMN_LEN+1) * sizeof(CHAR));
	strcpy(	columns[0],ROWIDCOL);
	strcpy(	columns[1],INTCOL);
	strcpy(	columns[2],STRCOL);
	strcpy( columns[3],SHPCOL);

	//prepare a shape object
	result = SE_layerinfo_create (NULL,&layer);
	check_rc_return_on_failure (connection,NULL,result,"SE_layerinfo_create");
	result = SE_coordref_create (&coordref);
	check_rc_return_on_failure (connection,NULL,result,"SE_coordref_create");
	result = SE_layer_get_info (connection,table,SHPCOL,layer);
	check_rc_return_on_failure (connection,NULL,result,"SE_layer_get_info");
	result = SE_layerinfo_get_coordref (layer,coordref);
	check_rc_return_on_failure (connection,NULL,result,"SE_layerinfo_get_coordref");
	result = SE_shape_create (coordref,&shape);
	check_rc_return_on_failure (connection,NULL,result,"SE_shape_create");

	//Prepare the query
	result=SE_stream_create(connection, &query_stream);
	check_rc_return_on_failure (connection,NULL,result,"SE_stream_create");

	result = SE_queryinfo_create(&qinfo);
	check_rc_return_on_failure (connection,NULL,result,"SE_queryinfo_create");
	result = SE_queryinfo_set_tables (qinfo, 1, (const CHAR**)&table, NULL);
	check_rc_return_on_failure (connection,NULL,result,"SE_queryinfo_set_tables");
	result = SE_queryinfo_set_columns (qinfo, num_of_column, (const CHAR **)columns);
	check_rc_return_on_failure (connection,NULL,result,"SE_queryinfo_set_columns");
	result = SE_queryinfo_set_where_clause(qinfo,where);
	check_rc_return_on_failure (connection,NULL,result,"SE_queryinfo_set_where_clause");
	sprintf(orderby,"order by %s",INTCOL);
	result = SE_queryinfo_set_by_clause(qinfo,orderby);
	check_rc_return_on_failure (connection,NULL,result,"SE_queryinfo_set_by_clause");

	//Apply the spatial filter if there is one
	if(spfilter!=NULL){
		result = SE_stream_set_spatial_constraints (query_stream,SE_OPTIMIZE,FALSE,(SHORT)1,spfilter);
		check_rc_return_on_failure (NULL,query_stream,result,"SE_stream_set_spatial_constraints");
	}

	//Set the logfile for the query stream if we need query a existed logfile
	if(logfile_usage==LOGFILE_USAGE_QUERY_LOGFILE){
		result=SE_queryinfo_set_logfile(qinfo,*logfilename);
	    check_rc_return_on_failure (connection,NULL,result,"SE_queryinfo_set_logfile");
	}

	result = SE_stream_query_with_info (query_stream,qinfo);
	check_rc_return_on_failure (NULL,query_stream,result,"SE_stream_query_with_info");

	/*Execute and fetech features*/
    result = SE_stream_execute (query_stream);
	check_rc_return_on_failure (NULL,query_stream,result,"SE_stream_execute");

	printf("\t%-15s %-15s %-15s\n",ROWIDCOL,INTCOL,STRCOL);
	printf("\t%=============================================\n",ROWIDCOL,INTCOL,STRCOL);
	while(result==SE_SUCCESS){
	   result = SE_stream_fetch (query_stream);
	   if(result!=SE_FINISHED){
		    check_rc_return_on_failure (NULL,query_stream,result,"SE_stream_fetch");
			result = SE_stream_get_integer(query_stream,1,&rowid);
			check_rc_return_on_failure (NULL,query_stream,result,"SE_stream_get_integer");
			result = SE_stream_get_integer(query_stream,2,&intval);
			check_rc_return_on_failure (NULL,query_stream,result,"SE_stream_get_integer");
			result = SE_stream_get_string(query_stream,3,strval);
			check_rc_return_on_failure (NULL,query_stream,result,"SE_stream_get_string");
			result = SE_stream_get_shape(query_stream,4,shape);
			check_rc_return_on_failure (NULL,query_stream,result,"SE_stream_get_shape");
			idlist[fetched_rows++]=rowid;
			printf("\t%-15d %-15d %-15s\n",rowid,intval,strval);
	   }
	}	
	printf("\t---------------------------\n\tFeteched %d rows\n",fetched_rows);

	//Add ID list to logfile and then close it as needed
	if(logfile_usage==LOGFILE_USAGE_STORE_RESULT){
		result = SE_log_add_id_list(connection, log, fetched_rows,idlist); 
		check_rc_return_on_failure (connection,NULL,result,"SE_log_add_id_list");

		result= SE_log_close(connection,log);
		check_rc_return_on_failure (connection,NULL,result,"SE_log_close");
	}

	//free resource
	if(logfile_usage!=LOGFILE_USAGE_NONE)
		SE_loginfo_free(loginfo);
	SE_layerinfo_free (layer);
	SE_coordref_free (coordref);
	SE_shape_free (shape);
	SE_queryinfo_free(qinfo);
	SE_stream_free(query_stream);
	for(i=0;i<num_of_column;i++)
		free(columns[i]);
	free(columns);

	return(SE_SUCCESS);
}



/***********************************************************************
*
*N  {check_rc_}  -  check the returned code
*
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
*P  Purpose:
*     Check returned sde error code and print the error messages.
***********************************************************************/
void check_rc_(SE_CONNECTION Connection, SE_STREAM Stream, LONG rc, 
				 char *comment, LONG line_no, char* file_name) 
{

	SE_ERROR	error;
	CHAR		error_string [SE_MAX_MESSAGE_LENGTH];
	LONG		temp_rc=SE_FAILURE;


	if ((rc != SE_SUCCESS) && (rc != SE_FINISHED)) 
	{
		error_string[0] = '\0';
		SE_error_get_string (rc, error_string);

	    printf ("%s encountered a %d error:\"%s\" \nat line %ld in file %s\n",comment, rc,error_string, line_no, file_name);

		/*Print extended error info, if any */
		if ((SE_DB_IO_ERROR == rc) | (SE_INVALID_WHERE == rc) | (SE_SSA_FUNCTION_ERROR == rc)) 
		{
			if (NULL != Stream) 
			{
				/* Assume this is a stream error */
				temp_rc = SE_stream_get_ext_error (Stream, &error);
			}else if (NULL != Connection) {
				/*Assume this is a connection error */
				temp_rc = SE_connection_get_ext_error (Connection, &error);
			}
			if (SE_SUCCESS == temp_rc)
			{
					printf("Extended error code: %d, extended error string:\n%s\n",
					error.ext_error, error.err_msg1);
			}
		} /*End SE_DB_IO_ERROR */

	} 
}