/***************************************************************************** * -- Oracle Spatial (SDO) support for MapServer -- * * * * Authors: Fernando Simon (fsimon@univali.br) * * Rodrigo Becke Cabral (cabral@univali.br) * * Collaborator: Adriana Gomes Alves * * MapServer: MapServer 4.8-rc1 (cvs) * * Oracle: Oracle 9.2 Spatial Cartridge 9.2 release 9.0.1 * * * ***************************************************************************** = This piece for MapServer was originally developed under the funding of = agreement n.45/00 between CTTMAR/UNIVALI (www.cttmar.univali.br) = and CEPSUL/IBAMA (www.ibama.gov.br). ***************************************************************************** = Current development is funded by CNPq (www.cnpq.br) under = process 401263.03-7 = and FUNCITEC (www.funcitec.rct-sc.br) under process FCTP1523-031. ***************************************************************************** * $Id: maporaclespatial.c,v 1.31 2006/06/01 20:08:42 dan Exp $ * * Revision 1.29 $Date: 2006/06/01 20:08:42 $ fernando * Bug fix: #1593 * * Revision 1.28 2005/10/28 01:09:42 [CVS-TIME] jani * MS RFC 3: Layer vtable architecture (bug 1477) * * Revision 1.27 2005/09/13 [CVS-TIME] fernando * Bug fix: #1343, #1442 and #1469. * * Revision 1.26 2005/04/28 22:19:41 [CVS-TIME] fernando * and Revision 1.25 2005/04/21 15:09:28 [CVS-TIME] julien * Bug fix: #1244 * * Revision 1.22 * and Revision 1.21 2005/02/21 14:08:43 [CVS-TIME] fernando * Added the support for 3D Data. * Bug fix: #1144 * * Revision 1.20 2005/02/14 19:42:44 [CVS-TIME] fernando * and Revision 1.19 2005/02/10 20:27:03 [CVS-TIME] * Bug fix: #1109. * * Revision 1.18 2005/02/04 13:10:46 [CVS-TIME] fernando * Bug fix: #1109, #1110, #1111, #1112, #1136, * #1210, #1211, #1212, #1213. * Cleaned code. * Added debug messages for internal SQL's. * * Revision 1.15 2004/12/20 14:01:10 [CVS-TIME] fernando * Fixed problem with LayerClose function. * Added token NONE for DATA statement. * * Revision 1.14 2004/11/15 20:35:02 [CVS-TIME] dan * Added msLayerIsOpen() to all vector layer types (bug 1051) * * Revision 1.13 2004/11/15 20:35:02 [CVS-TIME] fernando * Fixed declarations problems - Bug #1044 * * Revision 1.12 2004/11/05 20:33:14 [CVS-TIME] fernando * Added debug messages. * * Revision 1.11 2004/10/30 05:15:15 [CVS-TIME] fernando * Connection Pool support. * New query item support. * New improve of performance. * Updated mapfile DATA statement to include more options. * Bug fix from version 1.9 * * Revision 1.10 2004/10/21 04:30:54 [CVS-TIME] frank * MS_CVSID support added. * * Revision 1.9 2004/04/30 13:27:46 [CVS-TIME] fernando * Query item support implemented. * Query map is not being generated yet. * * Revision 1.8 2003/03/18 04:56:28 [CVS-TIME] rodrigo * Updated mapfile DATA statement to include SRID number. * SRID fix in r1.6 proved to be inefficient and time-consuming. * * Revision 1.7 2002/01/19 18:29:25 [CVS-TIME] rodrigo * Fixed bug in SQL statement when using "FILTER" in mapfile. * * Revision 1.6 2001/12/22 18:32:02 [CVS-TIME] rodrigo * Fixed SRID mismatch error. * * Revision 1.5 2001/11/21 22:35:58 [CVS-TIME] rodrigo * Added support for 2D circle geometries (gtype/etype/interpretation): * - (2003/[?00]3/4) * * Revision 1.4 2001/10/22 17:09:03 [CVS-TIME] rodrigo * Added support for mapfile items. * * Revision 1.3 2001/10/18 11:39:04 [CVS-TIME] rodrigo * Added support for the following 2D geometries: * - 2001/1/1 point * - 2001/1/n multipoint * - 2002/2/1 line string * * Revision 1.2 2001/09/28 10:42:29 [GMT-03:00] rodrigo * Added OracleSpatial "partial" support. Displaying only the following * 2D geometries (gtype/etype/interpretation): * - 2001/NULL/NULL point * - 2003/[?00]3/1 simple polygon * - 2003/[?00]3/3 rectangle * * Revisions 1.0/1.1 * OracleSpatial support stubbed in by sdlime. * ***************************************************************************** * * Using OracleSpatial: * - CONNECTIONTYPE oraclespatial * - CONNECTION 'username/password@database' * - DATA 'geometry_column FROM ' * or * DATA 'geometry_column FROM
[USING UNIQUE ' SRID #srid VERSION ]' * can be: * 'FILTER', 'RELATE', GEOMRELATE' or 'NONE' * can be: * '8i', '9i' or '10g' * *
can be: * One database table name * or: * (SELECT stmt) * - Parts of the CONNECTION string may be encrypted, see MS-RFC-18 * ***************************************************************************** * Notices above shall be included in all copies or portions of the software. * This piece is provided "AS IS", without warranties of any kind. Got it? *****************************************************************************/ #include "map.h" #include MS_CVSID("$Id: maporaclespatial.c,v 1.31 2006/06/01 20:08:42 dan Exp $") #ifdef USE_ORACLESPATIAL #include #include #define ARRAY_SIZE 1024 #define QUERY_SIZE 1 #define TEXT_SIZE 256 #define TYPE_OWNER "MDSYS" #define SDO_GEOMETRY TYPE_OWNER".SDO_GEOMETRY" #define SDO_GEOMETRY_LEN strlen( SDO_GEOMETRY ) #define FUNCTION_FILTER 1 #define FUNCTION_RELATE 2 #define FUNCTION_GEOMRELATE 3 #define FUNCTION_NONE 4 #define VERSION_8i 1 #define VERSION_9i 2 #define VERSION_10g 3 #define TOLERANCE 0.001 #define NULLERRCODE 1405 typedef struct { OCINumber x; OCINumber y; OCINumber z; } SDOPointObj; typedef struct { OCINumber gtype; OCINumber srid; SDOPointObj point; OCIArray *elem_info; OCIArray *ordinates; } SDOGeometryObj; typedef struct { OCIInd _atomic; OCIInd x; OCIInd y; OCIInd z; } SDOPointInd; typedef struct { OCIInd _atomic; OCIInd gtype; OCIInd srid; SDOPointInd point; OCIInd elem_info; OCIInd ordinates; } SDOGeometryInd; typedef text item_text[TEXT_SIZE]; typedef item_text item_text_array[ARRAY_SIZE]; typedef item_text item_text_array_query[QUERY_SIZE]; typedef struct { /*Oracle handlers*/ OCIEnv *envhp; OCIError *errhp; OCISvcCtx *svchp; int last_oci_status; text last_oci_error[2048]; } msOracleSpatialHandler; typedef struct { /* Oracle data handlers */ OCIStmt *stmthp; OCIDescribe *dschp; OCIType *tdo; } msOracleSpatialDataHandler; typedef struct { /* oracle handlers */ msOracleSpatialHandler *orahandlers; /* oracle data handlers */ msOracleSpatialDataHandler *oradatahandlers; /* fetch data */ int rows_fetched; int row_num; int row; item_text_array *items; /* items buffer */ item_text_array_query *items_query; /* items buffer */ SDOGeometryObj *obj[ARRAY_SIZE]; /* spatial object buffer */ SDOGeometryInd *ind[ARRAY_SIZE]; /* object indicator */ } msOracleSpatialLayerInfo; /* local prototypes */ static int TRY( msOracleSpatialHandler *hand, sword status ); static int ERROR( char *routine, msOracleSpatialHandler *hand, msOracleSpatialDataHandler *dthand ); static void msSplitLogin( char *connection, mapObj *map, char *username, char *password, char *dblink ); static int msSplitData( char *data, char *geometry_column_name, char *table_name, char* unique, char *srid, int *function, int * version); static void msOCICloseConnection( void *layerinfo ); static msOracleSpatialHandler *msOCISetHandlers( char *username, char *password, char *dblink ); static int msOCISetDataHandlers( msOracleSpatialHandler *hand, msOracleSpatialDataHandler *dthand ); static void msOCICloseDataHandlers ( msOracleSpatialDataHandler *dthand ); static void msOCICloseHandlers( msOracleSpatialHandler *hand ); static void msOCIClearLayerInfo( msOracleSpatialLayerInfo *layerinfo ); static int msOCIGet2DOrdinates( msOracleSpatialHandler *hand, SDOGeometryObj *obj, int s, int e, pointObj *pt ); static int msOCIGet3DOrdinates( msOracleSpatialHandler *hand, SDOGeometryObj *obj, int s, int e, pointObj *pt ); static int msOCIConvertCircle( pointObj *pt ); static void osAggrGetExtent(layerObj *layer, char *query_str, char *geom_column_name, char *table_name); static void osConvexHullGetExtent(layerObj *layer, char *query_str, char *geom_column_name, char *table_name); static void osGeodeticData(int function, int version, char *query_str, char *geom_column_name, char *srid, rectObj rect); static void osNoGeodeticData(int function, int version, char *query_str, char *geom_column_name, char *srid, rectObj rect); static double osCalculateArcRadius(pointObj *pnt); static void osCalculateArc(pointObj *pnt, int data3d, double area, double radius, double npoints, int side, lineObj arcline, shapeObj *shape); static void osGenerateArc(shapeObj *shape, lineObj arcline, lineObj points, int i, int n, int data3d); static void osShapeBounds ( shapeObj *shp ); static void osCloneShape(shapeObj *shape, shapeObj *newshape, int data3d); static void osPointCluster(msOracleSpatialHandler *hand, shapeObj *shape, SDOGeometryObj *obj, int start, int end, lineObj points, int interpretation, int data3d); static void osPoint(msOracleSpatialHandler *hand, shapeObj *shape, SDOGeometryObj *obj, int start, int end, lineObj points, pointObj *pnt, int data3d); static void osClosedPolygon(msOracleSpatialHandler *hand, shapeObj *shape, SDOGeometryObj *obj, int start, int end, lineObj points, int elem_type, int data3d); static void osRectangle(msOracleSpatialHandler *hand, shapeObj *shape, SDOGeometryObj *obj, int start, int end, lineObj points, pointObj *pnt, int data3d); static void osCircle(msOracleSpatialHandler *hand, shapeObj *shape, SDOGeometryObj *obj, int start, int end, lineObj points, pointObj *pnt, int data3d); static void osArcPolygon(msOracleSpatialHandler *hand, shapeObj *shape, SDOGeometryObj *obj, int start, int end, lineObj arcpoints, int data3d); static int osGetOrdinates(msOracleSpatialDataHandler *dthand, msOracleSpatialHandler *hand, shapeObj *shape, SDOGeometryObj *obj, SDOGeometryInd *ind); static int osCheck2DGtype(int pIntGtype); static int osCheck3DGtype(int pIntGtype); /* if an error ocurred call msSetError, sets last_oci_status to MS_FAILURE and return 0; * otherwise returns 1 */ static int TRY( msOracleSpatialHandler *hand, sword status ) { sb4 errcode = 0; if (hand->last_oci_status == MS_FAILURE) return 0; /* error from previous call */ switch (status) { case OCI_ERROR: OCIErrorGet((dvoid *)hand->errhp, (ub4)1, (text *)NULL, &errcode, hand->last_oci_error, (ub4)sizeof(hand->last_oci_error), OCI_HTYPE_ERROR ); if (errcode == NULLERRCODE) { hand->last_oci_error[0] = (text)'\0'; return 1; } hand->last_oci_error[sizeof(hand->last_oci_error)-1] = 0; /* terminate string!? */ break; case OCI_NEED_DATA: strcpy( hand->last_oci_error, "OCI_NEED_DATA" ); break; case OCI_INVALID_HANDLE: strcpy( hand->last_oci_error, "OCI_INVALID_HANDLE" ); break; case OCI_STILL_EXECUTING: strcpy( hand->last_oci_error, "OCI_STILL_EXECUTING"); break; case OCI_CONTINUE: strcpy( hand->last_oci_error, "OCI_CONTINUE" ); break; default: return 1; /* no error */ } /* if I got here, there was an error */ hand->last_oci_status = MS_FAILURE; return 0; /* error! */ } /* check last_oci_status for MS_FAILURE (set by TRY()) if an error ocurred return 1; * otherwise, returns 0 */ static int ERROR( char *routine, msOracleSpatialHandler *hand, msOracleSpatialDataHandler *dthand ) { if (hand->last_oci_status == MS_FAILURE) { /* there was an error */ msSetError( MS_ORACLESPATIALERR, hand->last_oci_error, routine ); return 1; /* error processed */ } else return 0; /* no error */ } /* break layer->connection (username/password@dblink) into username, password and dblink */ static void msSplitLogin( char *connection, mapObj *map, char *username, char *password, char *dblink ) { char *src, *tgt, *conn_decrypted; /* clearup */ *username = *password = *dblink = 0; /* bad 'connection' */ if (connection == NULL) return; /* Decrypt any encrypted token */ conn_decrypted = msDecryptStringTokens(map, connection); if (conn_decrypted == NULL) return; /* ok, split connection */ for( tgt=username, src=conn_decrypted; *src; src++, tgt++ ) if (*src=='/' || *src=='@') break; else *tgt = *src; *tgt = 0; if (*src == '/') { for( tgt=password, ++src; *src; src++, tgt++ ) if (*src == '@') break; else *tgt = *src; *tgt = 0; } if (*src == '@') strcpy( dblink, ++src ); msFree(conn_decrypted); } /* break layer->data into geometry_column_name, table_name and srid */ static int msSplitData( char *data, char *geometry_column_name, char *table_name, char *unique, char *srid, int *function, int *version ) { char *tok_from = "from"; char *tok_using = "using"; char *tok_unique = "unique"; char *tok_srid = "srid"; char *tok_version = "version"; char data_version[3] = ""; char tok_function[11] = ""; int parenthesis, i; char *src = data, *tgt; /* clearup */ *geometry_column_name = *table_name = 0; /* bad 'data' */ if (data == NULL) return 0; /* parsing 'geometry_column_name' */ for( ;*src && isspace( *src ); src++ ); /* skip blanks */ for( tgt=geometry_column_name; *src; src++, tgt++ ) if (isspace( *src )) break; else *tgt = *src; *tgt = 0; /* parsing 'from' */ for( ;*src && isspace( *src ); src++ ) ; /* skip blanks */ for( ;*src && *tok_from && tolower(*src)==*tok_from; src++, tok_from++ ); if (*tok_from != '\0') return 0; /* parsing 'table_name' or '(SELECT stmt)' */ for( ;*src && isspace( *src ); src++ ); /* skip blanks */ for( tgt=table_name, parenthesis=0; *src; src++, tgt++ ) { if (*src == '(') parenthesis++; else if (*src == ')') parenthesis--; else if (parenthesis==0 && isspace( *src )) break; /* stop on spaces */ *tgt = *src; } *tgt = 0; strcpy( unique, "" ); strcpy( srid, "NULL" ); *function = -1; *version = -1; /* parsing 'unique' */ for( ;*src && isspace( *src ); src++ ) ; /* skip blanks */ if (*src != '\0') { /* parse 'using' */ for( ;*src && *tok_using && tolower(*src)==*tok_using; src++, tok_using++ ); if (*tok_using != '\0') return 0; /* parsing 'unique' */ for( ;*src && isspace( *src ); src++ ); /* skip blanks */ for( ;*src && *tok_unique && tolower(*src)==*tok_unique; src++, tok_unique++ ); if (*tok_unique == '\0') { for( ;*src && isspace( *src ); src++ ); /* skip blanks */ if (*src == '\0') return 0; for( tgt=unique; *src; src++, tgt++ ) if (isspace( *src )) break; else *tgt = *src; *tgt = 0; if (*tok_unique != '\0') return 0; } /* parsing 'srid' */ for( ;*src && isspace( *src ); src++ ); /* skip blanks */ for( ;*src && *tok_srid && tolower(*src)==*tok_srid; src++, tok_srid++ ); if (*tok_srid == '\0') { for( ;*src && isspace( *src ); src++ ); /* skip blanks */ if (*src == '\0') return 0; for( tgt=srid; *src; src++, tgt++ ) if (isspace( *src )) break; else *tgt = *src; *tgt = 0; if (*tok_srid != '\0') return 0; } /*parsing function/version */ for( ;*src && isspace( *src ); src++ ); if (*src != '\0') { for( tgt=tok_function; *src; src++, tgt++ ) if (isspace( *src )) break; else *tgt = *src; *tgt = 0; } /*Upcase conversion for the FUNCTION/VERSION token*/ for (i=0; tok_function[i] != '\0'; i++) tok_function[i] = toupper(tok_function[i]); if (strcmp(tok_function, "VERSION")) { if (!strcmp(tok_function, "FILTER") || !strcmp(tok_function, "")) *function = FUNCTION_FILTER; else if(!strcmp(tok_function, "RELATE")) *function = FUNCTION_RELATE; else if (!strcmp(tok_function,"GEOMRELATE")) *function = FUNCTION_GEOMRELATE; else if (!strcmp(tok_function,"NONE")) *function = FUNCTION_NONE; else { *function = -1; return 0; } /*parsing VERSION token when user defined one function*/ for( ;*src && isspace( *src ); src++ ); for( ;*src && *tok_version && tolower(*src)==*tok_version; src++, tok_version++ ); } else { for(tgt = "VERSION";*tgt && *tok_version && toupper(*tgt)==toupper(*tok_version); tgt++, tok_version++ ); *function = FUNCTION_FILTER; } /*parsing version*/ if (*tok_version == '\0') { for( ;*src && isspace( *src ); src++ ); /* skip blanks */ for( tgt=data_version; *src; src++, tgt++ ) if (isspace( *src )) break; else *tgt = *src; *tgt = 0; for (i=0; data_version[i] != '\0'; i++) data_version[i] = tolower(data_version[i]); if (!strcmp(data_version, "8i")) *version = VERSION_8i; else if(!strcmp(data_version, "9i")) *version = VERSION_9i; else if (!strcmp(data_version, "10g")) *version = VERSION_10g; else return 0; } } /* finish parsing */ for( ;*src && isspace( *src ); src++ ); /* skip blanks */ return (*src == '\0'); } static int msOCISetDataHandlers(msOracleSpatialHandler *hand, msOracleSpatialDataHandler *dthand) { int success = 0; OCIParam *paramp = NULL; OCIRef *type_ref = NULL; success = TRY( hand, /* allocate stmthp */ OCIHandleAlloc( (dvoid *)hand->envhp, (dvoid **)&dthand->stmthp, (ub4)OCI_HTYPE_STMT, (size_t)0, (dvoid **)0 ) ) && TRY( hand, /* allocate dschp */ OCIHandleAlloc( hand->envhp, (dvoid **)&dthand->dschp, (ub4)OCI_HTYPE_DESCRIBE, (size_t)0, (dvoid **)0 ) ) && TRY( hand, /* describe SDO_GEOMETRY in svchp (dschp) */ OCIDescribeAny( hand->svchp, hand->errhp, (text *)SDO_GEOMETRY, (ub4)SDO_GEOMETRY_LEN, OCI_OTYPE_NAME, (ub1)1, (ub1)OCI_PTYPE_TYPE, dthand->dschp ) ) && TRY( hand, /* get param for SDO_GEOMETRY */ OCIAttrGet( (dvoid *)dthand->dschp, (ub4)OCI_HTYPE_DESCRIBE, (dvoid *)¶mp, (ub4 *)0, (ub4)OCI_ATTR_PARAM, hand->errhp ) ) && TRY( hand, /* get type_ref for SDO_GEOMETRY */ OCIAttrGet( (dvoid *)paramp, (ub4)OCI_DTYPE_PARAM, (dvoid *)&type_ref, (ub4 *)0, (ub4)OCI_ATTR_REF_TDO, hand->errhp ) ) && TRY( hand, /* get TDO for SDO_GEOMETRY */ OCIObjectPin( hand->envhp, hand->errhp, type_ref, (OCIComplexObject *)0, OCI_PIN_ANY, OCI_DURATION_SESSION, OCI_LOCK_NONE, (dvoid **)&dthand->tdo ) ); return success; } /* connect to database */ static msOracleSpatialHandler *msOCISetHandlers( char *username, char *password, char *dblink ) { int success; msOracleSpatialHandler *hand = (msOracleSpatialHandler *) malloc( sizeof(msOracleSpatialHandler)); memset( hand, 0, sizeof(msOracleSpatialHandler) ); hand->last_oci_status = MS_SUCCESS; hand->last_oci_error[0] = (text)'\0'; success = TRY( hand, /* allocate envhp */ OCIEnvCreate( &hand->envhp, OCI_OBJECT, (dvoid *)0, 0, 0, 0, (size_t) 0, (dvoid **)0 ) ) && TRY( hand, /* allocate errhp */ OCIHandleAlloc( (dvoid *)hand->envhp, (dvoid **)&hand->errhp, (ub4)OCI_HTYPE_ERROR, (size_t)0, (dvoid **)0 ) ) && TRY( hand, /* logon */ OCILogon( hand->envhp, hand->errhp, &hand->svchp, username, strlen(username), password, strlen(password), dblink, strlen(dblink) ) ); if ( !success ) { msSetError( MS_ORACLESPATIALERR, "Cannot create OCI Handlers. " "Connection failure. Check the connection string. " "Error: %s.", "msOracleSpatialLayerOpen()", hand->last_oci_error); msOCICloseHandlers(hand); return NULL; } return hand; } static void msOCICloseHandlers( msOracleSpatialHandler *hand ) { if (hand->svchp != NULL) OCILogoff( hand->svchp, hand->errhp ); if (hand->errhp != NULL) OCIHandleFree( (dvoid *)hand->errhp, (ub4)OCI_HTYPE_ERROR ); if (hand->envhp != NULL) OCIHandleFree( (dvoid *)hand->envhp, (ub4)OCI_HTYPE_ENV ); if (hand != NULL) memset( hand, 0, sizeof (msOracleSpatialHandler)); free(hand); } static void msOCICloseDataHandlers( msOracleSpatialDataHandler *dthand ) { if (dthand->dschp != NULL) OCIHandleFree( (dvoid *)dthand->dschp, (ub4)OCI_HTYPE_DESCRIBE ); if (dthand->stmthp != NULL) OCIHandleFree( (dvoid *)dthand->stmthp, (ub4)OCI_HTYPE_STMT ); if (dthand != NULL) memset( dthand, 0, sizeof (msOracleSpatialDataHandler)); free(dthand); } static void msOCIClearLayerInfo( msOracleSpatialLayerInfo *layerinfo ) { if (layerinfo->items != NULL) free( layerinfo->items ); if (layerinfo->items_query != NULL) free( layerinfo->items_query ); if (layerinfo != NULL) memset( layerinfo, 0, sizeof( msOracleSpatialLayerInfo ) ); free(layerinfo); } /*function taht creates the correct sql for geoditical srid for version 9i*/ static void osGeodeticData(int function, int version, char *query_str, char *geom_column_name, char *srid, rectObj rect) { switch (function) { case FUNCTION_FILTER: { sprintf( query_str + strlen(query_str), "SDO_FILTER( %s, SDO_CS.VIEWPORT_TRANSFORM(MDSYS.SDO_GEOMETRY(" "2003, 0, NULL," "MDSYS.SDO_ELEM_INFO_ARRAY(1,1003,3)," "MDSYS.SDO_ORDINATE_ARRAY(%.9g,%.9g,%.9g,%.9g) ), %s)," "'querytype=window') = 'TRUE'", geom_column_name, rect.minx, rect.miny, rect.maxx, rect.maxy, srid ); break; } case FUNCTION_RELATE: { sprintf( query_str + strlen(query_str), "SDO_RELATE( %s, SDO_CS.VIEWPORT_TRANSFORM(MDSYS.SDO_GEOMETRY(" "2003, 0, NULL," "MDSYS.SDO_ELEM_INFO_ARRAY(1,1003,3)," "MDSYS.SDO_ORDINATE_ARRAY(%.9g,%.9g,%.9g,%.9g) ), %s)," "'mask=anyinteract querytype=window') = 'TRUE'", geom_column_name, rect.minx, rect.miny, rect.maxx, rect.maxy, srid); break; } case FUNCTION_GEOMRELATE: { sprintf( query_str + strlen(query_str), "SDO_GEOM.RELATE( %s, 'anyinteract', SDO_CS.VIEWPORT_TRANSFORM(MDSYS.SDO_GEOMETRY(" "2003, 0, NULL," "MDSYS.SDO_ELEM_INFO_ARRAY(1,1003,3)," "MDSYS.SDO_ORDINATE_ARRAY(%.9g,%.9g,%.9g,%.9g)), %s)," "%f) = 'TRUE' AND %s IS NOT NULL", geom_column_name, rect.minx, rect.miny, rect.maxx, rect.maxy, srid, TOLERANCE, geom_column_name ); break; } case FUNCTION_NONE: { break; } default: { sprintf( query_str + strlen(query_str), "SDO_FILTER( %s, SDO_CS.VIEWPORT_TRANSFORM(MDSYS.SDO_GEOMETRY(" "2003, 0, NULL," "MDSYS.SDO_ELEM_INFO_ARRAY(1,1003,3)," "MDSYS.SDO_ORDINATE_ARRAY(%.9g,%.9g,%.9g,%.9g) ), %s)," "'querytype=window') = 'TRUE'", geom_column_name, rect.minx, rect.miny, rect.maxx, rect.maxy, srid ); } } } /*function that generate the correct sql for no geoditic srid's*/ static void osNoGeodeticData(int function, int version, char *query_str, char *geom_column_name, char *srid, rectObj rect) { switch (function) { case FUNCTION_FILTER: { sprintf( query_str + strlen(query_str), "SDO_FILTER( %s, MDSYS.SDO_GEOMETRY(" "2003, %s, NULL," "MDSYS.SDO_ELEM_INFO_ARRAY(1,1003,3)," "MDSYS.SDO_ORDINATE_ARRAY(%.9g,%.9g,%.9g,%.9g) )," "'querytype=window') = 'TRUE'", geom_column_name, srid, rect.minx, rect.miny, rect.maxx, rect.maxy ); break; } case FUNCTION_RELATE: { if (version == VERSION_10g) { sprintf( query_str + strlen(query_str), "SDO_ANYINTERACT( %s, MDSYS.SDO_GEOMETRY(" "2003, %s, NULL," "MDSYS.SDO_ELEM_INFO_ARRAY(1,1003,3)," "MDSYS.SDO_ORDINATE_ARRAY(%.9g,%.9g,%.9g,%.9g))) = 'TRUE'", geom_column_name, srid, rect.minx, rect.miny, rect.maxx, rect.maxy); } else { sprintf( query_str + strlen(query_str), "SDO_RELATE( %s, MDSYS.SDO_GEOMETRY(" "2003, %s, NULL," "MDSYS.SDO_ELEM_INFO_ARRAY(1,1003,3)," "MDSYS.SDO_ORDINATE_ARRAY(%.9g,%.9g,%.9g,%.9g) )," "'mask=anyinteract querytype=window') = 'TRUE'", geom_column_name, srid, rect.minx, rect.miny, rect.maxx, rect.maxy); } break; } case FUNCTION_GEOMRELATE: { sprintf( query_str + strlen(query_str), "SDO_GEOM.RELATE( %s, 'anyinteract', MDSYS.SDO_GEOMETRY(" "2003, %s, NULL," "MDSYS.SDO_ELEM_INFO_ARRAY(1,1003,3)," "MDSYS.SDO_ORDINATE_ARRAY(%.9g,%.9g,%.9g,%.9g))," "%f) = 'TRUE' AND %s IS NOT NULL", geom_column_name, srid, rect.minx, rect.miny, rect.maxx, rect.maxy, TOLERANCE, geom_column_name ); break; } case FUNCTION_NONE: { break; } default: { sprintf( query_str + strlen(query_str), "SDO_FILTER( %s, MDSYS.SDO_GEOMETRY(" "2003, %s, NULL," "MDSYS.SDO_ELEM_INFO_ARRAY(1,1003,3)," "MDSYS.SDO_ORDINATE_ARRAY(%.9g,%.9g,%.9g,%.9g) )," "'querytype=window') = 'TRUE'", geom_column_name, srid, rect.minx, rect.miny, rect.maxx, rect.maxy ); } } } /* get ordinates from SDO buffer */ static int msOCIGet2DOrdinates( msOracleSpatialHandler *hand, SDOGeometryObj *obj, int s, int e, pointObj *pt ) { double x, y; int i, n, success = 1; boolean exists; OCINumber *oci_number; for( i=s, n=0; i < e && success; i+=2, n++ ) { success = TRY( hand, OCICollGetElem( hand->envhp, hand->errhp, (OCIColl *)obj->ordinates, (sb4)i, (boolean *)&exists, (dvoid *)&oci_number, (dvoid **)0 ) ) && TRY( hand, OCINumberToReal( hand->errhp, oci_number, (uword)sizeof(double), (dvoid *)&x ) ) && TRY( hand, OCICollGetElem( hand->envhp, hand->errhp, (OCIColl *)obj->ordinates, (sb4)i+1, (boolean *)&exists, (dvoid *)&oci_number, (dvoid **)0 ) ) && TRY( hand, OCINumberToReal( hand->errhp, oci_number, (uword)sizeof(double), (dvoid *)&y ) ); if (success) { pt[n].x = x; pt[n].y = y; } } return success ? n : 0; } static int msOCIGet3DOrdinates( msOracleSpatialHandler *hand, SDOGeometryObj *obj, int s, int e, pointObj *pt ) { double x, y; int i, n, success = 1; boolean exists; #ifdef USE_POINT_Z_M double z; boolean numnull; #endif /* USE_POINT_Z_M */ OCINumber *oci_number; for( i=s, n=0; i < e && success; i+=3, n++ ) { success = TRY( hand, OCICollGetElem( hand->envhp, hand->errhp, (OCIColl *)obj->ordinates, (sb4)i, (boolean *)&exists, (dvoid *)&oci_number, (dvoid **)0 ) ) && TRY( hand, OCINumberToReal( hand->errhp, oci_number, (uword)sizeof(double), (dvoid *)&x ) ) && TRY( hand, OCICollGetElem( hand->envhp, hand->errhp, (OCIColl *)obj->ordinates, (sb4)i+1, (boolean *)&exists, (dvoid *)&oci_number, (dvoid **)0 ) ) && TRY( hand, OCINumberToReal( hand->errhp, oci_number, (uword)sizeof(double), (dvoid *)&y ) ) #ifdef USE_POINT_Z_M && TRY( hand, OCICollGetElem( hand->envhp, hand->errhp, (OCIColl *)obj->ordinates, (sb4)i+2, (boolean *)&exists, (dvoid *)&oci_number, (dvoid **)0 ) ) #endif /* USE_POINT_Z_M */ ; #ifdef USE_POINT_Z_M if (success) { success = TRY(hand, OCINumberIsZero( hand->errhp, oci_number, (boolean *)&numnull)); if (success) { success = TRY( hand, OCINumberToReal( hand->errhp, oci_number, (uword)sizeof(double), (dvoid *)&z ) ); } else { hand->last_oci_status = MS_SUCCESS; strcpy( hand->last_oci_error, "Retrieve z value, but NULL value for z. Setting z to 0." ); z = 0; success = 1; } } #endif /* USE_POINT_Z_M */ if (success) { pt[n].x = x; pt[n].y = y; #ifdef USE_POINT_Z_M pt[n].z = z; #endif /* USE_POINT_Z_M */ } } return success ? n : 0; } /* convert three-point circle to two-point rectangular bounds */ static int msOCIConvertCircle( pointObj *pt ) { pointObj ptaux; double dXa, dXb; double ma, mb; double cx, cy, r; int success; dXa = pt[1].x - pt[0].x; success = (fabs( dXa ) > 1e-8); if (!success) { /* switch points 1 & 2 */ ptaux = pt[1]; pt[1] = pt[2]; pt[2] = ptaux; dXa = pt[1].x - pt[0].x; success = (fabs( dXa ) > 1e-8); } if (success) { dXb = pt[2].x - pt[1].x; success = (fabs( dXb ) > 1e-8); if (!success) { /* insert point 2 before point 0 */ ptaux = pt[2]; pt[2] = pt[1]; pt[1] = pt[0]; pt[0] = ptaux; dXb = dXa; /* segment A has become B */ dXa = pt[1].x - pt[0].x; /* recalculate new segment A */ success = (fabs( dXa ) > 1e-8); } } if (success) { ma = (pt[1].y - pt[0].y)/dXa; mb = (pt[2].y - pt[1].y)/dXb; success = (fabs( mb - ma ) > 1e-8); } if (!success) return 0; /* calculate center and radius */ cx = (ma*mb*(pt[0].y - pt[2].y) + mb*(pt[0].x + pt[1].x) - ma*(pt[1].x + pt[2].x))/(2*(mb - ma)); cy = (fabs( ma ) > 1e-8) ? ((pt[0].y + pt[1].y)/2 - (cx - (pt[0].x + pt[1].x)/2)/ma) : ((pt[1].y + pt[2].y)/2 - (cx - (pt[1].x + pt[2].x)/2)/mb); r = sqrt( pow( pt[0].x - cx, 2 ) + pow( pt[0].y - cy, 2 ) ); /* update pt buffer with rectangular bounds */ pt[0].x = cx - r; pt[0].y = cy - r; pt[1].x = cx + r; pt[1].y = cy + r; return 1; } static void osAggrGetExtent(layerObj *layer, char *query_str, char *geom_column_name, char *table_name) { char query_str2[6000]; int i = 0; sprintf( query_str2, "(SELECT"); for( i = 0; i < layer->numitems; ++i ) sprintf( query_str2 + strlen(query_str2), " %s,", layer->items[i] ); sprintf( query_str2 + strlen(query_str2), " %s FROM %s", geom_column_name, table_name); if (layer->filter.string != NULL) sprintf( query_str2 + strlen(query_str2), " WHERE %s", (layer->filter.string)); sprintf( query_str, "SELECT SDO_AGGR_MBR(%s) AS GEOM from %s)", geom_column_name, query_str2); } static void osConvexHullGetExtent(layerObj *layer, char *query_str, char *geom_column_name, char *table_name) { char query_str2[6000]; int i = 0; sprintf( query_str2, "(SELECT"); for( i = 0; i < layer->numitems; ++i ) sprintf( query_str2 + strlen(query_str2), " %s,", layer->items[i] ); sprintf( query_str2 + strlen(query_str2), " %s FROM %s", geom_column_name, table_name); if (layer->filter.string != NULL) sprintf( query_str2 + strlen(query_str2), " WHERE %s", (layer->filter.string)); sprintf( query_str, "SELECT SDO_GEOM.SDO_CONVEXHULL(%s, %f) AS GEOM from %s)", geom_column_name, TOLERANCE, query_str2); } static double osCalculateArcRadius(pointObj *pnt) { double rc; double r1, r2, r3; r1 = sqrt( pow(pnt[0].x-pnt[1].x,2) + pow(pnt[0].y-pnt[1].y,2) ); r2 = sqrt( pow(pnt[1].x-pnt[2].x,2) + pow(pnt[1].y-pnt[2].y,2) ); r3 = sqrt( pow(pnt[2].x-pnt[0].x,2) + pow(pnt[2].y-pnt[0].y,2) ); rc = ( r1+r2+r3 )/2; return ( ( r1*r2*r3 )/( 4*sqrt( rc * (rc-r1) * (rc-r2) * (rc-r3) ) ) ); } static void osCalculateArc(pointObj *pnt, int data3d, double area, double radius, double npoints, int side, lineObj arcline, shapeObj *shape) { double length, ctrl, angle; double divbas, plusbas, cosbas, sinbas = 0; #ifdef USE_POINT_Z_M double zrange = 0; #endif /* USE_POINT_Z_M */ int i = 0; if ( npoints > 0 ) { length = sqrt(((pnt[1].x-pnt[0].x)*(pnt[1].x-pnt[0].x))+((pnt[1].y-pnt[0].y)*(pnt[1].y-pnt[0].y))); ctrl = length/(2*radius); #ifdef USE_POINT_Z_M if (data3d) { zrange = labs(pnt[0].z-pnt[1].z)/npoints; if ((pnt[0].z > pnt[1].z) && side == 1) zrange *= -1; else if ((pnt[0].z < pnt[1].z) && side == 1) zrange = zrange; else if ((pnt[0].z > pnt[1].z) && side != 1) zrange *= -1; else if ((pnt[0].z < pnt[1].z) && side != 1) zrange = zrange; } #endif /* USE_POINT_Z_M */ if( ctrl <= 1 ) { divbas = 2 * asin(ctrl); plusbas = divbas/(npoints); cosbas = (pnt[0].x-pnt[3].x)/radius; sinbas = (pnt[0].y-pnt[3].y)/radius; angle = plusbas; arcline.point = (pointObj *)malloc(sizeof(pointObj)*(npoints+1)); arcline.point[0].x = pnt[0].x; arcline.point[0].y = pnt[0].y; #ifdef USE_POINT_Z_M if (data3d) arcline.point[0].z = pnt[0].z; #endif /* USE_POINT_Z_M */ for (i = 1; i <= npoints; i++) { if( side == 1) { arcline.point[i].x = pnt[3].x + radius * ((cosbas*cos(angle))-(sinbas*sin(angle))); arcline.point[i].y = pnt[3].y + radius * ((sinbas*cos(angle))+(cosbas*sin(angle))); #ifdef USE_POINT_Z_M if (data3d) arcline.point[i].z = pnt[0].z + (zrange*i); #endif /* USE_POINT_Z_M */ } else { if ( side == -1) { arcline.point[i].x = pnt[3].x + radius * ((cosbas*cos(angle))+(sinbas*sin(angle))); arcline.point[i].y = pnt[3].y + radius * ((sinbas*cos(angle))-(cosbas*sin(angle))); #ifdef USE_POINT_Z_M if (data3d) arcline.point[i].z = pnt[0].z + (zrange*i); #endif /* USE_POINT_Z_M */ } else { arcline.point[i].x = pnt[0].x; arcline.point[i].y = pnt[0].y; #ifdef USE_POINT_Z_M if (data3d) arcline.point[i].z = pnt[0].z; #endif /* USE_POINT_Z_M */ } } angle += plusbas; } arcline.numpoints = npoints+1; msAddLine( shape, &arcline ); free (arcline.point); } } else { arcline.point = (pointObj *)malloc(sizeof(pointObj)*(2)); arcline.point[0].x = pnt[0].x; arcline.point[0].y = pnt[0].y; arcline.point[1].x = pnt[1].x; arcline.point[1].y = pnt[1].y; #ifdef USE_POINT_Z_M if(data3d) { arcline.point[0].z = pnt[0].z; arcline.point[1].z = pnt[1].z; } #endif /* USE_POINT_Z_M */ arcline.numpoints = 2; msAddLine( shape, &arcline ); free (arcline.point); } } /* Part of this function was based on Terralib function TeGenerateArc * found in TeGeometryAlgorith.cpp (www.terralib.org). * Part of this function was based on Dr. Ialo (Univali/Cttmar) functions. */ static void osGenerateArc(shapeObj *shape, lineObj arcline, lineObj points, int i, int n, int data3d) { double mult, plus1, plus2, plus3, bpoint; double cx, cy; double radius, side, area, npoints; double dist1 = 0; double dist2 = 0; pointObj point5[4]; mult = ( points.point[i+1].x - points.point[i].x ) * ( points.point[i+2].y - points.point[i].y ) - ( points.point[i+1].y - points.point[i].y ) * ( points.point[i+2].x - points.point[i].x ); if (mult) { /*point5 = (pointObj *)malloc(sizeof(pointObj)*(4));*/ plus1 = points.point[i].x * points.point[i].x + points.point[i].y * points.point[i].y; plus2 = points.point[i+1].x * points.point[i+1].x + points.point[i+1].y * points.point[i+1].y; plus3 = points.point[i+2].x * points.point[i+2].x + points.point[i+2].y * points.point[i+2].y; bpoint = plus1 * ( points.point[i+1].y - points.point[i+2].y ) + plus2 * ( points.point[i+2].y - points.point[i].y ) + plus3 * ( points.point[i].y - points.point[i+1].y ); cx = bpoint / (2.0 * mult); bpoint = plus1 * ( points.point[i+2].x - points.point[i+1].x ) + plus2 * ( points.point[i].x - points.point[i+2].x ) + plus3 * ( points.point[i+1].x - points.point[i].x ); cy = bpoint / (2.0 * mult); dist1 = (points.point[i+1].x - points.point[i].x) * (cy - points.point[i].y); dist2 = (points.point[i+1].y - points.point[i].y) * (cx - points.point[i].x); side = 0; if((dist1-dist2) > 0) side = 1; else { if((dist1-dist2) < 0) side = -1; } point5[0] = points.point[i]; point5[1] = points.point[i+1]; point5[2] = points.point[i+2]; point5[3].x = cx; point5[3].y = cy; radius = osCalculateArcRadius(point5); area = ((points.point[i].x + points.point[i+1].x) * (points.point[i+1].y - points.point[i].y)) + ((points.point[i+1].x + points.point[i+2].x) * (points.point[i+2].y - points.point[i+1].y)); npoints = labs(area/radius); point5[0] = points.point[i]; point5[1] = points.point[i+1]; osCalculateArc(point5, data3d, area, radius, (npoints>1000)?1000:npoints, side, arcline, shape); point5[0] = points.point[i+1]; point5[1] = points.point[i+2]; osCalculateArc(point5, data3d, area, radius, (npoints>1000)?1000:npoints, side, arcline, shape); } else { arcline.point = (pointObj *)malloc(sizeof(pointObj)*(2)); arcline.point[0].x = points.point[i].x; arcline.point[0].y = points.point[i].y; arcline.point[1].x = points.point[i+2].x; arcline.point[1].y = points.point[i+2].y; #ifdef USE_POINT_Z_M if (data3d) { arcline.point[0].z = points.point[i].z; arcline.point[1].z = points.point[i+2].z; } #endif /* USE_POINT_Z_M */ arcline.numpoints = 2; msAddLine( shape, &arcline ); free (arcline.point); } } static void osShapeBounds ( shapeObj *shp ) { int i, f; if ( (shp->numlines > 0) && (shp->line[0].numpoints > 0) ) { shp->bounds.minx = shp->line[0].point[0].x; shp->bounds.maxx = shp->line[0].point[0].x; shp->bounds.miny = shp->line[0].point[0].y; shp->bounds.maxy = shp->line[0].point[0].y; } for ( i = 0 ; i < shp->numlines; i++) { for( f = 0; f < shp->line[i].numpoints; f++) { if (shp->line[i].point[f].x < shp->bounds.minx) shp->bounds.minx = shp->line[i].point[f].x; if (shp->line[i].point[f].x > shp->bounds.maxx) shp->bounds.maxx = shp->line[i].point[f].x; if (shp->line[i].point[f].y < shp->bounds.miny) shp->bounds.miny = shp->line[i].point[f].y; if (shp->line[i].point[f].y > shp->bounds.maxy) shp->bounds.maxy = shp->line[i].point[f].y; } } } static void osCloneShape(shapeObj *shape, shapeObj *newshape, int data3d) { int max_points = 0; int i,f,g; lineObj shapeline = {0, NULL}; for (i = 0; i < shape->numlines; i++) max_points += shape->line[i].numpoints; if (max_points > 0) shapeline.point = (pointObj *)malloc( sizeof(pointObj)*max_points ); g = 0; for ( i = 0 ; i < shape->numlines; i++) { for( f = 0; f < shape->line[i].numpoints && g <= max_points; f++, g++) { shapeline.point[g].x = shape->line[i].point[f].x; shapeline.point[g].y = shape->line[i].point[f].y; #ifdef USE_POINT_Z_M if (data3d) shapeline.point[g].z = shape->line[i].point[f].z; #endif /* USE_POINT_Z_M */ } } if (g) { shapeline.numpoints = g; newshape->type = MS_SHAPE_POLYGON; msAddLine( newshape, &shapeline ); } } static void osPointCluster(msOracleSpatialHandler *hand, shapeObj *shape, SDOGeometryObj *obj, int start, int end, lineObj points, int interpretation, int data3d) { int n; n = (end - start)/2; if (n == interpretation) { points.point = (pointObj *)malloc( sizeof(pointObj)*n ); if (data3d) n = msOCIGet3DOrdinates( hand, obj, start, end, points.point ); else n = msOCIGet2DOrdinates( hand, obj, start, end, points.point ); if (n == interpretation && n>0) { shape->type = MS_SHAPE_POINT; points.numpoints = n; msAddLine( shape, &points ); } free( points.point ); } } static void osPoint(msOracleSpatialHandler *hand, shapeObj *shape, SDOGeometryObj *obj, int start, int end, lineObj points, pointObj *pnt, int data3d) { int n; if (data3d) n = msOCIGet3DOrdinates( hand, obj, start, end, pnt ); else n = msOCIGet2DOrdinates( hand, obj, start, end, pnt ); /* n must be < 5 */ if (n == 1) { shape->type = MS_SHAPE_POINT; points.numpoints = 1; points.point = pnt; msAddLine( shape, &points ); } } static void osClosedPolygon(msOracleSpatialHandler *hand, shapeObj *shape, SDOGeometryObj *obj, int start, int end, lineObj points, int elem_type, int data3d) { int n; n = (end - start)/2; points.point = (pointObj *)malloc( sizeof(pointObj)*n ); if (data3d) n = msOCIGet3DOrdinates( hand, obj, start, end, points.point ); else n = msOCIGet2DOrdinates( hand, obj, start, end, points.point ); if (n > 0) { shape->type = (elem_type==21) ? MS_SHAPE_LINE : MS_SHAPE_POLYGON; points.numpoints = n; msAddLine( shape, &points ); } free( points.point ); } static void osRectangle(msOracleSpatialHandler *hand, shapeObj *shape, SDOGeometryObj *obj, int start, int end, lineObj points, pointObj *pnt, int data3d) { int n; if (data3d) n = msOCIGet3DOrdinates( hand, obj, start, end, pnt ); /* n must be < 5 */ else n = msOCIGet2DOrdinates( hand, obj, start, end, pnt ); /* n must be < 5 */ if (n == 2) { shape->type = MS_SHAPE_POLYGON; points.numpoints = 5; points.point = pnt; /* point5 [0] & [1] contains the lower-left and upper-right points of the rectangle */ pnt[2] = pnt[1]; pnt[1].x = pnt[0].x; pnt[3].x = pnt[2].x; pnt[3].y = pnt[0].y; pnt[4] = pnt[0]; #ifdef USE_POINT_Z_M if (data3d) { pnt[1].z = pnt[0].z; pnt[3].z = pnt[2].z; } #endif /* USE_POINT_Z_M */ msAddLine( shape, &points ); } } static void osCircle(msOracleSpatialHandler *hand, shapeObj *shape, SDOGeometryObj *obj, int start, int end, lineObj points, pointObj *pnt, int data3d) { int n; if (data3d) n = msOCIGet3DOrdinates( hand, obj, start, end, pnt ); /* n must be < 5 */ else n = msOCIGet2DOrdinates( hand, obj, start, end, pnt ); /* n must be < 5 */ if (n == 3) { if (msOCIConvertCircle( pnt )) { shape->type = MS_SHAPE_POINT; points.numpoints = 2; points.point = pnt; msAddLine( shape, &points ); } else { strcpy( hand->last_oci_error, "Points in circle object are colinear" ); hand->last_oci_status = MS_FAILURE; } } } static void osArcPolygon(msOracleSpatialHandler *hand, shapeObj *shape, SDOGeometryObj *obj, int start, int end, lineObj arcpoints, int data3d) { int n, i; lineObj points = {0, NULL}; n = (end - start)/2; points.point = (pointObj *)malloc( sizeof(pointObj)*n ); if (data3d) n = msOCIGet3DOrdinates( hand, obj, start, end, points.point ); else n = msOCIGet2DOrdinates( hand, obj, start, end, points.point ); if (n > 2) { shape->type = MS_SHAPE_LINE; points.numpoints = n; for (i = 0; i < n-2; i = i+2) osGenerateArc(shape, arcpoints, points, i, n, data3d); } free (points.point); } static int osCheck2DGtype(int pIntGtype) { if (pIntGtype > 2000 && pIntGtype < 2008) { if (pIntGtype != 2004) return MS_TRUE; } return MS_FALSE; } static int osCheck3DGtype(int pIntGtype) { if (pIntGtype > 3000 && pIntGtype < 3308) { if (pIntGtype > 3007) pIntGtype-= 300; if (pIntGtype < 3007 && pIntGtype != 3004) return MS_TRUE; } /* * Future version, untested * return (pIntGtype & 2208 && (pIntGtype & 3000 || pIntGtype & 3296) && pIntGtype & 3); */ return MS_FALSE; } static int osGetOrdinates(msOracleSpatialDataHandler *dthand, msOracleSpatialHandler *hand, shapeObj *shape, SDOGeometryObj *obj, SDOGeometryInd *ind) { int gtype, elem_type, compound_type; float compound_lenght, compound_count; ub4 etype; ub4 interpretation; int nelems, nords, data3d; int elem, ord_start, ord_end; boolean exists; OCINumber *oci_number; double x, y; #ifdef USE_POINT_Z_M double z; #endif /* USE_POINT_Z_M */ int success; lineObj points = {0, NULL}; pointObj point5[5]; /* for quick access */ shapeObj newshape; /* for compound polygons */ /*stat the variables for compound polygons*/ compound_lenght = 0; compound_type = 0; compound_count = -1; data3d = 0; if (ind->_atomic != OCI_IND_NULL) /* not a null object */ { nelems = nords = 0; success = TRY( hand, OCICollSize( hand->envhp, hand->errhp, (OCIColl *)obj->elem_info, &nelems ) ) && TRY( hand, OCICollSize( hand->envhp, hand->errhp, (OCIColl *)obj->ordinates, &nords ) ) && TRY( hand, OCINumberToInt( hand->errhp, &(obj->gtype), (uword)sizeof(int), OCI_NUMBER_SIGNED, (dvoid *)>ype ) ); /*&& (nords%2==0 && nelems%3==0);*/ /* check %2==0 for 2D geometries; and %3==0 for element info triplets */ if (success && osCheck2DGtype(gtype)) success = (nords%2==0 && nelems%3==0)?1:0; /* check %2==0 for 2D geometries; and %3==0 for element info triplets */ else if (success && osCheck3DGtype(gtype)) { success = (nords%3==0 && nelems%3==0)?1:0; /* check %2==0 for 2D geometries; and %3==0 for element info triplets */ data3d = 1; } if (success) { /* reading SDO_POINT from SDO_GEOMETRY for a 2D/3D point geometry */ if ((gtype==2001 || gtype==3001) && ind->point._atomic == OCI_IND_NOTNULL && ind->point.x == OCI_IND_NOTNULL && ind->point.y == OCI_IND_NOTNULL) { success = TRY( hand, OCINumberToReal( hand->errhp, &(obj->point.x), (uword)sizeof(double), (dvoid *)&x ) ) && TRY( hand, OCINumberToReal( hand->errhp, &(obj->point.y), (uword)sizeof(double), (dvoid *)&y ) ); if (ERROR( "osGetOrdinates()", hand, dthand )) return MS_FAILURE; shape->type = MS_SHAPE_POINT; points.numpoints = 1; points.point = point5; point5[0].x = x; point5[0].y = y; #ifdef USE_POINT_Z_M if (data3d) { if (ind->point.z == OCI_IND_NOTNULL) { success = TRY( hand, OCINumberToReal( hand->errhp, &(obj->point.z), (uword)sizeof(double), (dvoid *)&z )); if (ERROR( "osGetOrdinates()", hand, dthand )) return MS_FAILURE; else point5[0].z = z; } else point5[0].z = 0; } #endif /* USE_POINT_Z_M */ msAddLine( shape, &points ); return MS_SUCCESS; } /* if SDO_POINT not fetched, proceed reading elements (element info/ordinates) */ success = TRY( hand, OCICollGetElem( hand->envhp, hand->errhp, (OCIColl *)obj->elem_info,(sb4)0, (boolean *)&exists, (dvoid *)&oci_number, (dvoid **)0 ) ) && TRY( hand, OCINumberToInt( hand->errhp, oci_number, (uword)sizeof(ub4), OCI_NUMBER_SIGNED, (dvoid *)&ord_end ) ); elem = 0; ord_end--; /* shifts offset from 1..n to 0..n-1 */ do{ ord_start = ord_end; if (elem+3 >= nelems) /* processing last element */ { ord_end = nords; success = 1; } else /* get start ordinate position for next element which is ord_end for this element */ { success = TRY( hand, OCICollGetElem( hand->envhp, hand->errhp, (OCIColl *)obj->elem_info, (sb4)elem+3, (boolean *)&exists, (dvoid *)&oci_number, (dvoid **)0 ) ) && TRY( hand, OCINumberToInt( hand->errhp, oci_number, (uword)sizeof(ub4), OCI_NUMBER_SIGNED, (dvoid *)&ord_end ) ); ord_end--; /* shifts offset from 1..n to 0..n-1 */ } success = (success && TRY( hand, OCICollGetElem( hand->envhp, hand->errhp, (OCIColl *)obj->elem_info, (sb4)elem+1, (boolean *)&exists, (dvoid *)&oci_number, (dvoid **)0) ) && TRY( hand, OCINumberToInt( hand->errhp, oci_number, (uword)sizeof(ub4), OCI_NUMBER_UNSIGNED, (dvoid *)&etype ) ) && TRY( hand, OCICollGetElem( hand->envhp, hand->errhp, (OCIColl *)obj->elem_info, (sb4)elem+2, (boolean *)&exists, (dvoid *)&oci_number, (dvoid **)0 ) ) && TRY( hand, OCINumberToInt( hand->errhp, oci_number, (uword)sizeof(ub4), OCI_NUMBER_UNSIGNED, (dvoid *)&interpretation ) )); if (ERROR( "osGetOrdinates()", hand, dthand )) return MS_FAILURE; if ( etype == 1005 || etype == 2005 || etype == 4 ) { compound_type = 1; compound_lenght = interpretation; compound_count = 0; msInitShape(&newshape); } elem_type = (etype == 1 && interpretation > 1) ? 10 : ((etype%10)*10 + interpretation); switch (elem_type) { case 10: /* point cluster with 'interpretation'-points */ osPointCluster (hand, shape, obj, ord_start, ord_end, points, interpretation, data3d); break; case 11: /* point type */ osPoint(hand, shape, obj, ord_start, ord_end, points, point5, data3d); break; case 21: /* line string whose vertices are connected by straight line segments */ if (compound_type) osClosedPolygon(hand, &newshape, obj, ord_start, (compound_count= compound_lenght) { osCloneShape(&newshape, shape, data3d); msFreeShape(&newshape); } if (ERROR( "osGetOrdinates()", hand, dthand )) return MS_FAILURE; /* prepare for next cycle */ ord_start = ord_end; elem += 3; if (compound_type) compound_count++; } while (elem < nelems); /* end of element loop */ } /* end of gtype big-if */ } /* end of not-null-object if */ if (compound_type) msFreeShape(&newshape); return MS_SUCCESS; } static void msOCICloseConnection( void *hand ) { msOCICloseHandlers( (msOracleSpatialHandler *)hand ); } /* opens a layer by connecting to db with username/password@database stored in layer->connection */ int msOracleSpatialLayerOpen( layerObj *layer ) { char username[1024], password[1024], dblink[1024]; msOracleSpatialLayerInfo *layerinfo = (msOracleSpatialLayerInfo *)malloc(sizeof(msOracleSpatialLayerInfo)); msOracleSpatialDataHandler *dthand = (msOracleSpatialDataHandler *)malloc(sizeof(msOracleSpatialDataHandler)); msOracleSpatialHandler *hand = (msOracleSpatialHandler *)malloc(sizeof(msOracleSpatialHandler)); memset( hand, 0, sizeof(msOracleSpatialHandler) ); memset( dthand, 0, sizeof(msOracleSpatialDataHandler) ); memset( layerinfo, 0, sizeof(msOracleSpatialLayerInfo) ); if (layer->debug) msDebug("msOracleSpatialLayerOpen called with: %s\n",layer->data); if (layer->layerinfo != NULL) return MS_SUCCESS; if (layer->data == NULL) { msSetError( MS_ORACLESPATIALERR, "Error parsing OracleSpatial DATA variable. Must be:" "'geometry_column FROM table_name [USING UNIQUE SRID srid# FUNCTION]' or " "'geometry_column FROM (SELECT stmt) [USING UNIQUE SRID srid# FUNCTION]'." "If want to set the FUNCTION statement you can use: FILTER, RELATE, GEOMRELATE or NONE.", "msOracleSpatialLayerOpen()"); return MS_FAILURE; } msSplitLogin( layer->connection, layer->map, username, password, dblink ); hand = (msOracleSpatialHandler *) msConnPoolRequest( layer ); if( hand == NULL ) { hand = msOCISetHandlers( username, password, dblink ); if (hand == NULL) { msOCICloseDataHandlers( dthand ); msOCIClearLayerInfo( layerinfo ); return MS_FAILURE; } if ( layer->debug ) msDebug("msOracleSpatialLayerOpen. Shared connection not available. Creating one.\n"); msConnPoolRegister( layer, hand, msOCICloseConnection ); } else { hand->last_oci_status = MS_SUCCESS; hand->last_oci_error[0] = (text)'\0'; } if (!msOCISetDataHandlers(hand, dthand)) { msSetError( MS_ORACLESPATIALERR, "Cannot create OCI LayerInfo. " "Connection failure.", "msOracleSpatialLayerOpen()"); if (layer->debug) msDebug("msOracleSpatialLayerOpen. Cannot create OCI LayerInfo. Connection failure.\n"); msOCICloseDataHandlers ( dthand ); msOCICloseHandlers( hand ); msOCIClearLayerInfo( layerinfo ); } layerinfo->orahandlers = hand; layerinfo->oradatahandlers = dthand; layer->layerinfo = layerinfo; return layer->layerinfo != NULL ? MS_SUCCESS : MS_FAILURE; } /* return MS_TRUE if layer is open, MS_FALSE otherwise.*/ int msOracleSpatialLayerIsOpen(layerObj *layer) { if (layer->layerinfo != NULL) return MS_TRUE; return MS_FALSE; } /* closes the layer, disconnecting from db if connected. layer->layerinfo is freed */ int msOracleSpatialLayerClose( layerObj *layer ) { msOracleSpatialLayerInfo *layerinfo = (msOracleSpatialLayerInfo *)layer->layerinfo; if (layer->debug) msDebug("msOracleSpatialLayerClose was called. Layer connection: %s\n",layer->connection); if (layerinfo != NULL) { if (layer->debug) msDebug("msOracleSpatialLayerClose. Cleaning layerinfo handlers.\n"); msOCICloseDataHandlers( layerinfo->oradatahandlers ); layerinfo->oradatahandlers = NULL; if (layer->debug) msDebug("msOracleSpatialLayerClose. Cleaning Oracle handlers.\n"); msConnPoolRelease( layer, layerinfo->orahandlers ); layerinfo->orahandlers = NULL; msOCIClearLayerInfo( layerinfo ); layer->layerinfo = NULL; } return MS_SUCCESS; } /* create SQL statement for retrieving shapes */ int msOracleSpatialLayerWhichShapes( layerObj *layer, rectObj rect ) { int success, i; int function = 0; int version = 0; char query_str[6000]; char table_name[2000], geom_column_name[100], unique[100], srid[100]; OCIDefine *adtp = NULL, *items[ARRAY_SIZE] = { NULL }; /* get layerinfo */ msOracleSpatialLayerInfo *layerinfo = (msOracleSpatialLayerInfo *)layer->layerinfo; msOracleSpatialDataHandler *dthand = NULL; msOracleSpatialHandler *hand = NULL; if (layer->debug) msDebug("msOracleSpatialLayerWhichShapes was called.\n"); if (layerinfo == NULL) { msSetError( MS_ORACLESPATIALERR, "msOracleSpatialLayerWhichShapes called on unopened layer", "msOracleSpatialLayerWhichShapes()" ); return MS_FAILURE; } else { dthand = (msOracleSpatialDataHandler *)layerinfo->oradatahandlers; hand = (msOracleSpatialHandler *)layerinfo->orahandlers; } /* parse geom_column_name and table_name */ if (!msSplitData( layer->data, geom_column_name, table_name, unique, srid, &function, &version)) { msSetError( MS_ORACLESPATIALERR, "Error parsing OracleSpatial DATA variable. Must be:" "'geometry_column FROM table_name [USING UNIQUE SRID srid# FUNCTION]' or " "'geometry_column FROM (SELECT stmt) [USING UNIQUE SRID srid# FUNCTION]'." "If want to set the FUNCTION statement you can use: FILTER, RELATE, GEOMRELATE or NONE." "Your data statement: %s", "msOracleSpatialLayerWhichShapes()", layer->data ); return MS_FAILURE; } /*Define the unique*/ if (unique[0] == '\0') strcpy( unique, "rownum" ); sprintf( query_str, "SELECT %s", unique ); /* allocate enough space for items */ if (layer->numitems >= 0) { layerinfo->items = (item_text_array *)malloc( sizeof(item_text_array) * (layer->numitems+1) ); if (layerinfo->items == NULL) { msSetError( MS_ORACLESPATIALERR,"Cannot allocate items buffer","msOracleSpatialLayerWhichShapes()" ); return MS_FAILURE; } } /* define SQL query */ for( i=0; i < layer->numitems; ++i ) sprintf( query_str + strlen(query_str), ", %s", layer->items[i] ); sprintf( query_str + strlen(query_str), ", %s FROM %s", geom_column_name, table_name ); if (layer->filter.string != NULL) { if (function == FUNCTION_NONE) sprintf (query_str + strlen(query_str), " WHERE %s ", layer->filter.string); else sprintf (query_str + strlen(query_str), " WHERE %s AND ", layer->filter.string); } else { if (function != FUNCTION_NONE) strcat( query_str, " WHERE " ); } if ((((atol(srid) >= 8192) && (atol(srid) <= 8330)) || (atol(srid) == 2) || (atol(srid) == 5242888) || (atol(srid) == 2000001)) && (version == VERSION_9i)) osGeodeticData(function, version, query_str, geom_column_name, srid, rect); else osNoGeodeticData(function, version, query_str, geom_column_name, srid, rect); if (layer->debug) msDebug("msOracleSpatialLayerWhichShapes. Using this Sql to retrieve the data: %s\n", query_str); /* prepare */ success = TRY( hand, OCIStmtPrepare( dthand->stmthp, hand->errhp, (text *)query_str, (ub4)strlen(query_str), (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT) ); if (success && layer->numitems >= 0) { for( i=0; i <= layer->numitems && success; ++i ) success = TRY( hand, OCIDefineByPos( dthand->stmthp, &items[i], hand->errhp, (ub4)i+1, (dvoid *)layerinfo->items[i], (sb4)TEXT_SIZE, SQLT_STR, (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT ) ); } if (success) { success = TRY( hand, /* define spatial position adtp ADT object */ OCIDefineByPos( dthand->stmthp, &adtp, hand->errhp, (ub4)layer->numitems+2, (dvoid *)0, (sb4)0, SQLT_NTY, (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT) ) && TRY( hand, /* define object tdo from adtp */ OCIDefineObject( adtp, hand->errhp, dthand->tdo, (dvoid **)layerinfo->obj, (ub4 *)0, (dvoid **)layerinfo->ind, (ub4 *)0 ) ) && TRY( hand, /* execute */ OCIStmtExecute( hand->svchp, dthand->stmthp, hand->errhp, (ub4)ARRAY_SIZE, (ub4)0, (OCISnapshot *)NULL, (OCISnapshot *)NULL, (ub4)OCI_DEFAULT ) ) && TRY( hand, /* get rows fetched */ OCIAttrGet( (dvoid *)dthand->stmthp, (ub4)OCI_HTYPE_STMT, (dvoid *)&layerinfo->rows_fetched, (ub4 *)0, (ub4)OCI_ATTR_ROW_COUNT, hand->errhp ) ); } if (!success) { msSetError( MS_ORACLESPATIALERR, "Error: %s . " "Query statement: %s . " "Check your data statement.", "msOracleSpatialLayerWhichShapes()", hand->last_oci_error, query_str ); return MS_FAILURE; } /* should begin processing first row */ layerinfo->row_num = layerinfo->row = 0; return MS_SUCCESS; } /* fetch next shape from previous SELECT stmt (see *WhichShape()) */ int msOracleSpatialLayerNextShape( layerObj *layer, shapeObj *shape ) { SDOGeometryObj *obj; SDOGeometryInd *ind; int success, i; /* get layerinfo */ msOracleSpatialLayerInfo *layerinfo = (msOracleSpatialLayerInfo *)layer->layerinfo; msOracleSpatialDataHandler *dthand = NULL; msOracleSpatialHandler *hand = NULL; if (layerinfo == NULL) { msSetError( MS_ORACLESPATIALERR, "msOracleSpatialLayerWhichShapes called on unopened layer", "msOracleSpatialLayerNextShape()" ); return MS_FAILURE; } else { dthand = (msOracleSpatialDataHandler *)layerinfo->oradatahandlers; hand = (msOracleSpatialHandler *)layerinfo->orahandlers; } /* no rows fetched */ if (layerinfo->rows_fetched == 0) return MS_DONE; do{ /* is buffer empty? */ if (layerinfo->row_num >= layerinfo->rows_fetched) { /* fetch more */ success = TRY( hand, OCIStmtFetch( dthand->stmthp, hand->errhp, (ub4)ARRAY_SIZE, (ub2)OCI_FETCH_NEXT, (ub4)OCI_DEFAULT ) ) && TRY( hand, OCIAttrGet( (dvoid *)dthand->stmthp, (ub4)OCI_HTYPE_STMT, (dvoid *)&layerinfo->rows_fetched, (ub4 *)0, (ub4)OCI_ATTR_ROW_COUNT, hand->errhp ) ); if (!success || layerinfo->rows_fetched == 0) return MS_DONE; if (layerinfo->row_num >= layerinfo->rows_fetched) return MS_DONE; layerinfo->row = 0; /* reset row index */ } /* set obj & ind for current row */ obj = layerinfo->obj[ layerinfo->row ]; ind = layerinfo->ind[ layerinfo->row ]; /* get the items for the shape */ shape->index = atol( (layerinfo->items[0][ layerinfo->row ])); shape->numvalues = layer->numitems; shape->values = (char **)malloc( sizeof(char*) * shape->numvalues ); if (shape->values == NULL) { msSetError( MS_ORACLESPATIALERR, "No memory avaliable to allocate the values", "msOracleSpatialLayerNextShape()" ); return MS_FAILURE; } for( i=0; i < shape->numvalues; ++i ) { shape->values[i] = (char *)malloc(strlen(layerinfo->items[i+1][ layerinfo->row ])+1); if (shape->values[i] == NULL) { msSetError( MS_ORACLESPATIALERR, "No memory avaliable to allocate the items", "msOracleSpatialLayerNextShape()" ); return MS_FAILURE; } else { strcpy(shape->values[i], layerinfo->items[i+1][ layerinfo->row ]); shape->values[i][strlen(layerinfo->items[i+1][ layerinfo->row ])] = '\0'; } } /* increment for next row */ layerinfo->row_num++; layerinfo->row++; /* fetch a layer->type object */ success = osGetOrdinates(dthand, hand, shape, obj, ind); if (success != MS_SUCCESS) return MS_FAILURE; osShapeBounds(shape); }while(shape->type == MS_SHAPE_NULL); return MS_SUCCESS; } int msOracleSpatialLayerInitItemInfo( layerObj *layer ) { int i; int *itemindexes ; if (layer->debug) msDebug("msOracleSpatialLayerInitItemInfo was called.\n"); if (layer->numitems == 0) return MS_SUCCESS; if (layer->iteminfo) free( layer->iteminfo ); if ((layer->iteminfo = (long *)malloc(sizeof(int)*layer->numitems))== NULL) { msSetError(MS_MEMERR, NULL, "msOracleSpatialLayerInitItemInfo()"); return MS_FAILURE; } itemindexes = (int*)layer->iteminfo; for(i=0; i < layer->numitems; i++) itemindexes[i] = i; /*last one is always the geometry one - the rest are non-geom*/ return MS_SUCCESS; } int msOracleSpatialLayerGetItems( layerObj *layer ) { char *rzt = ""; char *flk = ""; int function = 0; int version = 0; int existgeom; int count_item, flk_len, success, i; char query_str[6000], table_name[2000], geom_column_name[100], unique[100], srid[100]; OCIParam *pard = (OCIParam *) 0; msOracleSpatialLayerInfo *layerinfo = (msOracleSpatialLayerInfo *) layer->layerinfo; msOracleSpatialDataHandler *dthand = NULL; msOracleSpatialHandler *hand = NULL; if (layer->debug) msDebug("msOracleSpatialLayerGetItems was called.\n"); if (layerinfo == NULL) { msSetError( MS_ORACLESPATIALERR, "msOracleSpatialLayerGetItems called on unopened layer", "msOracleSpatialLayerGetItems()" ); return MS_FAILURE; } else { dthand = (msOracleSpatialDataHandler *)layerinfo->oradatahandlers; hand = (msOracleSpatialHandler *)layerinfo->orahandlers; } if (!msSplitData(layer->data, geom_column_name, table_name, unique, srid, &function, &version)) { msSetError( MS_ORACLESPATIALERR, "Error parsing OracleSpatial DATA variable. Must be: " "'geometry_column FROM table_name [USING UNIQUE SRID srid# FUNCTION]' or " "'geometry_column FROM (SELECT stmt) [USING UNIQUE SRID srid# FUNCTION]'. " "If want to set the FUNCTION statement you can use: FILTER, RELATE, GEOMRELATE or NONE. " "Your data statement: %s", "msOracleSpatialLayerGetItems()", layer->data ); return MS_FAILURE; } sprintf( query_str, "SELECT * FROM %s", table_name ); success = TRY( hand, OCIStmtPrepare( dthand->stmthp, hand->errhp, (text *)query_str, (ub4)strlen(query_str), (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DESCRIBE_ONLY) ) && TRY( hand, OCIStmtExecute( hand->svchp, dthand->stmthp, hand->errhp, (ub4)QUERY_SIZE, (ub4)0, (OCISnapshot *)NULL, (OCISnapshot *)NULL, (ub4)OCI_DESCRIBE_ONLY ) ) && TRY( hand, OCIAttrGet( (dvoid *)dthand->stmthp, (ub4)OCI_HTYPE_STMT, (dvoid *)&layer->numitems, (ub4 *)0, OCI_ATTR_PARAM_COUNT, hand->errhp) ); if (!success) { msSetError( MS_QUERYERR, "Cannot retrieve column list", "msOracleSpatialLayerGetItems()" ); return MS_FAILURE; } layerinfo->row_num = layerinfo->row = 0; layer->numitems = layer->numitems-1; layer->items = malloc (sizeof(char *) * (layer->numitems)); if (layer->items == NULL) { msSetError( MS_ORACLESPATIALERR,"Cannot allocate items", "msOracleSpatialLayerGetItems()" ); return MS_FAILURE; } if (layer->numitems > 0) { layerinfo->items_query = (item_text_array_query *)malloc( sizeof(item_text_array_query) * (layer->numitems) ); if (layerinfo->items_query == NULL) { msSetError( MS_ORACLESPATIALERR,"Cannot allocate items buffer", "msOracleSpatialLayerGetItems()" ); return MS_FAILURE; } } count_item = 0; existgeom = 0; /*Upcase conversion for the geom_column_name*/ for (i=0; geom_column_name[i] != '\0'; i++) geom_column_name[i] = toupper(geom_column_name[i]); /*Retrive columns name from the user table*/ for (i = 0; i <= layer->numitems; i++) { success = TRY( hand, OCIParamGet ((dvoid*) dthand->stmthp, (ub4)OCI_HTYPE_STMT,hand->errhp,(dvoid*)&pard, (ub4)i+1)) && TRY( hand, OCIAttrGet ((dvoid *) pard,(ub4) OCI_DTYPE_PARAM,(dvoid*)&rzt,(ub4 *)&flk_len, (ub4) OCI_ATTR_NAME, hand->errhp )); flk = (char *)malloc(sizeof(char*) * flk_len+1); if (flk == NULL) { msSetError( MS_ORACLESPATIALERR, "No memory avaliable to allocate the items", "msOracleSpatialLayerGetItems()" ); return MS_FAILURE; } else { strncpy(flk, rzt, flk_len); flk[flk_len] = '\0'; } /*Comapre the column name (flk) with geom_column_name and ignore with true*/ if (strcmp(flk, geom_column_name) != 0) { layer->items[count_item] = (char *)malloc(sizeof(char) * flk_len+1); if (layer->items[count_item] == NULL) { msSetError( MS_ORACLESPATIALERR, "No memory avaliable to allocate the items buffer", "msOracleSpatialLayerGetItems()" ); return MS_FAILURE; } else { strcpy(layer->items[count_item], flk); } count_item++; } else existgeom = 1; strcpy( rzt, "" ); free(flk); /* Better?!*/ flk_len = 0; } if (!(existgeom)) { msSetError (MS_ORACLESPATIALERR, "No geometry column, check stmt", "msOracleSpatialLayerGetItems()" ); return MS_FAILURE; } return msOracleSpatialLayerInitItemInfo( layer ); } int msOracleSpatialLayerGetShape( layerObj *layer, shapeObj *shape, long record ) { char query_str[6000], table_name[2000], geom_column_name[100], unique[100], srid[100]; int success, i; int function = 0; int version = 0; OCIDefine *adtp = NULL, *items[QUERY_SIZE] = { NULL }; SDOGeometryObj *obj = NULL; SDOGeometryInd *ind = NULL; sb2 *nullind = NULL; msOracleSpatialLayerInfo *layerinfo = (msOracleSpatialLayerInfo *)layer->layerinfo; msOracleSpatialDataHandler *dthand = NULL; msOracleSpatialHandler *hand = NULL; if (layer->debug) msDebug("msOracleSpatialLayerGetShape was called. Using the record = %ld.\n", record); if (layerinfo == NULL) { msSetError( MS_ORACLESPATIALERR, "msOracleSpatialLayerGetShape called on unopened layer","msOracleSpatialLayerGetShape()" ); return MS_FAILURE; } else { dthand = (msOracleSpatialDataHandler *)layerinfo->oradatahandlers; hand = (msOracleSpatialHandler *)layerinfo->orahandlers; } /* allocate enough space for items */ if (layer->numitems > 0) { layerinfo->items_query = (item_text_array_query *)malloc( sizeof(item_text_array_query) * (layer->numitems) ); nullind = (sb2 *)malloc( sizeof(sb2) * (layer->numitems) ); if (layerinfo->items_query == NULL) { msSetError( MS_ORACLESPATIALERR, "Cannot allocate items buffer", "msOracleSpatialLayerGetShape()" ); return MS_FAILURE; } } if (!msSplitData( layer->data, geom_column_name, table_name, unique, srid, &function, &version )) { msSetError( MS_ORACLESPATIALERR, "Error parsing OracleSpatial DATA variable. Must be: " "'geometry_column FROM table_name [USING UNIQUE SRID srid# FUNCTION]' or " "'geometry_column FROM (SELECT stmt) [USING UNIQUE SRID srid# FUNCTION]'. " "If want to set the FUNCTION statement you can use: FILTER, RELATE, GEOMRELATE or NONE. " "Your data statement: %s", "msOracleSpatialLayerGetShape()", layer->data ); return MS_FAILURE; } /*Define the first query to retrive itens*/ if (unique[0] == '\0') { msSetError( MS_ORACLESPATIALERR, "Error parsing OracleSpatial DATA variable for query. To execute " "query functions you need to define one " "unique column [USING UNIQUE <#column>]", "msOracleSpatialLayerGetShape()" ); return MS_FAILURE; } else sprintf( query_str, "SELECT"); /*Define the query*/ for( i = 0; i < layer->numitems; ++i ) sprintf( query_str + strlen(query_str), " %s,", layer->items[i] ); sprintf( query_str + strlen(query_str), " %s FROM %s WHERE %s = %ld", geom_column_name, table_name, unique, record); if (layer->filter.string != NULL) sprintf( query_str + strlen(query_str), " AND %s", (layer->filter.string)); if (layer->debug) msDebug("msOracleSpatialLayerGetShape. Sql: %s\n", query_str); /*Prepare the handlers to the query*/ success = TRY( hand,OCIStmtPrepare( dthand->stmthp, hand->errhp, (text *)query_str, (ub4)strlen(query_str), (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT) ); if (success && layer->numitems > 0) { for( i = 0; i < layer->numitems && success; ++i ) success = TRY( hand, OCIDefineByPos( dthand->stmthp, &items[i], hand->errhp, (ub4)i+1, (dvoid *)layerinfo->items_query[i], (sb4)TEXT_SIZE, SQLT_STR, (sb2 *)&nullind[i], (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT ) ); } if(!success) { msSetError( MS_ORACLESPATIALERR, "Error: %s . " "Query statement: %s . " "Check your data statement.", "msOracleSpatialLayerGetShape()", hand->last_oci_error, query_str ); return MS_FAILURE; } if (success) { success = TRY( hand, OCIDefineByPos( dthand->stmthp, &adtp, hand->errhp, (ub4)layer->numitems+1, (dvoid *)0, (sb4)0, SQLT_NTY, (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT) ) && TRY( hand, OCIDefineObject( adtp, hand->errhp, dthand->tdo, (dvoid **)layerinfo->obj, (ub4 *)0, (dvoid **)layerinfo->ind, (ub4 *)0 ) ) && TRY (hand, OCIStmtExecute( hand->svchp, dthand->stmthp, hand->errhp, (ub4)QUERY_SIZE, (ub4)0, (OCISnapshot *)NULL, (OCISnapshot *)NULL, (ub4)OCI_DEFAULT )) && TRY (hand, OCIAttrGet( (dvoid *)dthand->stmthp, (ub4)OCI_HTYPE_STMT, (dvoid *)&layerinfo->rows_fetched, (ub4 *)0, (ub4)OCI_ATTR_ROW_COUNT, hand->errhp )); } if(!success) { msSetError( MS_ORACLESPATIALERR, "Error: %s . " "Query statement: %s ." "Check your data statement.", "msOracleSpatialLayerGetShape()", hand->last_oci_error, query_str ); return MS_FAILURE; } shape->type = MS_SHAPE_NULL; /* no rows fetched */ if (layerinfo->rows_fetched == 0) return (MS_DONE); obj = layerinfo->obj[ layerinfo->row ]; ind = layerinfo->ind[ layerinfo->row ]; /* get the items for the shape */ shape->numvalues = layer->numitems; shape->values = (char **) malloc(sizeof(char *) * layer->numitems); if (shape->values == NULL) { msSetError( MS_ORACLESPATIALERR, "No memory avaliable to allocate the values.", "msOracleSpatialLayerGetShape()" ); return MS_FAILURE; } shape->index = record; for( i = 0; i < layer->numitems; ++i ) { shape->values[i] = (char *)malloc(strlen(layerinfo->items_query[layerinfo->row][i])+1); if (shape->values[i] == NULL) { msSetError( MS_ORACLESPATIALERR, "No memory avaliable to allocate the items buffer.", "msOracleSpatialLayerGetShape()" ); return MS_FAILURE; } else { if (nullind[i] != OCI_IND_NULL) { strcpy(shape->values[i], layerinfo->items_query[layerinfo->row][i]); shape->values[i][strlen(layerinfo->items_query[layerinfo->row][i])] = '\0'; } else { shape->values[i][0] = '\0'; } } } /* increment for next row */ layerinfo->row_num++; layerinfo->row++; /* fetch a layer->type object */ success = osGetOrdinates(dthand, hand, shape, obj, ind); if (success != MS_SUCCESS) { msSetError( MS_ORACLESPATIALERR, "Cannot execute query", "msOracleSpatialLayerGetShape()" ); return MS_FAILURE; } osShapeBounds(shape); layerinfo->row = layerinfo->row_num = 0; return (MS_SUCCESS); } int msOracleSpatialLayerGetExtent(layerObj *layer, rectObj *extent) { char query_str[6000], table_name[2000], geom_column_name[100], unique[100], srid[100]; int success, i; int function = 0; int version = 0; OCIDefine *adtp = NULL, *items[QUERY_SIZE] = { NULL }; SDOGeometryObj *obj = NULL; SDOGeometryInd *ind = NULL; shapeObj shape; rectObj bounds; msOracleSpatialLayerInfo *layerinfo = (msOracleSpatialLayerInfo *)layer->layerinfo; msOracleSpatialDataHandler *dthand = NULL; msOracleSpatialHandler *hand = NULL; if (layer->debug) msDebug("msOracleSpatialLayerGetExtent was called.\n"); if (layerinfo == NULL) { msSetError( MS_ORACLESPATIALERR, "msOracleSpatialLayerGetExtent called on unopened layer","msOracleSpatialLayerGetExtent()"); return MS_FAILURE; } else { dthand = (msOracleSpatialDataHandler *)layerinfo->oradatahandlers; hand = (msOracleSpatialHandler *)layerinfo->orahandlers; } /* allocate enough space for items */ if (layer->numitems > 0) { layerinfo->items_query = (item_text_array_query *)malloc( sizeof(item_text_array_query) * (layer->numitems) ); if (layerinfo->items_query == NULL) { msSetError( MS_ORACLESPATIALERR, "Cannot allocate items buffer", "msOracleSpatialLayerGetExtent()" ); return MS_FAILURE; } } if (!msSplitData( layer->data, geom_column_name, table_name, unique, srid, &function, &version )) { msSetError( MS_ORACLESPATIALERR, "Error parsing OracleSpatial DATA variable. Must be: " "'geometry_column FROM table_name [USING UNIQUE SRID srid# FUNCTION]' or " "'geometry_column FROM (SELECT stmt) [USING UNIQUE SRID srid# FUNCTION]'. " "If want to set the FUNCTION statement you can use: FILTER, RELATE, GEOMRELATE or NONE. " "Your data statement: %s", "msOracleSpatialLayerGetExtent()", layer->data ); return MS_FAILURE; } if (version == VERSION_10g) osAggrGetExtent(layer, query_str, geom_column_name, table_name); else { if (((atol(srid) < 8192) || (atol(srid) > 8330)) && (atol(srid) != 2) && (atol(srid) != 5242888) && (atol(srid) != 2000001)) { if (version == VERSION_9i) osAggrGetExtent(layer, query_str, geom_column_name, table_name); else osConvexHullGetExtent(layer, query_str, geom_column_name, table_name); } else osConvexHullGetExtent(layer, query_str, geom_column_name, table_name); } if (layer->debug) msDebug("msOracleSpatialLayerGetExtent. Using this Sql to retrieve the extent: %s.\n", query_str); /*Prepare the handlers to the query*/ success = TRY( hand,OCIStmtPrepare( dthand->stmthp, hand->errhp, (text *)query_str, (ub4)strlen(query_str), (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT) ); if (success && layer->numitems > 0) { for( i = 0; i < layer->numitems && success; ++i ) success = TRY( hand, OCIDefineByPos( dthand->stmthp, &items[i], hand->errhp, (ub4)i+1, (dvoid *)layerinfo->items_query[i], (sb4)TEXT_SIZE, SQLT_STR, (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT ) ); } if(!success) { msSetError( MS_ORACLESPATIALERR, "Error: %s . " "Query statement: %s . " "Check your data statement.", "msOracleSpatialLayerGetExtent()", hand->last_oci_error, query_str ); return MS_FAILURE; } if (success) { success = TRY( hand, OCIDefineByPos( dthand->stmthp, &adtp, hand->errhp, (ub4)layer->numitems+1, (dvoid *)0, (sb4)0, SQLT_NTY, (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT) ) && TRY( hand, OCIDefineObject( adtp, hand->errhp, dthand->tdo, (dvoid **)layerinfo->obj, (ub4 *)0, (dvoid **)layerinfo->ind, (ub4 *)0 ) ) && TRY (hand, OCIStmtExecute( hand->svchp, dthand->stmthp, hand->errhp, (ub4)QUERY_SIZE, (ub4)0, (OCISnapshot *)NULL, (OCISnapshot *)NULL, (ub4)OCI_DEFAULT )) && TRY (hand, OCIAttrGet( (dvoid *)dthand->stmthp, (ub4)OCI_HTYPE_STMT, (dvoid *)&layerinfo->rows_fetched, (ub4 *)0, (ub4)OCI_ATTR_ROW_COUNT, hand->errhp )); } if(!success) { msSetError( MS_ORACLESPATIALERR, "Error: %s . " "Query statement: %s ." "Check your data statement.", "msOracleSpatialLayerGetExtent()", hand->last_oci_error, query_str ); return MS_FAILURE; } /* should begin processing first row */ layerinfo->row_num = layerinfo->row = 0; msInitShape( &shape ); do{ /* is buffer empty? */ if (layerinfo->row_num >= layerinfo->rows_fetched) { /* fetch more */ success = TRY( hand, OCIStmtFetch( dthand->stmthp, hand->errhp, (ub4)ARRAY_SIZE, (ub2)OCI_FETCH_NEXT, (ub4)OCI_DEFAULT ) ) && TRY( hand, OCIAttrGet( (dvoid *)dthand->stmthp, (ub4)OCI_HTYPE_STMT, (dvoid *)&layerinfo->rows_fetched, (ub4 *)0, (ub4)OCI_ATTR_ROW_COUNT, hand->errhp ) ); if (!success || layerinfo->rows_fetched == 0) break; if (layerinfo->row_num >= layerinfo->rows_fetched) break; layerinfo->row = 0; /* reset row index */ } /* no rows fetched */ if (layerinfo->rows_fetched == 0) break; obj = layerinfo->obj[ layerinfo->row ]; ind = layerinfo->ind[ layerinfo->row ]; /* get the items for the shape */ shape.numvalues = layer->numitems; shape.values = (char **) malloc(sizeof(char *) * layer->numitems); if (shape.values == NULL) { msSetError( MS_ORACLESPATIALERR, "No memory avaliable to allocate the values.", "msOracleSpatialLayerGetExtent()" ); return MS_FAILURE; } shape.index = layerinfo->row_num; for( i = 0; i < layer->numitems; ++i ) { shape.values[i] = (char *)malloc(strlen(layerinfo->items_query[layerinfo->row][i])+1); if (shape.values[i] == NULL) { msSetError( MS_ORACLESPATIALERR, "No memory avaliable to allocate the items buffer.", "msOracleSpatialLayerGetExtent()" ); return MS_FAILURE; } else { strcpy(shape.values[i], layerinfo->items_query[layerinfo->row][i]); shape.values[i][strlen(layerinfo->items_query[layerinfo->row][i])] = '\0'; } } /* increment for next row */ layerinfo->row_num++; layerinfo->row++; /* fetch a layer->type object */ success = osGetOrdinates(dthand, hand, &shape, obj, ind); if (success != MS_SUCCESS) { msSetError( MS_ORACLESPATIALERR, "Cannot execute query", "msOracleSpatialLayerGetExtent()" ); return MS_FAILURE; } }while(layerinfo->row <= layerinfo->rows_fetched); layerinfo->row = layerinfo->row_num = 0; osShapeBounds(&shape); bounds = shape.bounds; extent->minx = bounds.minx; extent->miny = bounds.miny; extent->maxx = bounds.maxx; extent->maxy = bounds.maxy; msFreeShape(&shape); return(MS_SUCCESS); } void msOracleSpatialLayerFreeItemInfo( layerObj *layer ) { if (layer->debug) msDebug("msOracleSpatialLayerFreeItemInfo was called.\n"); if (layer->iteminfo) free(layer->iteminfo); layer->iteminfo = NULL; /* nothing to do */ } int msOracleSpatialLayerGetAutoStyle( mapObj *map, layerObj *layer, classObj *c, int tile, long record ) { msSetError( MS_ORACLESPATIALERR, "Function not implemented yet", "msLayerGetAutoStyle()" ); return MS_FAILURE; } #else /* OracleSpatial "not-supported" procedures */ int msOracleSpatialLayerOpen(layerObj *layer) { msSetError( MS_ORACLESPATIALERR, "OracleSpatial is not supported", "msOracleSpatialLayerOpen()" ); return MS_FAILURE; } int msOracleSpatialLayerIsOpen(layerObj *layer) { msSetError( MS_ORACLESPATIALERR, "OracleSpatial is not supported", "msOracleSpatialLayerIsOpen()" ); return MS_FALSE; } int msOracleSpatialLayerClose(layerObj *layer) { msSetError( MS_ORACLESPATIALERR, "OracleSpatial is not supported", "msOracleSpatialLayerClose()" ); return MS_FAILURE; } int msOracleSpatialLayerWhichShapes(layerObj *layer, rectObj rect) { msSetError( MS_ORACLESPATIALERR, "OracleSpatial is not supported", "msOracleSpatialLayerWhichShapes()" ); return MS_FAILURE; } int msOracleSpatialLayerNextShape(layerObj *layer, shapeObj *shape) { msSetError( MS_ORACLESPATIALERR, "OracleSpatial is not supported", "msOracleSpatialLayerNextShape()" ); return MS_FAILURE; } int msOracleSpatialLayerGetItems(layerObj *layer) { msSetError( MS_ORACLESPATIALERR, "OracleSpatial is not supported", "msOracleSpatialLayerGetItems()" ); return MS_FAILURE; } int msOracleSpatialLayerGetShape( layerObj *layer, shapeObj *shape, long record ) { msSetError( MS_ORACLESPATIALERR, "OracleSpatial is not supported", "msOracleSpatialLayerGetShape()" ); return MS_FAILURE; } int msOracleSpatialLayerGetExtent(layerObj *layer, rectObj *extent) { msSetError( MS_ORACLESPATIALERR, "OracleSpatial is not supported", "msOracleSpatialLayerGetExtent()" ); return MS_FAILURE; } int msOracleSpatialLayerInitItemInfo(layerObj *layer) { msSetError( MS_ORACLESPATIALERR, "OracleSpatial is not supported", "msOracleSpatialLayerInitItemInfo()" ); return MS_FAILURE; } void msOracleSpatialLayerFreeItemInfo(layerObj *layer) { msSetError( MS_ORACLESPATIALERR, "OracleSpatial is not supported", "msOracleSpatialLayerFreeItemInfo()" ); } int msOracleSpatialLayerGetAutoStyle( mapObj *map, layerObj *layer, classObj *c, int tile, long record ) { msSetError( MS_ORACLESPATIALERR, "OracleSpatial is not supported", "msLayerGetAutoStyle()" ); return MS_FAILURE; } #endif int msOracleSpatialLayerGetShapeVT(layerObj *layer, shapeObj *shape, int tile, long record) { return msOracleSpatialLayerGetShape(layer, shape, record); } int msOracleSpatialLayerInitializeVirtualTable(layerObj *layer) { assert(layer != NULL); assert(layer->vtable != NULL); layer->vtable->LayerInitItemInfo = msOracleSpatialLayerInitItemInfo; layer->vtable->LayerFreeItemInfo = msOracleSpatialLayerFreeItemInfo; layer->vtable->LayerOpen = msOracleSpatialLayerOpen; layer->vtable->LayerIsOpen = msOracleSpatialLayerIsOpen; layer->vtable->LayerWhichShapes = msOracleSpatialLayerWhichShapes; layer->vtable->LayerNextShape = msOracleSpatialLayerNextShape; layer->vtable->LayerGetShape = msOracleSpatialLayerGetShapeVT; layer->vtable->LayerClose = msOracleSpatialLayerClose; layer->vtable->LayerGetItems = msOracleSpatialLayerGetItems; layer->vtable->LayerGetExtent = msOracleSpatialLayerGetExtent; /* layer->vtable->LayerGetAutoStyle, use default */ layer->vtable->LayerCloseConnection = msOracleSpatialLayerClose; layer->vtable->LayerApplyFilterToLayer = msLayerApplyCondSQLFilterToLayer; layer->vtable->LayerSetTimeFilter = msLayerMakePlainTimeFilter; /* layer->vtable->LayerCreateItems, use default */ /* layer->vtable->LayerGetNumFeatures, use default */ return MS_SUCCESS; }