/****************************************************************************** * * Project: MapServer * Purpose: Implements the MySQL/"MyGIS" connection type support. * Author: Attila Csipa * ****************************************************************************** * Copyright (c) 1996-2005 Regents of the University of Minnesota. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies of this Software or works derived from this Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ****************************************************************************** * * $Log: mapmygis.c,v $ * Revision 1.21 2006/05/26 21:46:27 tamas * Moving layerObj.sameconnection and msCheckConnection() internal to the MYGIS data provider. * * Revision 1.20 2005/10/28 01:09:41 jani * MS RFC 3: Layer vtable architecture (bug 1477) * * Revision 1.19 2005/06/14 16:03:33 dan * Updated copyright date to 2005 * * Revision 1.18 2005/04/21 15:09:27 julien * Bug1244: Replace USE_SHAPE_Z_M by USE_POINT_Z_M * * Revision 1.17 2005/04/14 15:17:14 julien * Bug 1244: Remove Z and M from point by default to gain performance. * * Revision 1.16 2005/02/18 03:06:46 dan * Turned all C++ (//) comments into C comments (bug 1238) * * Revision 1.15 2004/12/07 16:56:31 dan * Fixed build error introduced by adding msLayerIsOpen() (bug 1116) * * Revision 1.14 2004/11/15 20:35:02 dan * Added msLayerIsOpen() to all vector layer types (bug 1051) * * Revision 1.13 2004/10/21 04:30:55 frank * Added standardized headers. Added MS_CVSID(). * */ #include "map.h" #include #include #if !defined(_WIN32) #include #endif MS_CVSID("$Id: mapmygis.c,v 1.21 2006/05/26 21:46:27 tamas Exp $") #ifndef FLT_MAX #define FLT_MAX 25000000.0 #endif #ifdef USE_MYGIS #ifndef LITTLE_ENDIAN #define LITTLE_ENDIAN 1 #endif #ifndef BIG_ENDIAN #define BIG_ENDIAN 2 #endif #ifndef _mysql_h #include #endif #include #define ETYPE_POINT 1 #define ETYPE_LINESTRING 2 #define ETYPE_POLYGON 3 #define GTYPE_GEOMETRY 0 #define GTYPE_POINT 1 #define GTYPE_CURVE 2 #define GTYPE_LINESTRING 3 #define GTYPE_SURFACE 4 #define GTYPE_POLYGON 5 #define GTYPE_COLLECTION 6 #define GTYPE_MULTIPOINT 7 #define GTYPE_MULTICURVE 8 #define GTYPE_MULTILINESTRING 9 #define GTYPE_MULTISURFACE 10 #define GTYPE_MULTIPOLYGON 11 #define GTYPE_ANNOTATION 128 #define WKBTYPE_GEOMETRY 0 #define WKBTYPE_POINT 1 #define WKBTYPE_LINESTRING 2 #define WKBTYPE_POLYGON 3 #define WKBTYPE_MULTIPOINT 4 #define WKBTYPE_MULTILINESTRING 5 #define WKBTYPE_MULTIPOLYGON 6 #define WKBTYPE_GEOMETRYCOLLECTION 7 #define MYDEBUG 0 #define SHOWQUERY 0 void mysql_NOTICE_HANDLER(void *arg, const char *message); static char *DATAERRORMESSAGE(char *dataString, char *preamble) { char *message; char tmp[5000]; message = malloc(7000); sprintf(message,"%s",preamble); sprintf(tmp,"Error parsing MYGIS data variable. You specified '%s'.
\nStandard ways of specifiying are :
\n(1) 'geometry_column from geometry_table'
\n(2) 'geometry_column from (<sub query>) as foo using unique <column name> using SRID=<srid#>'

\n
\n", dataString); strcat(message,tmp); sprintf(tmp,"NOTE: for (2) 'using unique' and 'SRID=' are optional, but its highly recommended that you use them!!!

\n
\n"); strcat(message,tmp); sprintf(tmp,"The most common problem with (1) is incorrectly uploading your data. There must be an entry in the geometry_columns table. This will be automatically done if you used the shp2mysql program or created your geometry column with the AddGeometryColumn() MYGIS function.

\n
\n"); strcat(message,tmp); sprintf(tmp,"Another important thing to check is that the MYGIS user specified in the CONNECTION string does have SELECT permissions on the table(s) specified in your DATA string.

\n
\n"); strcat(message,tmp); sprintf(tmp,"If you are using the (2) method, you've probably made a typo.
\nExample: 'the_geom from (select the_geom,oid from mytable) as foo using unique oid using SRID=76'
\nThis is very much like the (1) example. The subquery ('select the_geom,oid from mytable') will be executed, and mapserver will use 'oid' (a postgresql system column) for uniquely specifying a geometry (for mapserver queries). The geometry (the_geom) must have a SRID of 76.

\n
\n"); strcat(message,tmp); sprintf(tmp,"Example: 'roads from (select table1.roads,table1.rd_segment_id,table2.rd_name,table2.rd_type from table1,table2 where table1.rd_segment_id=table2.rd_segment_id) as foo using unique rd_segment_id using SRID=89'

\n
\n"); strcat(message,tmp); sprintf(tmp,"This is a more complex sub-query involving joining two tables. The resulting geometry (column 'roads') has SRID=89, and mapserver will use rd_segment_id to uniquely identify a geometry. The attributes rd_type and rd_name are useable by other parts of mapserver.

\n
\n"); strcat(message,tmp); sprintf(tmp,"To use a view, do something like:
\n' from (SELECT * FROM ) as foo using unique using SRID='
\nFor example: 'the_geom from (SELECT * FROM myview) as foo using unique gid using SRID=-1'

\n
\n"); strcat(message,tmp); sprintf(tmp,"NOTE: for the (2) case, the ' as foo ' is requred. The 'using unique <column>' and 'using SRID=' are case sensitive.
\n "); strcat(message,tmp); sprintf(tmp,"NOTE: 'using unique <column>' would normally be the system column 'oid', but for views and joins you'll almost certainly want to use a real column in one of your tables.

\n"); strcat(message,tmp); sprintf(tmp,"NOTE: you'll want to build a spatial index on your geometric data:

\n"); strcat(message,tmp); sprintf(tmp,"CREATE INDEX <indexname> ON <table> USING GIST (<geometrycolumn> GIST_GEOMETRY_OPS )

\n"); strcat(message,tmp); sprintf(tmp,"You'll also want to put an index on either oid or whatever you used for your unique column:

\n"); strcat(message,tmp); sprintf(tmp,"CREATE INDEX <indexname> ON <table> (<uniquecolumn>)"); strcat(message,tmp); return message; } typedef struct ms_MYGIS_layer_info_t { char *sql; /* sql query to send to DB */ MYSQL mysql,*conn; MYSQL_RES *query_result; MYSQL_RES *query2_result; long row_num; /* what row is the NEXT to be read (for random access) */ long total_num; /* what row is the NEXT to be read (for random access) */ char *query; char *query2; char *fields; /* results from EXPLAIN VERBOSE (or null) */ char *urid_name; /* name of user-specified unique identifier or OID */ char *user_srid; /* zero length = calculate, non-zero means using this value! */ char *table; char *feature; int attriboffset; } msMYGISLayerInfo; int wkbdata = 1; int msMYGISLayerParseData(char *data, char *geom_column_name, char *table_name, char *urid_name,char *user_srid); void mysql_NOTICE_HANDLER(void *arg, const char *message) { char *str,*str2; char *result; if (strstr(message,"QUERY DUMP")) { if ( ((msMYGISLayerInfo *) arg)->fields) { free(((msMYGISLayerInfo *) arg)->fields); /* free up space */ } result = malloc ( 6000) ; ((msMYGISLayerInfo *) arg)->fields = result; result[0] = 0; /* null terminate it */ /* need to parse it a bit */ str = (char *) message; while (str != NULL) { str = strstr(str," :resname "); if (str != NULL) { str++; /* now points at ":" */ str= strstr(str," "); /* now points to last " " */ str++; /* now points to start of next word */ str2 = strstr(str," "); /* points to end of next word */ if (strncmp(str, "<>", (str2-str))) { /* Not a bogus resname */ if (strlen(result) > 0) { strcat(result,","); } strncat(result,str, (str2-str) ); } } } printf("notice returns: %s
\n",result); } } static int gBYTE_ORDER = 0; void end_memcpy(char order, void* dest, void* src, int num) { u_int16_t* shorts=NULL; u_int32_t* longs; if ( (gBYTE_ORDER == LITTLE_ENDIAN && order == 1) || (gBYTE_ORDER == BIG_ENDIAN && order == 0) /* no change required */ ){ } else if ((gBYTE_ORDER == LITTLE_ENDIAN && order == 0)){ /* we're little endian but data is big endian */ } else if ((gBYTE_ORDER == BIG_ENDIAN && order == 1)){ /* we're big endian but data is little endian */ switch (num){ case 2: shorts = (u_int16_t*) shorts; *shorts = htons(*shorts); break; case 4: longs = (u_int32_t*) src; *longs = htonl(*longs); break; case 8: longs = (u_int32_t*) src; *longs = htonl(*longs); longs ++; *longs = htonl(*longs); break; } } memcpy(dest, src, num); } msMYGISLayerInfo *getMyGISLayerInfo(layerObj *layer) { return layer->layerinfo; } void setMyGISLayerInfo(layerObj *layer,msMYGISLayerInfo *mygislayerinfo ) { layer->layerinfo = (void*)mygislayerinfo; } int query(msMYGISLayerInfo *layer, char qbuf[]){ int numrows=-1; int i; if (layer->query_result) /* query leftover */ { mysql_free_result(layer->query_result); } if (SHOWQUERY || MYDEBUG) printf("%s
\n", qbuf); if (mysql_query(layer->conn,qbuf) < 0){ mysql_close(layer->conn); msSetError(MS_QUERYERR, " bad mysql query ", qbuf); /* printf("mysql query FAILED real bad...
\n"); */ return MS_FAILURE; } if (!(layer->query_result=mysql_store_result(layer->conn))) { mysql_close(layer->conn); /* printf("mysql query FAILED...
\n"); */ msSetError(MS_QUERYERR, " mysql query failed ", qbuf); return MS_FAILURE; } layer->query = strdup(qbuf); if (layer->query_result) /* There were some rows found, write 'em out for debug */ { numrows = mysql_affected_rows(&(layer->mysql)); if (SHOWQUERY || MYDEBUG) printf("%d rows
\n", numrows); for(i=0;iquery_result); */ /* printf("(%s)
\n",row[0]); */ } } /* mysql_free_result(layer->query_result); // don't free, might be used later */ return MS_SUCCESS; } /* ** Functions for persistent database connections. Code by Jan Hartman ** (jhart@frw.uva.nl). ** ** See also mappool.c for the "new" connection pooling API. ** msMYGISCheckConnection will return the reference of a layer using the same connection */ layerObj* msMYGISCheckConnection(layerObj * layer) { int i; layerObj *lp; /* TODO: there is an issue with layer order since it's possible that layers to be rendered out of order */ for (i=0;iindex;i++) { /* check all layers previous to this one */ lp = &(layer->map->layers[i]); if (lp == layer) continue; /* check to make sure lp even has an open connection (database types only) */ switch (lp->connectiontype) { case MS_MYGIS: if(!lp->layerinfo) continue; break; default: continue; /* not a database layer or uses new connection pool API -> skip it */ break; } /* check if the layers share this connection */ if (lp->connectiontype != layer->connectiontype) continue; if (!lp->connection) continue; if (strcmp(lp->connection, layer->connection)) continue; /* layerinfo->sameconnection = lp;*/ return(lp); /* this connection can be shared */ } /*layerinfo->sameconnection = NULL; */ return(NULL); } /* open up a connection to the postgresql database using the connection string in layer->connection */ /* ie. "host=192.168.50.3 user=postgres port=5555 dbname=mapserv" */ int msMYGISLayerOpen(layerObj *layer) { msMYGISLayerInfo *layerinfo; layerObj* sameconnection = NULL; int order_test = 1; char* DB_HOST = NULL; char* DB_USER = NULL; char* DB_PASSWD = NULL; char* DB_DATABASE = NULL; char* DB_DATATYPE = NULL; char* delim; if (MYDEBUG) printf("msMYGISLayerOpen called
\n"); if (setvbuf(stdout, NULL, _IONBF , 0)){ printf("Whoops..."); }; if (getMyGISLayerInfo(layer)) { if (layer->debug) msDebug("msPOSTGISLayerOpen :: layer is already open!!\n"); return MS_SUCCESS; /* already open */ } /* have to setup a connection to the database */ layerinfo = (msMYGISLayerInfo *) malloc( sizeof(msMYGISLayerInfo) ); layerinfo->sql = NULL; /* calc later */ layerinfo->row_num=0; layerinfo->query_result= NULL; layerinfo->query2_result= NULL; layerinfo->fields = NULL; layerinfo->table = NULL; layerinfo->feature = NULL; layerinfo->attriboffset = 3; /* check whether previous connection can be used */ sameconnection = msMYGISCheckConnection(layer); if (sameconnection == NULL){ if( layer->data == NULL ) { msSetError(MS_QUERYERR, DATAERRORMESSAGE("","Error parsing MYGIS data variable: nothing specified in DATA statement.

\n\nMore Help:

\n
\n"), "msMYGISLayerOpen()"); free(layerinfo); return(MS_FAILURE); } delim = strdup(":"); DB_HOST = strdup(strtok(layer->connection, delim)); DB_USER = strdup(strtok(NULL, delim)); DB_PASSWD = strdup(strtok(NULL, delim)); DB_DATABASE = strdup(strtok(NULL, delim)); DB_DATATYPE = strdup(strtok(NULL, delim)); wkbdata = strcmp(DB_DATATYPE, "num") ? 1 : 0; if (DB_HOST == NULL || DB_USER == NULL || DB_PASSWD == NULL || DB_DATABASE == NULL) { printf("DB param error %s/%s/%s/%s !\n",DB_HOST,DB_USER,DB_PASSWD,DB_DATABASE); free(layerinfo); return MS_FAILURE; } if (strcmp(DB_PASSWD, "none") == 0) strcpy(DB_PASSWD, ""); #if MYSQL_VERSION_ID >= 40000 mysql_init(&(layerinfo->mysql)); if (!(layerinfo->conn = mysql_real_connect(&(layerinfo->mysql),DB_HOST,DB_USER,DB_PASSWD,NULL, 0, NULL, 0))) #else if (!(layerinfo->conn = mysql_connect(&(layerinfo->mysql),DB_HOST,DB_USER,DB_PASSWD))) #endif { char tmp[4000]; sprintf( tmp, "Failed to connect to SQL server: Error: %s\nHost: %s\nUsername:%s\nPassword:%s\n", mysql_error(&(layerinfo->mysql)), DB_HOST, DB_USER, DB_PASSWD); msSetError(MS_QUERYERR, tmp, "msMYGISLayerOpen()"); free(layerinfo); return MS_FAILURE; } if (MYDEBUG)printf("msMYGISLayerOpen2 called
\n"); if (mysql_select_db(layerinfo->conn,DB_DATABASE) < 0) { mysql_close(layerinfo->conn); free(layerinfo); msSetError(MS_QUERYERR, "SQL Database could not be opened", "msMYGISLayerOpen()"); return MS_FAILURE; } } else { /* connection reusable */ free(layerinfo); layerinfo = sameconnection->layerinfo; /* layerinfo->conn = layer->sameconnection->layerinfo->conn; */ } if (MYDEBUG)printf("msMYGISLayerOpen3 called
\n"); if( ((char *) &order_test)[0] == 1 ) gBYTE_ORDER = LITTLE_ENDIAN; else gBYTE_ORDER = BIG_ENDIAN; setMyGISLayerInfo(layer, layerinfo); return MS_SUCCESS; } /* Return MS_TRUE if layer is open, MS_FALSE otherwise. */ int msMYGISLayerIsOpen(layerObj *layer) { if (getMyGISLayerInfo(layer)) return MS_TRUE; return MS_FALSE; } /* Free the itemindexes array in a layer. */ void msMYGISLayerFreeItemInfo(layerObj *layer) { if (MYDEBUG)printf("msMYGISLayerFreeItemInfo called
\n"); if (layer->iteminfo) free(layer->iteminfo); layer->iteminfo = NULL; } /* allocate the iteminfo index array - same order as the item list */ int msMYGISLayerInitItemInfo(layerObj *layer) { int i; int *itemindexes ; if (MYDEBUG)printf("msMYGISLayerInitItemInfo called
\n"); if (layer->numitems == 0) return MS_SUCCESS; if (layer->iteminfo) free(layer->iteminfo); if((layer->iteminfo = (int *)malloc(sizeof(int)*layer->numitems))== NULL) { msSetError(MS_MEMERR, NULL, "msMYGISLayerInitItemInfo()"); return(MS_FAILURE); } itemindexes = (int*)layer->iteminfo; for(i=0;inumitems;i++) { itemindexes[i] = i; /* last one is always the geometry one - the rest are non-geom */ } return(MS_SUCCESS); } /* int prep_DB(char *geom_table,char *geom_column,layerObj *layer, PGresult **sql_results,rectObj rect,char *query_string, char *urid_name, char *user_srid) */ static int prep_DB(char *geom_table,char *geom_column,layerObj *layer, MYSQL_RES **sql_results,rectObj rect,char *query_string, char *urid_name, char *user_srid) { char columns_wanted[5000]=""; char temp[5000]=""; char query_string_0_5[6000]; char query_string_0_5_real[6000]; /* char query_string_0_6[6000]; */ char box3d[200]; msMYGISLayerInfo *layerinfo; char *pos_from, *pos_ftab, *pos_space, *pos_paren; char f_table_name[5000]; char ftable[5000]; char attribselect[5000] = "" ; int t; layerinfo = (msMYGISLayerInfo *) layer->layerinfo; /* Set the urid name */ layerinfo->urid_name = urid_name; /* Extract the proper f_table_name from the geom_table string. * We are expecting the geom_table to be either a single word * or a sub-select clause that possibly includes a join -- * * (select column[,column[,...]] from ftab[ natural join table2]) as foo * * We are expecting whitespace or a ')' after the ftab name. * */ pos_space = strstr(geom_table, " "); /* First space */ strncpy(ftable, geom_table, pos_space - geom_table); ftable[pos_space - geom_table] = NULL; layerinfo = (msMYGISLayerInfo *) layer->layerinfo; layerinfo->feature = strdup(ftable); /* printf("FEATURE %s/%s/%s/%s
", ftable, pos_ftab, pos_space, pos_paren); */ pos_from = strstr(geom_table, " from "); if (pos_from == NULL) { strcpy(f_table_name, geom_table); } else { /* geom_table is a sub-select clause */ pos_ftab = pos_from + 6; /* This should be the start of the ftab name */ pos_space = strstr(pos_ftab, " "); /* First space */ pos_paren = strstr(pos_ftab, ")"); /* Closing paren of clause */ if ( (pos_space ==NULL) || (pos_paren ==NULL) ) { msSetError(MS_QUERYERR, DATAERRORMESSAGE(geom_table,"Error parsing MYGIS data variable: Something is wrong with your subselect statement.

\n\nMore Help:

\n
\n"), "prep_DB()"); return(MS_FAILURE); } if (pos_paren < pos_space) { /* closing parenthesis preceeds any space */ strncpy(f_table_name, pos_ftab, pos_paren - pos_ftab); } else { strncpy(f_table_name, pos_ftab, pos_space - pos_ftab); } } /* columns_wanted[0] = 0; //len=0 */ /* printf(":%d:", layer->numitems); */ for (t=0;tnumitems; t++) { /* printf("(%s, %d/%d)", layer->items[t],t,layer->numitems); */ if (strchr(layer->items[t], '.') != NULL) sprintf(temp,", %s ",layer->items[t]); else sprintf(temp,", feature.%s ",layer->items[t]); strcat(columns_wanted,temp); } /* sprintf(box3d,"'BOX3D(%.15g %.15g,%.15g %.15g)'::BOX3D",rect.minx, rect.miny, rect.maxx, rect.maxy); */ sprintf(box3d,"(feature.x2 > %.15g AND feature.y2 > %.15g AND feature.x1 < %.15g AND feature.y1 < %.15g)",rect.minx, rect.miny, rect.maxx, rect.maxy); /* substitute token '!BOX!' in geom_table with the box3d - do at most 1 substitution */ if (strstr(geom_table,"!BOX!")) { /* need to do a substition */ char *start, *end; char *result; result = malloc(7000); start = strstr(geom_table,"!BOX!"); end = start+5; start[0] =0; result[0]=0; strcat(result,geom_table); strcat(result,box3d); strcat(result,end); geom_table= result; } if (layer->type == MS_LAYER_ANNOTATION){ /* attribselect = strdup(", feature.txt, feature.angle, ''"); */ /* if (layer->labelitem){ */ /* strcat(attribselect,", feature."); */ /* strcat(attribselect, layer->labelitem); */ /* } */ /* if (layer->labelitem) */ /* sprintf(attribselect,"%s, feature.%s", attribselect, layer->labelitem); */ /* if (layer->labelangleitem) */ /* sprintf(attribselect,"%s, feature.%s", attribselect, layer->labelangleitem); */ /* if (layer->labelsizeitem) */ /* sprintf(attribselect,"%s, feature.%s", attribselect, layer->labelsizeitem); */ /* if (layer->labelsizeitem) */ /* sprintf(attribselect,"%s, feature.%s", attribselect, layer->labelsizeitem); */ sprintf(attribselect,", %s%s, %s%s, %s%s", layer->labelitem ? "feature." : "", layer->labelitem ? layer->labelitem: "''", layer->labelangleitem ? "feature." : "", layer->labelangleitem ? layer->labelangleitem: "''", layer->labelsizeitem ? "feature." : "", layer->labelsizeitem ? layer->labelsizeitem: "''"); } if (wkbdata){ layerinfo->attriboffset = 3; if (layer->filter.string == NULL){ sprintf(query_string_0_5,"SELECT count(%s) from %s WHERE %s", columns_wanted,geom_table,box3d); sprintf(query_string_0_5_real,"SELECT feature.id, feature.vertices, geometry.WKB_GEOMETRY %s from %s WHERE %s AND feature.GID = geometry.GID ORDER BY feature.id", columns_wanted, geom_table,box3d); }else { sprintf(query_string_0_5,"SELECT count(%s) from %s WHERE (%s) and (%s)", columns_wanted,geom_table,layer->filter.string,box3d); sprintf(query_string_0_5_real,"SELECT feature.id, feature.vertices, geometry.WKB_GEOMETRY %s from %s WHERE (%s) AND feature.GID = geometry.GID AND (%s) ORDER BY feature.id", columns_wanted, geom_table,layer->filter.string,box3d); } } /* query(layerinfo, "SELECT "); // attrib ? */ else { layerinfo->attriboffset = 7; if (layer->filter.string == NULL) { /* sprintf(query_string_0_5,"SELECT count(%s) from %s WHERE %s && %s", */ /* columns_wanted,geom_table,geom_column,box3d); */ sprintf(query_string_0_5,"SELECT count(%s) from %s WHERE %s", columns_wanted,geom_table,box3d); sprintf(query_string_0_5_real,"SELECT feature.id, feature.vertices, geometry.ETYPE, geometry.X1, geometry.Y1, geometry.X2, geometry.Y2 %s from %s WHERE %s AND feature.GID = geometry.GID ORDER BY feature.id, geometry.ESEQ, geometry.SEQ", attribselect, geom_table,box3d); /* if (strlen(user_srid) == 0) { sprintf(query_string_0_6,"DECLARE mycursor BINARY CURSOR FOR SELECT %s from %s WHERE %s && setSRID(%s, find_srid('','%s','%s') )", columns_wanted,geom_table,geom_column,box3d,f_table_name,geom_column); } else // use the user specified version { sprintf(query_string_0_6,"DECLARE mycursor BINARY CURSOR FOR SELECT %s from %s WHERE %s && setSRID(%s, %s )", columns_wanted,geom_table,geom_column,box3d,user_srid); } */ } else { /* sprintf(query_string_0_5,"SELECT count(%s) from %s WHERE (%s) and (%s && %s)", */ /* columns_wanted,geom_table,layer->filter.string,geom_column,box3d); */ sprintf(query_string_0_5,"SELECT count(%s) from %s WHERE (%s) and (%s)", columns_wanted,geom_table,layer->filter.string,box3d); sprintf(query_string_0_5_real,"SELECT feature.id, feature.vertices, geometry.ETYPE, geometry.X1, geometry.Y1, geometry.X2, geometry.Y2 %s from %s WHERE (%s) AND feature.GID = geometry.GID AND (%s) ORDER BY feature.id, geometry.ESEQ, geometry.SEQ", attribselect, geom_table,layer->filter.string,box3d); /* if (strlen(user_srid) == 0) { sprintf(query_string_0_6,"DECLARE mycursor BINARY CURSOR FOR SELECT %s from %s WHERE (%s) and (%s && setSRID( %s,find_srid('','%s','%s') ))", columns_wanted,geom_table,layer->filter.string,geom_column,box3d,f_table_name,geom_column); } else { sprintf(query_string_0_6,"DECLARE mycursor BINARY CURSOR FOR SELECT %s from %s WHERE (%s) and (%s && setSRID( %s,%s) )", columns_wanted,geom_table,layer->filter.string,geom_column,box3d,user_srid); } */ } } query(layerinfo, query_string_0_5_real); layerinfo->total_num = 10000000; return (MS_SUCCESS); } /* build the neccessary SQL */ /* allocate a cursor for the SQL query */ /* get ready to read from the cursor */ /* */ /* For queries, we need to also retreive the OID for each of the rows */ /* So GetShape() can randomly access a row. */ int msMYGISLayerWhichShapes(layerObj *layer, rectObj rect) { char *query_str; char table_name[5000]; char geom_column_name[5000]; char urid_name[5000]; char user_srid[5000]; int set_up_result; msMYGISLayerInfo *layerinfo; if (MYDEBUG) printf("msMYGISLayerWhichShapes called
\n"); layerinfo = (msMYGISLayerInfo *) layer->layerinfo; if (layerinfo == NULL) { /* layer not opened yet */ msSetError(MS_QUERYERR, "msMYGISLayerWhichShapes called on unopened layer (layerinfo = NULL)", "msMYGISLayerWhichShapes()"); return(MS_FAILURE); } if( layer->data == NULL ) { msSetError(MS_QUERYERR, "Missing DATA clause in MYGIS Layer definition. DATA statement must contain 'geometry_column from table_name' or 'geometry_column from (sub-query) as foo'.", "msMYGISLayerWhichShapes()"); return(MS_FAILURE); } query_str = (char *) malloc(6000); /* should be big enough */ memset(query_str,0,6000); /* zero it out */ if(MYDEBUG) printf("%s/%s/%s/%s/%s
\n", layer->data, geom_column_name, table_name, urid_name,user_srid); msMYGISLayerParseData(layer->data, geom_column_name, table_name, urid_name,user_srid); if(MYDEBUG) printf("%s
\n", layer->data); layerinfo->table = strdup(table_name); if(MYDEBUG) printf("%s/%s/%s/%s/%s
\n", layer->data, geom_column_name, table_name, urid_name,user_srid); set_up_result= prep_DB(table_name,geom_column_name, layer, &(layerinfo->query_result), rect,query_str, urid_name,user_srid); if (MYDEBUG) printf("...
"); if (set_up_result != MS_SUCCESS) return set_up_result; /* relay error */ layerinfo->sql = query_str; layerinfo->row_num =0; if (MYDEBUG) printf("prep_DB done
"); return(MS_SUCCESS); } /* Close the MYGIS record set and connection */ int msMYGISLayerClose(layerObj *layer) { msMYGISLayerInfo *layerinfo; if (MYDEBUG) printf("msMYGISLayerClose called
\n"); layerinfo = (msMYGISLayerInfo *) layer->layerinfo; if (layerinfo == NULL) return MS_FAILURE; mysql_close(layerinfo->conn); free(layer->layerinfo); layer->layerinfo = NULL; if (setvbuf(stdout, NULL, _IONBF , 0)){ printf("Whoops..."); }; /* fflush(NULL); */ return(MS_SUCCESS); } /* ******************************************************* */ /* wkb is assumed to be 2d (force_2d) */ /* and wkb is a GEOMETRYCOLLECTION (force_collection) */ /* and wkb is in the endian of this computer (asbinary(...,'[XN]DR')) */ /* each of the sub-geom inside the collection are point,linestring, or polygon */ /* */ /* also, int is 32bits long */ /* double is 64bits long */ /* ******************************************************* */ /* convert the wkb into points */ /* points -> pass through */ /* lines-> constituent points */ /* polys-> treat ring like line and pull out the consituent points */ /* int force_to_points(char *wkb, shapeObj *shape) */ static int force_to_points(MYSQL_ROW row, MYSQL_RES* qresult, shapeObj *shape, long *cnt) { /* we're going to make a 'line' for each entity (point, line or ring) in the geom collection */ int ngeoms ; int t, points=0; int type; lineObj line={0,NULL}; shape->type = MS_SHAPE_NULL; /* nothing in it */ ngeoms = atoi(row[1]); type = atoi(row[2]); shape->type = MS_SHAPE_POINT; line.numpoints = ngeoms; line.point = (pointObj *) malloc ((type == ETYPE_POINT ? 1 : 2) * ngeoms * sizeof(pointObj)); line.point[0].x = atof(row[3]); line.point[0].y = atof(row[4]); #ifdef USE_POINT_Z_M line.point[0].m = 0; #endif if (type != ETYPE_POINT){ /* if this geometry is not really a point */ points++; line.point[1].x = atof(row[5]); line.point[1].y = atof(row[6]); #ifdef USE_POINT_Z_M line.point[1].m = 0; #endif } for (t=1; t\n"); return(MS_FAILURE); } points++; line.point[points].x = atof(row[3]); line.point[points].y = atof(row[4]); #ifdef USE_POINT_Z_M line.point[points].m = 0; #endif if (type != ETYPE_POINT){ /* if this geometry is not really a point */ points++; line.point[points].x = atof(row[3]); line.point[points].y = atof(row[4]); #ifdef USE_POINT_Z_M line.point[points].m = 0; #endif } } if (ngeoms != points) printf("Warning ng%d/p%d\n", ngeoms, points); msAddLine(shape,&line); free(line.point); return(MS_SUCCESS); } /* convert the wkb into lines */ /* points-> remove */ /* lines -> pass through */ /* polys -> treat rings as lines */ /* int force_to_lines(char *wkb, shapeObj *shape) */ static int force_to_lines(MYSQL_ROW row, MYSQL_RES* qresult, shapeObj *shape, long *cnt) { int ngeoms ; int t, points=0; /* float x,y; */ int type; lineObj line={0,NULL}; shape->type = MS_SHAPE_NULL; /* nothing in it */ ngeoms = atoi(row[1]); /* x = atof(row[3]); */ /* y = atof(row[4]); */ type = atoi(row[2]); line.point = (pointObj *) malloc (2 * ngeoms * sizeof(pointObj)); for (t=0; t\n", id, t, ngeoms); return(MS_FAILURE); } } /* if (MYDEBUG) printf("(%s/%s/%s/%s/%s/%s/%s/%i)
\n",row[0],row[1],row[2],row[3],row[4],row[5],row[6],points); */ /* memcpy(&line.numpoints, wkb[offset+5],4); //num points */ line.point[points].x = atof(row[3]); line.point[points].y = atof(row[4]); #ifdef USE_POINT_Z_M line.point[points].m = 0; #endif line.point[points+1].x = atof(row[5]); line.point[points+1].y = atof(row[6]); #ifdef USE_POINT_Z_M line.point[points+1].m = 0; #endif shape->type = MS_SHAPE_LINE; /* printf("(%f/%f/%f/%f)
\n",line.point[points].x,line.point[points].y,line.point[points+1].x,line.point[points+1].y); */ points += 2; } if (2*ngeoms != points) printf("Warning ng%d/p%d\n", ngeoms, points); line.numpoints=points; if (points > 1){ msAddLine(shape,&line); /* printf("points: %d
\n",points); */ } free(line.point); return(MS_SUCCESS); } /* point -> reject */ /* line -> reject */ /* polygon -> lines of linear rings */ static int force_to_polygons(MYSQL_ROW row, MYSQL_RES* qresult, shapeObj *shape, long *cntchar) { int ngeoms ; int t,points=0; /* float x,y; */ int type; lineObj line={0,NULL}; shape->type = MS_SHAPE_NULL; /* nothing in it */ ngeoms = atoi(row[1]); /* x = atof(row[3]); */ /* y = atof(row[4]); */ type = atoi(row[2]); /* we do one shape per call -> all geoms in this shape are the point of the poly */ line.point = (pointObj *) malloc (2 * sizeof(pointObj)* ngeoms ); /* point struct */ /* line.point[0].x = x; */ /* line.point[0].y = y; */ /* line.point[0].m = 0; */ line.numpoints = ngeoms; for (t=0; t\n"); return(MS_FAILURE); } } /* if (strcmp(type, "polygon") == 0) //polygon */ /* { */ shape->type = MS_SHAPE_POLYGON; line.point[points].x = atof(row[3]); line.point[points].y = atof(row[4]); #ifdef USE_POINT_Z_M line.point[points].m = 0; #endif line.point[points+1].x = atof(row[5]); line.point[points+1].y = atof(row[6]); #ifdef USE_POINT_Z_M line.point[points+1].m = 0; #endif points+=2; /* } */ } line.numpoints = points; if (2*ngeoms != points) printf("Warning ng%d/p%d\n", ngeoms, points); if (points > 1){ msAddLine(shape,&line); /* printf("points: %d
\n",points); */ } free(line.point); return(MS_SUCCESS); } /* if there is any polygon in wkb, return force_polygon */ /* if there is any line in wkb, return force_line */ /* otherwise return force_point */ static int dont_force(MYSQL_ROW row, MYSQL_RES* qresult, shapeObj *shape, long *cntchar) /* int dont_force(char *wkb, shapeObj *shape) */ { int best_type; int type; /* printf("dont force"); */ best_type = MS_SHAPE_NULL; /* nothing in it */ type = atoi(row[2]); if (type == ETYPE_POINT) best_type = MS_SHAPE_POINT; if (type == ETYPE_LINESTRING) best_type = MS_SHAPE_LINE; if (type == ETYPE_POLYGON) best_type = MS_SHAPE_POLYGON; if (best_type == MS_SHAPE_POINT) { return force_to_points(row, qresult, shape, cntchar); } if (best_type == MS_SHAPE_LINE) { return force_to_lines(row, qresult, shape, cntchar); } if (best_type == MS_SHAPE_POLYGON) { return force_to_polygons(row, qresult, shape, cntchar); } printf("unkntype %d, ", type); return(MS_FAILURE); /* unknown type */ } int wkb_force_to_points(char *wkb, shapeObj *shape) { /* we're going to make a 'line' for each entity (point, line or ring) in the geom collection */ int offset =0,pt_offset; int ngeoms ; int t,u,v; int type,nrings,npoints; char byteorder = 0; lineObj line={0,NULL}; shape->type = MS_SHAPE_NULL; /* nothing in it */ byteorder = wkb[0]; end_memcpy(byteorder, &ngeoms, &wkb[5], 4); offset = 9; /* were the first geometry is */ for (t=0; ttype = MS_SHAPE_POINT; line.numpoints = 1; line.point = (pointObj *) malloc (sizeof(pointObj)); end_memcpy(byteorder, &line.point[0].x , &wkb[offset+5 ], 8); end_memcpy(byteorder, &line.point[0].y , &wkb[offset+5+8], 8); offset += 5+16; msAddLine(shape,&line); free(line.point); } if (type == 2) /* linestring */ { shape->type = MS_SHAPE_POINT; end_memcpy(byteorder, &line.numpoints, &wkb[offset+5],4); /* num points */ line.point = (pointObj *) malloc (sizeof(pointObj)* line.numpoints ); /* point struct */ for(u=0;utype = MS_SHAPE_POINT; end_memcpy(byteorder, &nrings, &wkb[offset+5],4); /* num rings */ /* add a line for each polygon ring */ pt_offset = 0; offset += 9; /* now points at 1st linear ring */ for (u=0;u remove */ /* lines -> pass through */ /* polys -> treat rings as lines */ int wkb_force_to_lines(char *wkb, shapeObj *shape) { int offset =0,pt_offset; int ngeoms ; int t,u,v; int type,nrings,npoints; char byteorder = 0; lineObj line={0,NULL}; shape->type = MS_SHAPE_NULL; /* nothing in it */ byteorder = wkb[0]; end_memcpy(byteorder, &ngeoms, &wkb[5], 4); offset = 9; /* were the first geometry is */ for (t=0; ttype = MS_SHAPE_LINE; end_memcpy(byteorder, &line.numpoints, &wkb[offset+5],4); /* num points */ line.point = (pointObj *) malloc (sizeof(pointObj)* line.numpoints ); /* point struct */ for(u=0;utype = MS_SHAPE_LINE; end_memcpy(byteorder, &nrings, &wkb[offset+5],4); /* num rings */ /* add a line for each polygon ring */ pt_offset = 0; offset += 9; /* now points at 1st linear ring */ for (u=0;u reject */ /* line -> reject */ /* polygon -> lines of linear rings */ int wkb_force_to_polygons(char *wkb, shapeObj *shape) { int offset =0,pt_offset; int ngeoms ; int t,u,v; int type,nrings,npoints; char byteorder = 0; lineObj line={0,NULL}; shape->type = MS_SHAPE_NULL; /* nothing in it */ byteorder = wkb[0]; end_memcpy(byteorder, &ngeoms, &wkb[5], 4); offset = 9; /* were the first geometry is */ for (t=0; ttype = MS_SHAPE_POLYGON; end_memcpy(byteorder, &nrings, &wkb[offset+5],4); /* num rings */ /* add a line for each polygon ring */ pt_offset = 0; offset += 9; /* now points at 1st linear ring */ for (u=0;unumlines; t++) { for(u=0;uline[t].numpoints; u++) { if (first_one) { shape->bounds.minx = shape->line[t].point[u].x; shape->bounds.maxx = shape->line[t].point[u].x; shape->bounds.miny = shape->line[t].point[u].y; shape->bounds.maxy = shape->line[t].point[u].y; first_one = 0; } else { if (shape->line[t].point[u].x < shape->bounds.minx) shape->bounds.minx = shape->line[t].point[u].x; if (shape->line[t].point[u].x > shape->bounds.maxx) shape->bounds.maxx = shape->line[t].point[u].x; if (shape->line[t].point[u].y < shape->bounds.miny) shape->bounds.miny = shape->line[t].point[u].y; if (shape->line[t].point[u].y > shape->bounds.maxy) shape->bounds.maxy = shape->line[t].point[u].y; } } } } /* find the next shape with the appropriate shape type (convert it if necessary) */ /* also, load in the attribute data */ /* MS_DONE => no more data */ int msMYGISLayerNextShape(layerObj *layer, shapeObj *shape) { int result; msMYGISLayerInfo *layerinfo; layerinfo = (msMYGISLayerInfo *) layer->layerinfo; /* if (MYDEBUG)printf("msMYGISLayerNextShape called
\n"); */ if (layerinfo == NULL) { msSetError(MS_QUERYERR, "NextShape called with layerinfo = NULL", "msMYGISLayerNextShape()"); return(MS_FAILURE); } result= msMYGISLayerGetShapeRandom(layer, shape, &(layerinfo->row_num) ); /* getshaperandom will increment the row_num */ if (result) layerinfo->row_num ++; /* printf("RES%i\n",result); */ return result; } /* Used by NextShape() to access a shape in the query set */ /* TODO: only fetch 1000 rows at a time. This should check to see if the */ /* requested feature is in the set. If it is, return it, otherwise */ /* grab the next 1000 rows. */ int msMYGISLayerGetShapeRandom(layerObj *layer, shapeObj *shape, long *record) { msMYGISLayerInfo *layerinfo; int result,t; char tmpstr[500]; MYSQL_ROW row; MYSQL_ROW row_attr; int numrows2 = 0; char* wkb; layerinfo = (msMYGISLayerInfo *) layer->layerinfo; /* if (MYDEBUG) printf("msMYGISLayerGetShapeRandom : called row %li
\n",*record); */ if (layerinfo == NULL) { msSetError(MS_QUERYERR, "GetShape called with layerinfo = NULL", "msMYGISLayerGetShape()"); return(MS_FAILURE); } if (layerinfo->conn == NULL) { msSetError(MS_QUERYERR, "NextShape called on MYGIS layer with no connection to DB.", "msMYGISLayerGetShape()"); return(MS_FAILURE); } if (layerinfo->query_result == NULL) { msSetError(MS_QUERYERR, "GetShape called on MYGIS layer with invalid DB query results.", "msMYGISLayerGetShapeRandom()"); return(MS_FAILURE); } msInitShape(shape); shape->type = MS_SHAPE_NULL; /* return (MS_FAILURE); // a little cheating can't harm... */ while(shape->type == MS_SHAPE_NULL) { if ( (*record) < layerinfo->total_num ) { /* retreive an item */ row = mysql_fetch_row(layerinfo->query_result); if (row==NULL){ /* printf("nullfetch
\n"); */ return(MS_DONE); } /* layerinfo->total_num = row[0]; */ /* if (MYDEBUG && !wkbdata) printf("HEAD (%s/%s/%s/%s/%s/%s/%s)
\n",row[0],row[1],row[2],row[3],row[4],row[5],row[6]); */ /* if (MYDEBUG && wkbdata) printf("HEAD (%s/%s/%s)
\n",row[0],row[1],row[2]); */ /* wkb = (char *) PQgetvalue(layerinfo->query_result, (*record), layer->numitems);i */ wkb = row[2]; switch(layer->type) { case MS_LAYER_POINT: result = wkbdata ? wkb_force_to_points(wkb, shape) : force_to_points(row, layerinfo->query_result, shape, record); break; case MS_LAYER_LINE: result = wkbdata ? wkb_force_to_lines(wkb, shape) : force_to_lines(row, layerinfo->query_result, shape, record); break; case MS_LAYER_POLYGON: result = wkbdata ? wkb_force_to_polygons(wkb, shape) : force_to_polygons(row, layerinfo->query_result, shape, record); break; case MS_LAYER_ANNOTATION: case MS_LAYER_QUERY: result = wkbdata ? wkb_dont_force(wkb, shape) : dont_force(row, layerinfo->query_result, shape, record); break; case MS_LAYER_RASTER: msDebug( "Ignoring MS_LAYER_RASTER in mapMYGIS.c
\n" ); break; case MS_LAYER_CIRCLE: msDebug( "Ignoring MS_LAYER_CIRCLE in mapMYGIS.c
\n" ); break; case MS_LAYER_TILEINDEX: msDebug( "Ignoring MS_LAYER_TILEINDEX in mapMYGIS.c
\n" ); break; } if (shape->type != MS_SHAPE_NULL) { /* if (MYDEBUG)printf("attrib
\n"); */ /* have to retreive the attributes */ shape->values = (char **) malloc(sizeof(char *) * layer->numitems); shape->index = atoi(row[0]); shape->numvalues = layer->numitems; if (layer->numitems > 0){ /* if (MYDEBUG)printf("RETR attrib
\n"); */ for (t=0;tnumitems;t++){ sprintf(tmpstr, "%d", t); /* shape->values[t]=strdup(""); */ shape->values[t]=strdup(row[layerinfo->attriboffset+t]); /* printf("%d/%s
"); */ } if (1){ } else if (1) { if (layer->labelitem && strlen(row[layerinfo->attriboffset+0]) > 0){ shape->values[layer->labelitemindex]=strdup(row[layerinfo->attriboffset+0]); } if (layer->labelangleitem && strlen(row[layerinfo->attriboffset+1]) > 0){ shape->values[layer->labelangleitemindex]=strdup(row[layerinfo->attriboffset+1]); } if (layer->labelsizeitem && strlen(row[layerinfo->attriboffset+2]) > 0){ shape->values[layer->labelsizeitemindex]=strdup(row[layerinfo->attriboffset+2]); } } else { /* sprintf(tmpstr,"select attribute, value from shape_attr where shape_attr.shape='%d'", shape->index); */ sprintf(tmpstr,"SELECT %s, %s, %s FROM %s feature WHERE feature.id='%li'", layer->labelitem ? layer->labelitem: "''", layer->labelangleitem ? layer->labelangleitem: "''", layer->labelsizeitem ? layer->labelsizeitem: "''", layerinfo->feature ? layerinfo->feature : "feature", shape->index); /* sprintf(tmpstr,"SELECT %s, %s, %s FROM %s WHERE feature.id='%d' AND feature.GID=geometry.GID GROUP BY feature.id", layer->labelitem ? layer->labelitem: "''", layer->labelangleitem ? layer->labelangleitem: "''", layer->labelsizeitem ? layer->labelsizeitem: "''", layerinfo->table ? layerinfo->table : "feature", shape->index); */ if (layerinfo->query2_result != NULL) /* query leftover */ { mysql_free_result(layerinfo->query2_result); } if (MYDEBUG) printf("%s
\n", tmpstr); if (mysql_query(layerinfo->conn,tmpstr) < 0){ mysql_close(layerinfo->conn); printf("mysql query FAILED real bad...
\n%s\n",tmpstr); return MS_FAILURE; } if (!(layerinfo->query2_result=mysql_store_result(layerinfo->conn))) { mysql_close(layerinfo->conn); printf("mysql query FAILED...
\n%s\n",tmpstr); return MS_FAILURE; } layerinfo->query2 = strdup(tmpstr); if (layerinfo->query2_result) /* There were some rows found, write 'em out for debug */ { /* numrows2 = mysql_affected_rows(&(layerinfo->mysql)); */ /* printf("%d rows
\n", numrows2); */ /* for(t=0;tquery2_result)) ) { if (row_attr==NULL){ printf("attr_nullfetch(%s-%d/%d)
\n",tmpstr,t,numrows2); /* return(MS_DONE); */ } /* printf("%s,%s,%s/%s,%s
\n", layer->labelitem, layer->labelsizeitem, layer->labelangleitem, row_attr[0], row_attr[1]); */ if (layer->labelitem && strlen(row_attr[0]) > 0){ shape->values[layer->labelitemindex]=strdup(row_attr[0]); } if (layer->labelangleitem && strlen(row_attr[1]) > 0){ shape->values[layer->labelangleitemindex]=strdup(row_attr[1]); } if (layer->labelsizeitem && strlen(row_attr[2]) > 0){ shape->values[layer->labelsizeitemindex]=strdup(row_attr[2]); } } } } } find_bounds(shape); (*record)++; /* move to next shape */ return (MS_SUCCESS); } else { (*record)++; /* move to next shape */ } } else { return (MS_DONE); } } msFreeShape(shape); return(MS_FAILURE); } /* Execute a query on the DB based on record being an OID. */ int msMYGISLayerGetShape(layerObj *layer, shapeObj *shape, long record) { char *query_str; char table_name[5000]; char geom_column_name[5000]; char urid_name[5000]; char user_srid[5000]; /* int nitems; */ char columns_wanted[5000]; char temp[5000]; msMYGISLayerInfo *layerinfo; int t; if (MYDEBUG) printf("msMYGISLayerGetShape called for record = %li
\n",record); /* return (MS_FAILURE); */ layerinfo = (msMYGISLayerInfo *) layer->layerinfo; if (layerinfo == NULL) { /* layer not opened yet */ msSetError(MS_QUERYERR, "msMYGISLayerGetShape called on unopened layer (layerinfo = NULL)", "msMYGISLayerGetShape()"); return(MS_FAILURE); } query_str = (char *) malloc(6000); /* should be big enough */ memset(query_str,0,6000); /* zero it out */ msMYGISLayerParseData(layer->data, geom_column_name, table_name, urid_name,user_srid); if (layer->numitems ==0) /* dont need the oid since its really record */ { if (gBYTE_ORDER == LITTLE_ENDIAN) sprintf(columns_wanted,"asbinary(force_collection(force_2d(%s)),'NDR')", geom_column_name); /* sprintf(columns_wanted,"asbinary(force_collection(force_2d(%s)),'NDR')", geom_column_name); */ else sprintf(columns_wanted,"asbinary(force_collection(force_2d(%s)),'XDR')", geom_column_name); /* sprintf(columns_wanted,"asbinary(force_collection(force_2d(%s)),'XDR')", geom_column_name); */ strcpy(columns_wanted, geom_column_name); } else { columns_wanted[0] = 0; /* len=0 */ for (t=0;tnumitems; t++) { sprintf(temp,", feature.%s",layer->items[t]); strcat(columns_wanted,temp); } if (gBYTE_ORDER == LITTLE_ENDIAN) sprintf(temp,"asbinary(force_collection(force_2d(%s)),'NDR')", geom_column_name); else sprintf(temp,"asbinary(force_collection(force_2d(%s)),'XDR')", geom_column_name); strcpy(temp, geom_column_name); strcat(columns_wanted,temp); } sprintf(query_str,"DECLARE mycursor BINARY CURSOR FOR SELECT %s from %s WHERE %s = %li", columns_wanted,table_name,urid_name,record); if (MYDEBUG) printf("msMYGISLayerGetShape: %s
\n",query_str); /* query_result = PQexec(layerinfo->conn, "BEGIN"); if (!(query_result) || PQresultStatus(query_result) != PGRES_COMMAND_OK) { msSetError(MS_QUERYERR, "Error executing MYGIS BEGIN statement.", "msMYGISLayerGetShape()"); PQclear(query_result); query_result = NULL; return(MS_FAILURE); } query_result = PQexec(layerinfo->conn, "set enable_seqscan = off"); if (!(query_result) || PQresultStatus(query_result) != PGRES_COMMAND_OK) { msSetError(MS_QUERYERR, "Error executing MYGIS 'set enable_seqscan off' statement.", "msMYGISLayerGetShape()"); PQclear(query_result); query_result = NULL; return(MS_FAILURE); } PQclear(query_result); query_result = PQexec(layerinfo->conn, query_str ); if (!(query_result) || PQresultStatus(query_result) != PGRES_COMMAND_OK) { char tmp[4000]; sprintf(tmp, "Error executing MYGIS SQL statement: %s", query_str); msSetError(MS_QUERYERR, tmp, "msMYGISLayerGetShape()"); PQclear(query_result); query_result = NULL; return(MS_FAILURE); } PQclear(query_result); query_result = PQexec(layerinfo->conn, "FETCH ALL in mycursor"); if (!(query_result) || PQresultStatus(query_result) != PGRES_TUPLES_OK) { char tmp[4000]; sprintf(tmp, "Error executing MYGIS SQL statement (in FETCH ALL): %s

\n\nMore Help:", query_str); msSetError(MS_QUERYERR, tmp, "msMYGISLayerWhichShapes()"); PQclear(query_result); query_result = NULL; return(MS_FAILURE); } // query has been done, so we can retreive the results shape->type = MS_SHAPE_NULL; if ( 0 < PQntuples(query_result) ) // only need to get one shape { // retreive an item wkb = (char *) PQgetvalue(query_result, 0, layer->numitems); // layer->numitems is the wkt column switch(layer->type) { case MS_LAYER_POINT: result = force_to_points(wkb, shape); break; case MS_LAYER_LINE: result = force_to_lines(wkb, shape); break; case MS_LAYER_POLYGON: result = force_to_polygons(wkb, shape); break; case MS_LAYER_ANNOTATION: case MS_LAYER_QUERY: result = dont_force(wkb,shape); break; case MS_LAYER_RASTER: msDebug( "Ignoring MS_LAYER_RASTER in mapMYGIS.c
\n" ); break; case MS_LAYER_CIRCLE: msDebug( "Ignoring MS_LAYER_RASTER in mapMYGIS.c
\n" ); } if (shape->type != MS_SHAPE_NULL) { // have to retreive the attributes shape->values = (char **) malloc(sizeof(char *) * layer->numitems); for (t=0;tnumitems;t++) { printf("msMYGISLayerGetShape: finding attribute info for '%s'
\n",layer->items[t]); temp1= (char *) PQgetvalue(query_result, 0, t); size = PQgetlength(query_result,0, t ) ; temp2 = (char *) malloc(size+1 ); memcpy(temp2, temp1, size); temp2[size] = 0; // null terminate it shape->values[t] = temp2; printf("msMYGISLayerGetShape: shape->values[%i] has value '%s'
\n",t,shape->values[t]); } shape->index = record; shape->numvalues = layer->numitems; find_bounds(shape); return (MS_SUCCESS); } } else { return (MS_DONE); } msFreeShape(shape); */ return(MS_FAILURE); } /* query the DB for info about the requested table */ /* */ /* CHEAT: dont look in the system tables, get query optimization infomation */ /* */ /* get the table name, return a list of the possible columns (except GEOMETRY column) */ /* */ /* found out this is called during a query */ int msMYGISLayerGetItems(layerObj *layer) { msMYGISLayerInfo *layerinfo; char table_name[5000]; char geom_column_name[5000]; char urid_name[5000]; char user_srid[5000]; char sql[6000]; MYSQL_ROW row; int t; char * sp; /* int nitems; */ if (MYDEBUG) printf( "in msMYGISLayerGetItems (find column names)
\n"); layerinfo = (msMYGISLayerInfo *) layer->layerinfo; if (layerinfo == NULL) { /* layer not opened yet */ msSetError(MS_QUERYERR, "msMYGISLayerGetItems called on unopened layer", "msMYGISLayerGetItems()"); return(MS_FAILURE); } if (layerinfo->conn == NULL) { msSetError(MS_QUERYERR, "msMYGISLayerGetItems called on MYGIS layer with no connection to DB.", "msMYGISLayerGetItems()"); return(MS_FAILURE); } /* get the table name and geometry column name */ msMYGISLayerParseData(layer->data, geom_column_name, table_name, urid_name, user_srid); /* two cases here. One, its a table (use select * from table) otherwise, just use the select clause */ if ((sp = strstr(table_name, " ")) != NULL) *sp = '\0'; sprintf(sql,"describe %s",table_name); t = 0; if (query(layerinfo, sql) == MS_FAILURE) return MS_FAILURE; while ((row = mysql_fetch_row(layerinfo->query_result)) != NULL){ if (strcmp(row[0], "x1") != 0 && strcmp(row[0], "x2") != 0 && strcmp(row[0], "y1") != 0 && strcmp(row[0], "y2") != 0){ t++; layer->items = realloc (layer->items, sizeof(char *) * t); layer->items[t-1] = strdup(row[0]); } } /* memset(layer->items[t],0, str2-str +1); */ /* strncpy(layer->items[t], str, str2-str); */ layer->numitems = t; /* one less because dont want to do anything with geometry column */ /* layerinfo->fields is a string with a list of all the columns */ /* # of items is number of "," in string + 1 */ /* layerinfo->fields looks like "geo_value,geo_id,desc" */ /* since we dont want to return the geometry column, we remove it. */ /* # columns is reduced by 1 */ return msMYGISLayerInitItemInfo(layer); } /* we return an infinite extent */ /* we could call the SQL AGGREGATE extent(GEOMETRY), but that would take FOREVER */ /* to return (it has to read the entire table). */ /* So, we just tell it that we're everywhere and lets the spatial indexing figure things out for us */ /* */ /* Never seen this function actually called */ int msMYGISLayerGetExtent(layerObj *layer, rectObj *extent) { if (MYDEBUG) printf("msMYGISLayerGetExtent called
\n"); extent->minx = extent->miny = -1.0*FLT_MAX ; extent->maxx = extent->maxy = FLT_MAX; return(MS_SUCCESS); } /* Function to parse the Mapserver DATA parameter for geometry * column name, table name and name of a column to serve as a * unique record id */ int msMYGISLayerParseData(char *data, char *geom_column_name, char *table_name, char *urid_name,char *user_srid) { char *pos_opt, *pos_scn, *tmp, *pos_srid; int slength; if (MYDEBUG)printf("msMYGISLayerParseData called
\n"); /* given a string of the from 'geom from ctivalues' or 'geom from () as foo' * return geom_column_name as 'geom' * and table name as 'ctivalues' or 'geom from () as foo' */ /* First look for the optional ' using unique ID' string */ pos_opt = strstr(data, " using unique "); if (pos_opt == NULL) { /* No user specified unique id so we will use the Postgesql OID */ strcpy(urid_name, "OID"); } else { /* CHANGE - protect the trailing edge for thing like 'using unique ftab_id using srid=33' */ tmp = strstr(pos_opt + 14," "); if (tmp == NULL) /* it lookes like 'using unique ftab_id' */ { strcpy(urid_name, pos_opt + 14); } else { /* looks like ' using unique ftab_id ' (space at end) */ strncpy(urid_name, pos_opt + 14, tmp-(pos_opt + 14 ) ); } } pos_srid = strstr(data," using SRID="); if (pos_srid == NULL) { user_srid[0] = 0; /* = "" */ } else { /* find the srid */ slength=strspn(pos_srid+12,"-0123456789"); if (slength == 0) { msSetError(MS_QUERYERR, DATAERRORMESSAGE(data,"Error parsing MYGIS data variable: You specified 'using SRID=#' but didnt have any numbers!

\n\nMore Help:

\n
\n"), "msMYGISLayerParseData()"); return(MS_FAILURE); } else { strncpy(user_srid,pos_srid+12,slength); user_srid[slength] = 0; /* null terminate it */ } } /* this is a little hack so the rest of the code works. If the ' using SRID=' comes before */ /* the ' using unique ', then make sure pos_opt points to where the ' using SRID' starts! */ if (pos_opt == NULL) { pos_opt = pos_srid; } else { if (pos_srid != NULL) { if (pos_opt>pos_srid) pos_opt = pos_srid; } } /* Scan for the table or sub-select clause */ pos_scn = strstr(data, " from "); if (pos_scn == NULL) { msSetError(MS_QUERYERR, DATAERRORMESSAGE(data,"Error parsing MYGIS data variable. Must contain 'geometry_column from table_name' or 'geom from (subselect) as foo' (couldnt find ' from '). More help:

\n
\n"), "msMYGISLayerParseData()"); /* msSetError(MS_QUERYERR, "Error parsing MYGIS data variable. Must contain 'geometry_column from table_name' or 'geom from (subselect) as foo' (couldnt find ' from ').", "msMYGISLayerParseData()"); */ return(MS_FAILURE); } /* Copy the geometry column name */ memcpy(geom_column_name, data, (pos_scn)-(data)); geom_column_name[(pos_scn)-(data)] = 0; /* null terminate it */ /* Copy out the table name or sub-select clause */ if (pos_opt == NULL) { strcpy(table_name, pos_scn + 6); /* table name or sub-select clause */ } else { strncpy(table_name, pos_scn + 6, (pos_opt) - (pos_scn + 6)); table_name[(pos_opt) - (pos_scn + 6)] = 0; /* null terminate it */ } if ( (strlen(table_name) < 1 ) || (strlen(geom_column_name) < 1 ) ) { msSetError(MS_QUERYERR, DATAERRORMESSAGE(data,"Error parsing MYGIS data variable. Must contain 'geometry_column from table_name' or 'geom from (subselect) as foo' (couldnt find a geometry_column or table/subselect). More help:

\n
\n"), "msMYGISLayerParseData()"); return(MS_FAILURE); } /* printf("unique column = %s, srid='%s'
\n", urid_name,user_srid); */ return(MS_SUCCESS); } #else /* prototypes if MYGIS isnt supposed to be compiled */ int msMYGISLayerOpen(layerObj *layer) { msSetError(MS_QUERYERR, "msMYGISLayerOpen called but unimplemented! (mapserver not compiled with MYGIS support)", "msMYGISLayerOpen()"); return(MS_FAILURE); } int msMYGISLayerIsOpen(layerObj *layer) { msSetError(MS_QUERYERR, "msMYGISIsLayerOpen called but unimplemented! (mapserver not compiled with MYGIS support)", "msMYGISLayerIsOpen()"); return(MS_FALSE); } void msMYGISLayerFreeItemInfo(layerObj *layer) { msSetError(MS_QUERYERR, "msMYGISLayerFreeItemInfo called but unimplemented!(mapserver not compiled with MYGIS support)", "msMYGISLayerFreeItemInfo()"); } int msMYGISLayerInitItemInfo(layerObj *layer) { msSetError(MS_QUERYERR, "msMYGISLayerInitItemInfo called but unimplemented!(mapserver not compiled with MYGIS support)", "msMYGISLayerInitItemInfo()"); return(MS_FAILURE); } int msMYGISLayerWhichShapes(layerObj *layer, rectObj rect) { msSetError(MS_QUERYERR, "msMYGISLayerWhichShapes called but unimplemented!(mapserver not compiled with MYGIS support)", "msMYGISLayerWhichShapes()"); return(MS_FAILURE); } int msMYGISLayerClose(layerObj *layer) { msSetError(MS_QUERYERR, "msMYGISLayerClose called but unimplemented!(mapserver not compiled with MYGIS support)", "msMYGISLayerClose()"); return(MS_FAILURE); } int msMYGISLayerNextShape(layerObj *layer, shapeObj *shape) { msSetError(MS_QUERYERR, "msMYGISLayerNextShape called but unimplemented!(mapserver not compiled with MYGIS support)", "msMYGISLayerNextShape()"); return(MS_FAILURE); } int msMYGISLayerGetShape(layerObj *layer, shapeObj *shape, long record) { msSetError(MS_QUERYERR, "msMYGISLayerGetShape called but unimplemented!(mapserver not compiled with MYGIS support)", "msMYGISLayerGetShape()"); return(MS_FAILURE); } int msMYGISLayerGetExtent(layerObj *layer, rectObj *extent) { msSetError(MS_QUERYERR, "msMYGISLayerGetExtent called but unimplemented!(mapserver not compiled with MYGIS support)", "msMYGISLayerGetExtent()"); return(MS_FAILURE); } int msMYGISLayerGetShapeRandom(layerObj *layer, shapeObj *shape, long *record) { msSetError(MS_QUERYERR, "msMYGISLayerGetShapeRandom called but unimplemented!(mapserver not compiled with MYGIS support)", "msMYGISLayerGetShapeRandom()"); return(MS_FAILURE); } int msMYGISLayerGetItems(layerObj *layer) { msSetError(MS_QUERYERR, "msMYGISLayerGetItems called but unimplemented!(mapserver not compiled with MYGIS support)", "msMYGISLayerGetItems()"); return(MS_FAILURE); } #endif /* use_mygis */ int msMYGISLayerGetShapeVT(layerObj *layer, shapeObj *shape, int tile, long record) { return msMYGISLayerGetShape(layer, shape, record); } int msMYGISLayerInitializeVirtualTable(layerObj *layer) { assert(layer != NULL); assert(layer->vtable != NULL); layer->vtable->LayerInitItemInfo = msMYGISLayerInitItemInfo; layer->vtable->LayerFreeItemInfo = msMYGISLayerFreeItemInfo; layer->vtable->LayerOpen = msMYGISLayerOpen; layer->vtable->LayerIsOpen = msMYGISLayerIsOpen; layer->vtable->LayerWhichShapes = msMYGISLayerWhichShapes; layer->vtable->LayerNextShape = msMYGISLayerNextShape; layer->vtable->LayerGetShape = msMYGISLayerGetShapeVT; layer->vtable->LayerClose = msMYGISLayerClose; layer->vtable->LayerGetItems = msMYGISLayerGetItems; layer->vtable->LayerGetExtent = msMYGISLayerGetExtent; /* layer->vtable->LayerGetAutoStyle, use default */ layer->vtable->LayerCloseConnection = msMYGISLayerClose; layer->vtable->LayerSetTimeFilter = msLayerMakePlainTimeFilter; /* layer->vtable->LayerApplyFilterToLayer, use default */ /* layer->vtable->LayerCreateItems, use default */ /* layer->vtable->LayerGetNumFeatures, use default */ return MS_SUCCESS; }