/****************************************************************************** * * Project: MapServer * Purpose: Implements MapServer joins. * Author: Steve Lime and the MapServer team. * ****************************************************************************** * 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: mapjoin.c,v $ * Revision 1.29 2006/05/12 18:32:41 pramsey * Added support for postgresql joins (Bug 1570). * * Revision 1.28 2005/12/07 16:47:43 sdlime * Fixed potential segfault in mapjoin.c. (bug 1556) * * Revision 1.27 2005/06/14 16:03:33 dan * Updated copyright date to 2005 * * Revision 1.26 2005/02/18 03:06:46 dan * Turned all C++ (//) comments into C comments (bug 1238) * * Revision 1.25 2004/10/21 04:30:55 frank * Added standardized headers. Added MS_CVSID(). * */ #include "map.h" MS_CVSID("$Id: mapjoin.c,v 1.29 2006/05/12 18:32:41 pramsey Exp $") #define ROW_ALLOCATION_SIZE 10 /* DBF/XBase function prototypes */ int msDBFJoinConnect(layerObj *layer, joinObj *join); int msDBFJoinPrepare(joinObj *join, shapeObj *shape); int msDBFJoinNext(joinObj *join); int msDBFJoinClose(joinObj *join); int msDBFJoinTable(layerObj *layer, joinObj *join, shapeObj *shape); /* CSV (comma delimited text file) function prototypes */ int msCSVJoinConnect(layerObj *layer, joinObj *join); int msCSVJoinPrepare(joinObj *join, shapeObj *shape); int msCSVJoinNext(joinObj *join); int msCSVJoinClose(joinObj *join); int msCSVJoinTable(layerObj *layer, joinObj *join, shapeObj *shape); /* MySQL function prototypes */ int msMySQLJoinConnect(layerObj *layer, joinObj *join); int msMySQLJoinPrepare(joinObj *join, shapeObj *shape); int msMySQLJoinNext(joinObj *join); int msMySQLJoinClose(joinObj *join); int msMySQLJoinTable(layerObj *layer, joinObj *join, shapeObj *shape); /* PostgreSQL function prototypes */ int msPOSTGRESQLJoinConnect(layerObj *layer, joinObj *join); int msPOSTGRESQLJoinPrepare(joinObj *join, shapeObj *shape); int msPOSTGRESQLJoinNext(joinObj *join); int msPOSTGRESQLJoinClose(joinObj *join); /* wrapper function for DB specific join functions */ int msJoinConnect(layerObj *layer, joinObj *join) { switch(join->connectiontype) { case(MS_DB_XBASE): return msDBFJoinConnect(layer, join); break; case(MS_DB_CSV): return msCSVJoinConnect(layer, join); break; case(MS_DB_MYSQL): return msMySQLJoinConnect(layer, join); break; case(MS_DB_POSTGRES): return msPOSTGRESQLJoinConnect(layer, join); break; default: break; } msSetError(MS_JOINERR, "Unsupported join connection type.", "msJoinConnect()"); return MS_FAILURE; } int msJoinPrepare(joinObj *join, shapeObj *shape) { switch(join->connectiontype) { case(MS_DB_XBASE): return msDBFJoinPrepare(join, shape); break; case(MS_DB_CSV): return msCSVJoinPrepare(join, shape); break; case(MS_DB_MYSQL): return msMySQLJoinPrepare(join, shape); break; case(MS_DB_POSTGRES): return msPOSTGRESQLJoinPrepare(join, shape); break; default: break; } msSetError(MS_JOINERR, "Unsupported join connection type.", "msJoinPrepare()"); return MS_FAILURE; } int msJoinNext(joinObj *join) { switch(join->connectiontype) { case(MS_DB_XBASE): return msDBFJoinNext(join); break; case(MS_DB_CSV): return msCSVJoinNext(join); break; case(MS_DB_MYSQL): return msMySQLJoinNext(join); break; case(MS_DB_POSTGRES): return msPOSTGRESQLJoinNext(join); break; default: break; } msSetError(MS_JOINERR, "Unsupported join connection type.", "msJoinNext()"); return MS_FAILURE; } int msJoinClose(joinObj *join) { switch(join->connectiontype) { case(MS_DB_XBASE): return msDBFJoinClose(join); break; case(MS_DB_CSV): return msCSVJoinClose(join); break; case(MS_DB_MYSQL): return msMySQLJoinClose(join); break; case(MS_DB_POSTGRES): return msPOSTGRESQLJoinClose(join); break; default: break; } msSetError(MS_JOINERR, "Unsupported join connection type.", "msJoinClose()"); return MS_FAILURE; } /* */ /* XBASE join functions */ /* */ typedef struct { DBFHandle hDBF; int fromindex, toindex; char *target; int nextrecord; } msDBFJoinInfo; int msDBFJoinConnect(layerObj *layer, joinObj *join) { int i; char szPath[MS_MAXPATHLEN]; msDBFJoinInfo *joininfo; if(join->joininfo) return(MS_SUCCESS); /* already open */ /* allocate a msDBFJoinInfo struct */ joininfo = (msDBFJoinInfo *) malloc(sizeof(msDBFJoinInfo)); if(!joininfo) { msSetError(MS_MEMERR, "Error allocating XBase table info structure.", "msDBFJoinConnect()"); return(MS_FAILURE); } /* initialize any members that won't get set later on in this function */ joininfo->target = NULL; joininfo->nextrecord = 0; join->joininfo = joininfo; /* open the XBase file */ if((joininfo->hDBF = msDBFOpen( msBuildPath3(szPath, layer->map->mappath, layer->map->shapepath, join->table), "rb" )) == NULL) { if((joininfo->hDBF = msDBFOpen( msBuildPath(szPath, layer->map->mappath, join->table), "rb" )) == NULL) { msSetError(MS_IOERR, "(%s)", "msDBFJoinConnect()", join->table); return(MS_FAILURE); } } /* get "to" item index */ if((joininfo->toindex = msDBFGetItemIndex(joininfo->hDBF, join->to)) == -1) { msSetError(MS_DBFERR, "Item %s not found in table %s.", "msDBFJoinConnect()", join->to, join->table); return(MS_FAILURE); } /* get "from" item index */ for(i=0; inumitems; i++) { if(strcasecmp(layer->items[i],join->from) == 0) { /* found it */ joininfo->fromindex = i; break; } } if(i == layer->numitems) { msSetError(MS_JOINERR, "Item %s not found in layer %s.", "msDBFJoinConnect()", join->from, layer->name); return(MS_FAILURE); } /* finally store away the item names in the XBase table */ join->numitems = msDBFGetFieldCount(joininfo->hDBF); join->items = msDBFGetItems(joininfo->hDBF); if(!join->items) return(MS_FAILURE); return(MS_SUCCESS); } int msDBFJoinPrepare(joinObj *join, shapeObj *shape) { msDBFJoinInfo *joininfo = join->joininfo; if(!joininfo) { msSetError(MS_JOINERR, "Join connection has not be created.", "msDBFJoinPrepare()"); return(MS_FAILURE); } if(!shape) { msSetError(MS_JOINERR, "Shape to be joined is empty.", "msDBFJoinPrepare()"); return(MS_FAILURE); } if(!shape->values) { msSetError(MS_JOINERR, "Shape to be joined has no attributes.", "msDBFJoinPrepare()"); return(MS_FAILURE); } joininfo->nextrecord = 0; /* starting with the first record */ if(joininfo->target) free(joininfo->target); /* clear last target */ joininfo->target = strdup(shape->values[joininfo->fromindex]); return(MS_SUCCESS); } int msDBFJoinNext(joinObj *join) { int i, n; msDBFJoinInfo *joininfo = join->joininfo; if(!joininfo) { msSetError(MS_JOINERR, "Join connection has not be created.", "msDBFJoinNext()"); return(MS_FAILURE); } if(!joininfo->target) { msSetError(MS_JOINERR, "No target specified, run msDBFJoinPrepare() first.", "msDBFJoinNext()"); return(MS_FAILURE); } /* clear any old data */ if(join->values) { msFreeCharArray(join->values, join->numitems); join->values = NULL; } n = msDBFGetRecordCount(joininfo->hDBF); for(i=joininfo->nextrecord; itarget, msDBFReadStringAttribute(joininfo->hDBF, i, joininfo->toindex)) == 0) break; } if(i == n) { /* unable to do the join */ if((join->values = (char **)malloc(sizeof(char *)*join->numitems)) == NULL) { msSetError(MS_MEMERR, NULL, "msDBFJoinNext()"); return(MS_FAILURE); } for(i=0; inumitems; i++) join->values[i] = strdup("\0"); /* intialize to zero length strings */ joininfo->nextrecord = n; return(MS_DONE); } if((join->values = msDBFGetValues(joininfo->hDBF,i)) == NULL) return(MS_FAILURE); joininfo->nextrecord = i+1; /* so we know where to start looking next time through */ return(MS_SUCCESS); } int msDBFJoinClose(joinObj *join) { msDBFJoinInfo *joininfo = join->joininfo; if(!joininfo) return(MS_SUCCESS); /* already closed */ if(joininfo->hDBF) msDBFClose(joininfo->hDBF); if(joininfo->target) free(joininfo->target); free(joininfo); joininfo = NULL; return(MS_SUCCESS); } /* */ /* CSV (comma separated value) join functions */ /* */ typedef struct { int fromindex, toindex; char *target; char ***rows; int numrows; int nextrow; } msCSVJoinInfo; int msCSVJoinConnect(layerObj *layer, joinObj *join) { int i; FILE *stream; char szPath[MS_MAXPATHLEN]; msCSVJoinInfo *joininfo; char buffer[MS_BUFFER_LENGTH]; if(join->joininfo) return(MS_SUCCESS); /* already open */ /* allocate a msCSVJoinInfo struct */ if((joininfo = (msCSVJoinInfo *) malloc(sizeof(msCSVJoinInfo))) == NULL) { msSetError(MS_MEMERR, "Error allocating CSV table info structure.", "msCSVJoinConnect()"); return(MS_FAILURE); } /* initialize any members that won't get set later on in this function */ joininfo->target = NULL; joininfo->nextrow = 0; join->joininfo = joininfo; /* open the CSV file */ if((stream = fopen( msBuildPath3(szPath, layer->map->mappath, layer->map->shapepath, join->table), "r" )) == NULL) { if((stream = fopen( msBuildPath(szPath, layer->map->mappath, join->table), "r" )) == NULL) { msSetError(MS_IOERR, "(%s)", "msCSVJoinConnect()", join->table); return(MS_FAILURE); } } /* once through to get the number of rows */ joininfo->numrows = 0; while(fgets(buffer, MS_BUFFER_LENGTH, stream) != NULL) joininfo->numrows++; rewind(stream); if((joininfo->rows = (char ***) malloc(joininfo->numrows*sizeof(char **))) == NULL) { msSetError(MS_MEMERR, "Error allocating rows.", "msCSVJoinConnect()"); return(MS_FAILURE); } /* load the rows */ i = 0; while(fgets(buffer, MS_BUFFER_LENGTH, stream) != NULL) { trimEOL(buffer); joininfo->rows[i] = split(buffer, ',', &(join->numitems)); i++; } fclose(stream); /* get "from" item index */ for(i=0; inumitems; i++) { if(strcasecmp(layer->items[i],join->from) == 0) { /* found it */ joininfo->fromindex = i; break; } } if(i == layer->numitems) { msSetError(MS_JOINERR, "Item %s not found in layer %s.", "msCSVJoinConnect()", join->from, layer->name); return(MS_FAILURE); } /* get "to" index (for now the user tells us which column, 1..n) */ joininfo->toindex = atoi(join->to) - 1; if(joininfo->toindex < 0 || joininfo->toindex > join->numitems) { msSetError(MS_JOINERR, "Invalid column index %s.", "msCSVJoinConnect()", join->to); return(MS_FAILURE); } /* store away the column names (1..n) */ if((join->items = (char **) malloc(sizeof(char *)*join->numitems)) == NULL) { msSetError(MS_MEMERR, "Error allocating space for join item names.", "msCSVJoinConnect()"); return(MS_FAILURE); } for(i=0; inumitems; i++) { join->items[i] = (char *) malloc(8); /* plenty of space */ sprintf(join->items[i], "%d", i+1); } return(MS_SUCCESS); } int msCSVJoinPrepare(joinObj *join, shapeObj *shape) { msCSVJoinInfo *joininfo = join->joininfo; if(!joininfo) { msSetError(MS_JOINERR, "Join connection has not be created.", "msCSVJoinPrepare()"); return(MS_FAILURE); } if(!shape) { msSetError(MS_JOINERR, "Shape to be joined is empty.", "msCSVJoinPrepare()"); return(MS_FAILURE); } if(!shape->values) { msSetError(MS_JOINERR, "Shape to be joined has no attributes.", "msCSVJoinPrepare()"); return(MS_FAILURE); } joininfo->nextrow = 0; /* starting with the first record */ if(joininfo->target) free(joininfo->target); /* clear last target */ joininfo->target = strdup(shape->values[joininfo->fromindex]); return(MS_SUCCESS); } int msCSVJoinNext(joinObj *join) { int i,j; msCSVJoinInfo *joininfo = join->joininfo; if(!joininfo) { msSetError(MS_JOINERR, "Join connection has not be created.", "msCSVJoinNext()"); return(MS_FAILURE); } /* clear any old data */ if(join->values) { msFreeCharArray(join->values, join->numitems); join->values = NULL; } for(i=joininfo->nextrow; inumrows; i++) { /* find a match */ if(strcmp(joininfo->target, joininfo->rows[i][joininfo->toindex]) == 0) break; } if((join->values = (char ** )malloc(sizeof(char *)*join->numitems)) == NULL) { msSetError(MS_MEMERR, NULL, "msCSVJoinNext()"); return(MS_FAILURE); } if(i == joininfo->numrows) { /* unable to do the join */ for(j=0; jnumitems; j++) join->values[j] = strdup("\0"); /* intialize to zero length strings */ joininfo->nextrow = joininfo->numrows; return(MS_DONE); } for(j=0; jnumitems; j++) join->values[j] = strdup(joininfo->rows[i][j]); joininfo->nextrow = i+1; /* so we know where to start looking next time through */ return(MS_SUCCESS); } int msCSVJoinClose(joinObj *join) { int i; msCSVJoinInfo *joininfo = join->joininfo; if(!joininfo) return(MS_SUCCESS); /* already closed */ for(i=0; inumrows; i++) msFreeCharArray(joininfo->rows[i], join->numitems); free(joininfo->rows); if(joininfo->target) free(joininfo->target); free(joininfo); joininfo = NULL; return(MS_SUCCESS); } #ifdef USE_MYGIS #ifndef _mysql_h #include #endif char* DB_HOST = NULL; char* DB_USER = NULL; char* DB_PASSWD = NULL; char* DB_DATABASE = NULL; char* delim; #define MYDEBUG if (0) MYSQL_RES *msMySQLQuery(char *q, MYSQL *conn) { MYSQL_RES *qresult=NULL; if (mysql_query(conn,q) < 0){ mysql_close(conn); msSetError(MS_QUERYERR, "Bad mysql query (%s)", "msMySQLQuery()", q); return qresult; } if (!(qresult=mysql_store_result(conn))) { mysql_close(conn); msSetError(MS_QUERYERR, "mysql query failed (%s)", "msMySQLQuery()", q); return qresult; } return qresult; } /* */ /* mysql join functions */ /* */ typedef struct { MYSQL mysql, *conn; MYSQL_RES *qresult; MYSQL_ROW row; int rows; int fromindex; char *tocolumn; char *target; int nextrecord; } msMySQLJoinInfo; #endif int msMySQLJoinConnect(layerObj *layer, joinObj *join) { #ifndef USE_MYGIS msSetError(MS_QUERYERR, "MySQL support not available (compile with --with-mygis)", "msMySQLJoinConnect()"); return(MS_FAILURE); #else int i; char qbuf[4000]; msMySQLJoinInfo *joininfo; MYDEBUG if (setvbuf(stdout, NULL, _IONBF , 0)){printf("Whoops...");}; if(join->joininfo) return(MS_SUCCESS); /* already open */ /* allocate a msMySQLJoinInfo struct */ joininfo = (msMySQLJoinInfo *) malloc(sizeof(msMySQLJoinInfo)); if(!joininfo) { msSetError(MS_MEMERR, "Error allocating mysql table info structure.", "msMySQLJoinConnect()"); return(MS_FAILURE); } /* initialize any members that won't get set later on in this function */ joininfo->qresult = NULL; joininfo->target = NULL; joininfo->nextrecord = 0; join->joininfo = joininfo; /* open the mysql connection */ if( join->connection == NULL ) { msSetError(MS_QUERYERR, "Error parsing MYSQL JOIN: nothing specified in CONNECTION statement.", "msMySQLJoinConnect()"); return(MS_FAILURE); } delim = strdup(":"); DB_HOST = strdup(strtok(join->connection, delim)); DB_USER = strdup(strtok(NULL, delim)); DB_PASSWD = strdup(strtok(NULL, delim)); DB_DATABASE = strdup(strtok(NULL, delim)); if (DB_HOST == NULL || DB_USER == NULL || DB_PASSWD == NULL || DB_DATABASE == NULL) { msSetError(MS_QUERYERR, "DB param error: at least one of HOST, USER, PASSWD or DATABASE is null!", "msMySQLJoinConnect()"); return MS_FAILURE; } if (strcmp(DB_PASSWD, "none") == 0) strcpy(DB_PASSWD, ""); #if MYSQL_VERSION_ID >= 40000 mysql_init(&(joininfo->mysql)); if (!(joininfo->conn = mysql_real_connect(&(joininfo->mysql),DB_HOST,DB_USER,DB_PASSWD,NULL, 0, NULL, 0))) #else if (!(joininfo->conn = mysql_connect(&(joininfo->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(joininfo->conn), DB_HOST, DB_USER, DB_PASSWD); msSetError(MS_QUERYERR, tmp, "msMYGISLayerOpen()"); free(joininfo); return MS_FAILURE; } MYDEBUG printf("msMYGISLayerOpen2 called
\n"); if (mysql_select_db(joininfo->conn,DB_DATABASE) < 0) { mysql_close(joininfo->conn); } MYDEBUG printf("msMYGISLayerOpen3 called
\n"); if (joininfo->qresult != NULL) /* query leftover */ { MYDEBUG printf("msMYGISLayerOpen4 called
\n"); mysql_free_result(joininfo->qresult); } MYDEBUG printf("msMYGISLayerOpen5 called
\n"); sprintf(qbuf, "SELECT count(%s) FROM %s", join->to, join->table); MYDEBUG printf("%s
\n", qbuf); if ((joininfo->qresult = msMySQLQuery(qbuf, joininfo->conn))) /* There were some rows found, write 'em out for debug */ { int numrows = mysql_affected_rows(joininfo->conn); MYDEBUG printf("%d rows
\n", numrows); for(i=0;iqresult); MYDEBUG printf("(%s)
\n",row[0]); joininfo->rows = atoi(row[0]); } } else { msSetError(MS_DBFERR, "Item %s not found in table %s.", "msMySQLJoinConnect()", join->to, join->table); return(MS_FAILURE); } sprintf(qbuf, "EXPLAIN %s", join->table); if ((joininfo->qresult = msMySQLQuery(qbuf, joininfo->conn))) /* There were some rows found, write 'em out for debug */ { join->numitems = mysql_affected_rows(joininfo->conn); if((join->items = (char **)malloc(sizeof(char *)*join->numitems)) == NULL) { msSetError(MS_MEMERR, NULL, "msMySQLJoinConnect()"); return(MS_FAILURE); } MYDEBUG printf("%d rows
\n", join->numitems); for(i=0;inumitems;i++) { MYSQL_ROW row = mysql_fetch_row(joininfo->qresult); MYDEBUG printf("(%s)
\n",row[0]); join->items[i] = strdup(row[0]); } } else { msSetError(MS_DBFERR, "Item %s not found in table %s.", "msMySQLJoinConnect()", join->to, join->table); return(MS_FAILURE); } joininfo->tocolumn = strdup(join->to); /* get "from" item index */ for(i=0; inumitems; i++) { if(strcasecmp(layer->items[i],join->from) == 0) { /* found it */ joininfo->fromindex = i; break; } } if(i == layer->numitems) { msSetError(MS_JOINERR, "Item %s not found in layer %s.", "msMySQLJoinConnect()", join->from, layer->name); return(MS_FAILURE); } /* finally store away the item names in the XBase table */ if(!join->items) return(MS_FAILURE); return(MS_SUCCESS); #endif } int msMySQLJoinPrepare(joinObj *join, shapeObj *shape) { #ifndef USE_MYGIS msSetError(MS_QUERYERR, "MySQL support not available (compile with --with-mygis)", "msMySQLJoinPrepare()"); return(MS_FAILURE); #else msMySQLJoinInfo *joininfo = join->joininfo; if(!joininfo) { msSetError(MS_JOINERR, "Join connection has not be created.", "msMySQLJoinPrepare()"); return(MS_FAILURE); } if(!shape) { msSetError(MS_JOINERR, "Shape to be joined is empty.", "msMySQLJoinPrepare()"); return(MS_FAILURE); } if(!shape->values) { msSetError(MS_JOINERR, "Shape to be joined has no attributes.", "msMySQLJoinPrepare()"); return(MS_FAILURE); } joininfo->nextrecord = 0; /* starting with the first record */ if(joininfo->target) free(joininfo->target); /* clear last target */ joininfo->target = strdup(shape->values[joininfo->fromindex]); return(MS_SUCCESS); #endif } int msMySQLJoinNext(joinObj *join) { #ifndef USE_MYGIS msSetError(MS_QUERYERR, "MySQL support not available (compile with --with-mygis)", "msMySQLJoinNext()"); return(MS_FAILURE); #else int i, n; char qbuf[4000]; msMySQLJoinInfo *joininfo = join->joininfo; if(!joininfo) { msSetError(MS_JOINERR, "Join connection has not be created.", "msMySQLJoinNext()"); return(MS_FAILURE); } if(!joininfo->target) { msSetError(MS_JOINERR, "No target specified, run msMySQLJoinPrepare() first.", "msMySQLJoinNext()"); return(MS_FAILURE); } /* clear any old data */ if(join->values) { msFreeCharArray(join->values, join->numitems); join->values = NULL; } n = joininfo->rows; /* for(i=joininfo->nextrecord; itarget, msMySQLReadStringAttribute(joininfo->conn, i, joininfo->toindex)) == 0) break; */ /* } */ sprintf(qbuf, "SELECT * FROM %s WHERE %s = %s", join->table, joininfo->tocolumn, joininfo->target); MYDEBUG printf("%s
\n", qbuf); if ((joininfo->qresult = msMySQLQuery(qbuf, joininfo->conn))) /* There were some rows found, write 'em out for debug */ { int numrows = mysql_affected_rows(joininfo->conn); int numfields = mysql_field_count(joininfo->conn); MYDEBUG printf("%d rows
\n", numrows); if (numrows > 0) { MYSQL_ROW row = mysql_fetch_row(joininfo->qresult); for(i=0; i\n"); free(join->values); if((join->values = (char **)malloc(sizeof(char *)*join->numitems)) == NULL) { msSetError(MS_MEMERR, NULL, "msMySQLJoinNext()"); return(MS_FAILURE); } for(i=0; inumitems; i++){ /* join->values[i] = strdup("\0"); */ /* intialize to zero length strings */ join->values[i] = strdup(row[i]); /* intialize to zero length strings */ /* rows = atoi(row[0]); */ } } else { if((join->values = (char **)malloc(sizeof(char *)*join->numitems)) == NULL) { msSetError(MS_MEMERR, NULL, "msMySQLJoinNext()"); return(MS_FAILURE); } for(i=0; inumitems; i++) join->values[i] = strdup("\0"); /* intialize to zero length strings */ return(MS_DONE); } } else { msSetError(MS_QUERYERR, "Query error (%s)", "msMySQLJoinNext()", qbuf); return(MS_FAILURE); } #ifdef __NOTDEF__ if(i == n) { /* unable to do the join */ if((join->values = (char **)malloc(sizeof(char *)*join->numitems)) == NULL) { msSetError(MS_MEMERR, NULL, "msMySQLJoinNext()"); return(MS_FAILURE); } for(i=0; inumitems; i++) join->values[i] = strdup("\0"); /* intialize to zero length strings */ joininfo->nextrecord = n; return(MS_DONE); } if((join->values = msMySQLGetValues(joininfo->conn,i)) == NULL) return(MS_FAILURE); joininfo->nextrecord = i+1; /* so we know where to start looking next time through */ #endif /* __NOTDEF__ */ return(MS_SUCCESS); #endif } int msMySQLJoinClose(joinObj *join) { #ifndef USE_MYGIS msSetError(MS_QUERYERR, "MySQL support not available (compile with --with-mygis)", "msMySQLJoinClose()"); return(MS_FAILURE); #else msMySQLJoinInfo *joininfo = join->joininfo; if(!joininfo) return(MS_SUCCESS); /* already closed */ mysql_close(joininfo->conn); if(joininfo->target) free(joininfo->target); free(joininfo); joininfo = NULL; return(MS_SUCCESS); #endif }