Datum LWGEOM_from_text(PG_FUNCTION_ARGS) { text *wkttext = PG_GETARG_TEXT_P(0); char *wkt = text2cstring(wkttext); LWGEOM_PARSER_RESULT lwg_parser_result; GSERIALIZED *geom_result = NULL; LWGEOM *lwgeom; POSTGIS_DEBUG(2, "LWGEOM_from_text"); POSTGIS_DEBUGF(3, "wkt: [%s]", wkt); if (lwgeom_parse_wkt(&lwg_parser_result, wkt, LW_PARSER_CHECK_ALL) == LW_FAILURE) PG_PARSER_ERROR(lwg_parser_result); lwgeom = lwg_parser_result.geom; if ( lwgeom->srid != SRID_UNKNOWN ) { elog(WARNING, "OGC WKT expected, EWKT provided - use GeomFromEWKT() for this"); } /* read user-requested SRID if any */ if ( PG_NARGS() > 1 ) lwgeom_set_srid(lwgeom, PG_GETARG_INT32(1)); geom_result = geometry_serialize(lwgeom); lwgeom_parser_result_free(&lwg_parser_result); PG_RETURN_POINTER(geom_result); }
Datum line_from_encoded_polyline(PG_FUNCTION_ARGS) { GSERIALIZED *geom; LWGEOM *lwgeom; text *encodedpolyline_input; char *encodedpolyline; int precision = 5; if (PG_ARGISNULL(0)) PG_RETURN_NULL(); encodedpolyline_input = PG_GETARG_TEXT_P(0); encodedpolyline = text2cstring(encodedpolyline_input); if (PG_NARGS() >2 && !PG_ARGISNULL(2)) { precision = PG_GETARG_INT32(2); if ( precision < 0 ) precision = 5; } lwgeom = lwgeom_from_encoded_polyline(encodedpolyline, precision); if ( ! lwgeom ) { /* Shouldn't get here */ elog(ERROR, "lwgeom_from_encoded_polyline returned NULL"); PG_RETURN_NULL(); } lwgeom_set_srid(lwgeom, 4326); geom = geometry_serialize(lwgeom); lwgeom_free(lwgeom); PG_RETURN_POINTER(geom); }
Datum point_from_geohash(PG_FUNCTION_ARGS) { GBOX *box = NULL; LWPOINT *point = NULL; GSERIALIZED *result = NULL; text *geohash_input = NULL; char *geohash = NULL; double lon, lat; int precision = -1; if (PG_ARGISNULL(0)) { PG_RETURN_NULL(); } if (!PG_ARGISNULL(1)) { precision = PG_GETARG_INT32(1); } geohash_input = PG_GETARG_TEXT_P(0); geohash = text2cstring(geohash_input); box = parse_geohash(geohash, precision); lon = box->xmin + (box->xmax - box->xmin) / 2; lat = box->ymin + (box->ymax - box->ymin) / 2; point = lwpoint_make2d(SRID_UNKNOWN, lon, lat); result = geometry_serialize((LWGEOM *) point); lwfree(box); PG_RETURN_POINTER(result); }
Datum geography_from_text(PG_FUNCTION_ARGS) { text *wkt_text = PG_GETARG_TEXT_P(0); /* Extract the cstring from the varlena */ char *wkt = text2cstring(wkt_text); /* Pass the cstring to the input parser, and magic occurs! */ Datum rv = DirectFunctionCall3(geography_in, PointerGetDatum(wkt), Int32GetDatum(0), Int32GetDatum(-1)); /* Clean up and return */ pfree(wkt); PG_RETURN_DATUM(rv); }
Datum ST_RelateMatch(PG_FUNCTION_ARGS) { #if POSTGIS_GEOS_VERSION < 33 lwerror("The GEOS version this postgis binary " "was compiled against (%d) doesn't support " "'ST_RelateMatch' function (3.3.0+ required)", POSTGIS_GEOS_VERSION); PG_RETURN_NULL(); #else /* POSTGIS_GEOS_VERSION >= 33 */ char *mat, *pat; text *mat_text, *pat_text; int result; /* Read the arguments */ mat_text = (PG_GETARG_TEXT_P(0)); pat_text = (PG_GETARG_TEXT_P(1)); /* Convert from text to cstring */ mat = text2cstring(mat_text); pat = text2cstring(pat_text); initGEOS(lwnotice, lwgeom_geos_error); result = GEOSRelatePatternMatch(mat, pat); if (result == 2) { lwfree(mat); lwfree(pat); lwerror("GEOSRelatePatternMatch: %s", lwgeom_geos_errmsg); PG_RETURN_NULL(); } lwfree(mat); lwfree(pat); PG_RETURN_BOOL(result); #endif /* POSTGIS_GEOS_VERSION >= 33 */ }
Datum sfcgal_from_ewkt(PG_FUNCTION_ARGS) { GSERIALIZED* result; sfcgal_prepared_geometry_t* g; text *wkttext = PG_GETARG_TEXT_P(0); char *cstring = text2cstring(wkttext); sfcgal_postgis_init(); g = sfcgal_io_read_ewkt( cstring, strlen(cstring) ); result = SFCGALPreparedGeometry2POSTGIS( g, 0 ); sfcgal_prepared_geometry_delete( g ); PG_RETURN_POINTER(result); }
Datum parse_WKT_lwgeom(PG_FUNCTION_ARGS) { text *wkt_text = PG_GETARG_TEXT_P(0); char *wkt; Datum result; /* Unwrap the PgSQL text type into a cstring */ wkt = text2cstring(wkt_text); /* Now we call over to the geometry_in function */ result = DirectFunctionCall1(LWGEOM_in, CStringGetDatum(wkt)); /* Return null on null */ if ( ! result ) PG_RETURN_NULL(); PG_RETURN_DATUM(result); }
Datum geography_from_binary(PG_FUNCTION_ARGS) { char *wkb_cstring = NULL; text *wkb_hex = NULL; char *wkb_bytea = (char*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); char *hexarg = palloc(4 + VARHDRSZ); /* Create our second argument to binary_encode */ SET_VARSIZE(hexarg, 4 + VARHDRSZ); memcpy(VARDATA(hexarg), "hex", 4); /* Convert the bytea into a hex representation cstring */ wkb_hex = (text*)DatumGetPointer(DirectFunctionCall2(binary_encode, PointerGetDatum(wkb_bytea), PointerGetDatum(hexarg))); wkb_cstring = text2cstring(wkb_hex); pfree(hexarg); /* Pass the cstring to the input parser, and magic occurs! */ PG_RETURN_DATUM(DirectFunctionCall3(geography_in, PointerGetDatum(wkb_cstring), Int32GetDatum(0), Int32GetDatum(-1))); }
Datum geom_from_geojson(PG_FUNCTION_ARGS) { #ifndef HAVE_LIBJSON elog(ERROR, "You need JSON-C for ST_GeomFromGeoJSON"); PG_RETURN_NULL(); #else /* HAVE_LIBJSON */ GSERIALIZED *geom; LWGEOM *lwgeom; text *geojson_input; char *geojson; char *srs = NULL; /* Get the geojson stream */ if (PG_ARGISNULL(0)) PG_RETURN_NULL(); geojson_input = PG_GETARG_TEXT_P(0); geojson = text2cstring(geojson_input); lwgeom = lwgeom_from_geojson(geojson, &srs); if ( ! lwgeom ) { /* Shouldn't get here */ elog(ERROR, "lwgeom_from_geojson returned NULL"); PG_RETURN_NULL(); } if ( srs ) { lwgeom_set_srid(lwgeom, getSRIDbySRS(srs)); lwfree(srs); } geom = geometry_serialize(lwgeom); lwgeom_free(lwgeom); PG_RETURN_POINTER(geom); #endif }
Datum geography_from_text(PG_FUNCTION_ARGS) { LWGEOM_PARSER_RESULT lwg_parser_result; GSERIALIZED *g_ser = NULL; text *wkt_text = PG_GETARG_TEXT_P(0); /* Extract the cstring from the varlena */ char *wkt = text2cstring(wkt_text); /* Pass the cstring to the input parser, and magic occurs! */ if ( lwgeom_parse_wkt(&lwg_parser_result, wkt, LW_PARSER_CHECK_ALL) == LW_FAILURE ) PG_PARSER_ERROR(lwg_parser_result); /* Clean up string */ pfree(wkt); g_ser = gserialized_geography_from_lwgeom(lwg_parser_result.geom, -1); /* Clean up temporary object */ lwgeom_free(lwg_parser_result.geom); PG_RETURN_POINTER(g_ser); }
Datum box2d_from_geohash(PG_FUNCTION_ARGS) { GBOX *box = NULL; text *geohash_input = NULL; char *geohash = NULL; int precision = -1; if (PG_ARGISNULL(0)) { PG_RETURN_NULL(); } if (!PG_ARGISNULL(1)) { precision = PG_GETARG_INT32(1); } geohash_input = PG_GETARG_TEXT_P(0); geohash = text2cstring(geohash_input); box = parse_geohash(geohash, precision); PG_RETURN_POINTER(box); }
Datum geom_from_geojson(PG_FUNCTION_ARGS) { #ifndef HAVE_LIBJSON elog(ERROR, "You need JSON-C for ST_GeomFromGeoJSON"); PG_RETURN_NULL(); #else /* HAVE_LIBJSON */ GSERIALIZED *geom; LWGEOM *lwgeom; text *geojson_input; int geojson_size; char *geojson; int root_srid=0; bool hasz=true; json_tokener* jstok = NULL; json_object* poObj = NULL; json_object* poObjSrs = NULL; /* Get the geojson stream */ if (PG_ARGISNULL(0)) PG_RETURN_NULL(); geojson_input = PG_GETARG_TEXT_P(0); geojson = text2cstring(geojson_input); geojson_size = VARSIZE(geojson_input) - VARHDRSZ; /* Begin to Parse json */ jstok = json_tokener_new(); poObj = json_tokener_parse_ex(jstok, geojson, -1); if( jstok->err != json_tokener_success) { char err[256]; snprintf(err, 256, "%s (at offset %d)", json_tokener_errors[jstok->err], jstok->char_offset); json_tokener_free(jstok); geojson_lwerror(err, 1); } json_tokener_free(jstok); poObjSrs = findMemberByName( poObj, "crs" ); if (poObjSrs != NULL) { json_object* poObjSrsType = findMemberByName( poObjSrs, "type" ); if (poObjSrsType != NULL) { json_object* poObjSrsProps = findMemberByName( poObjSrs, "properties" ); json_object* poNameURL = findMemberByName( poObjSrsProps, "name" ); const char* pszName = json_object_get_string( poNameURL ); root_srid = getSRIDbySRS(pszName); POSTGIS_DEBUGF(3, "getSRIDbySRS returned root_srid = %d.", root_srid ); } } lwgeom = parse_geojson(poObj, &hasz, &root_srid); lwgeom_add_bbox(lwgeom); if (root_srid && lwgeom->srid == -1) lwgeom->srid = root_srid; if (!hasz) { LWGEOM *tmp = lwgeom_force_2d(lwgeom); lwgeom_free(lwgeom); lwgeom = tmp; POSTGIS_DEBUG(2, "geom_from_geojson called."); } geom = geometry_serialize(lwgeom); lwgeom_free(lwgeom); PG_RETURN_POINTER(geom); #endif }
Datum geom_from_kml(PG_FUNCTION_ARGS) { GSERIALIZED *geom; LWGEOM *lwgeom, *hlwgeom; xmlDocPtr xmldoc; text *xml_input; int xml_size; char *xml; bool hasz=true; xmlNodePtr xmlroot=NULL; /* Get the KML stream */ if (PG_ARGISNULL(0)) PG_RETURN_NULL(); xml_input = PG_GETARG_TEXT_P(0); xml = text2cstring(xml_input); xml_size = VARSIZE(xml_input) - VARHDRSZ; /* Begin to Parse XML doc */ xmlInitParser(); xmldoc = xmlParseMemory(xml, xml_size); if (!xmldoc || (xmlroot = xmlDocGetRootElement(xmldoc)) == NULL) { xmlFreeDoc(xmldoc); xmlCleanupParser(); lwerror("invalid KML representation"); } lwgeom = parse_kml(xmlroot, &hasz); /* Homogenize geometry result if needed */ if (lwgeom->type == COLLECTIONTYPE) { hlwgeom = lwgeom_homogenize(lwgeom); lwgeom_release(lwgeom); lwgeom = hlwgeom; } lwgeom_add_bbox(lwgeom); /* KML geometries could be either 2 or 3D * * So we deal with 3D in all structures allocation, and flag hasz * to false if we met once a missing Z dimension * In this case, we force recursive 2D. */ if (!hasz) { LWGEOM *tmp = lwgeom_force_2d(lwgeom); lwgeom_free(lwgeom); lwgeom = tmp; } geom = geometry_serialize(lwgeom); lwgeom_free(lwgeom); xmlFreeDoc(xmldoc); xmlCleanupParser(); PG_RETURN_POINTER(geom); }
Datum LWGEOM_to_latlon(PG_FUNCTION_ARGS) { /* Get the parameters */ GSERIALIZED *pg_lwgeom = (GSERIALIZED *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); text *format_text = PG_GETARG_TEXT_P(1); LWGEOM *lwgeom; char *format_str = NULL; char * formatted_str; text * formatted_text; char * tmp; /* Only supports points. */ uint8_t geom_type = gserialized_get_type(pg_lwgeom); if (POINTTYPE != geom_type) { lwerror("Only points are supported, you tried type %s.", lwtype_name(geom_type)); } /* Convert to LWGEOM type */ lwgeom = lwgeom_from_gserialized(pg_lwgeom); if (format_text == NULL) { lwerror("ST_AsLatLonText: invalid format string (null"); PG_RETURN_NULL(); } format_str = text2cstring(format_text); assert(format_str != NULL); /* The input string supposedly will be in the database encoding, so convert to UTF-8. */ tmp = (char *)pg_do_encoding_conversion( (uint8_t *)format_str, strlen(format_str), GetDatabaseEncoding(), PG_UTF8); assert(tmp != NULL); if ( tmp != format_str ) { pfree(format_str); format_str = tmp; } /* Produce the formatted string. */ formatted_str = lwpoint_to_latlon((LWPOINT *)lwgeom, format_str); assert(formatted_str != NULL); pfree(format_str); /* Convert the formatted string from UTF-8 back to database encoding. */ tmp = (char *)pg_do_encoding_conversion( (uint8_t *)formatted_str, strlen(formatted_str), PG_UTF8, GetDatabaseEncoding()); assert(tmp != NULL); if ( tmp != formatted_str) { pfree(formatted_str); formatted_str = tmp; } /* Convert to the postgres output string type. */ formatted_text = cstring2text(formatted_str); pfree(formatted_str); PG_RETURN_POINTER(formatted_text); }
Datum transform_geom(PG_FUNCTION_ARGS) { GSERIALIZED *geom; GSERIALIZED *result=NULL; LWGEOM *lwgeom; projPJ input_pj, output_pj; char *input_proj4, *output_proj4; text *input_proj4_text; text *output_proj4_text; int32 result_srid ; char *pj_errstr; result_srid = PG_GETARG_INT32(3); if (result_srid == SRID_UNKNOWN) { elog(ERROR,"tranform: destination SRID = %d",SRID_UNKNOWN); PG_RETURN_NULL(); } geom = (GSERIALIZED *)PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0)); if (gserialized_get_srid(geom) == SRID_UNKNOWN) { pfree(geom); elog(ERROR,"transform_geom: source SRID = %d",SRID_UNKNOWN); PG_RETURN_NULL(); } /* Set the search path if we haven't already */ SetPROJ4LibPath(); /* Read the arguments */ input_proj4_text = (PG_GETARG_TEXT_P(1)); output_proj4_text = (PG_GETARG_TEXT_P(2)); /* Convert from text to cstring for libproj */ input_proj4 = text2cstring(input_proj4_text); output_proj4 = text2cstring(output_proj4_text); /* make input and output projection objects */ input_pj = lwproj_from_string(input_proj4); if ( input_pj == NULL ) { pj_errstr = pj_strerrno(*pj_get_errno_ref()); if ( ! pj_errstr ) pj_errstr = ""; /* we need this for error reporting */ /* pfree(input_proj4); */ pfree(output_proj4); pfree(geom); elog(ERROR, "transform_geom: could not parse proj4 string '%s' %s", input_proj4, pj_errstr); PG_RETURN_NULL(); } pfree(input_proj4); output_pj = lwproj_from_string(output_proj4); if ( output_pj == NULL ) { pj_errstr = pj_strerrno(*pj_get_errno_ref()); if ( ! pj_errstr ) pj_errstr = ""; /* we need this for error reporting */ /* pfree(output_proj4); */ pj_free(input_pj); pfree(geom); elog(ERROR, "transform_geom: couldn't parse proj4 output string: '%s': %s", output_proj4, pj_errstr); PG_RETURN_NULL(); } pfree(output_proj4); /* now we have a geometry, and input/output PJ structs. */ lwgeom = lwgeom_from_gserialized(geom); lwgeom_transform(lwgeom, input_pj, output_pj); lwgeom->srid = result_srid; /* clean up */ pj_free(input_pj); pj_free(output_pj); /* Re-compute bbox if input had one (COMPUTE_BBOX TAINTING) */ if ( lwgeom->bbox ) { lwgeom_drop_bbox(lwgeom); lwgeom_add_bbox(lwgeom); } result = geometry_serialize(lwgeom); lwgeom_free(lwgeom); PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(result); /* new geometry */ }
Datum geometry_estimated_extent(PG_FUNCTION_ARGS) { text *txnsp = NULL; text *txtbl = NULL; text *txcol = NULL; char *nsp = NULL; char *tbl = NULL; char *col = NULL; char *query; ArrayType *array = NULL; int SPIcode; SPITupleTable *tuptable; TupleDesc tupdesc ; HeapTuple tuple ; bool isnull; GBOX *box; size_t querysize; GEOM_STATS geomstats; float reltuples; Datum binval; if ( PG_NARGS() == 3 ) { txnsp = PG_GETARG_TEXT_P(0); txtbl = PG_GETARG_TEXT_P(1); txcol = PG_GETARG_TEXT_P(2); } else if ( PG_NARGS() == 2 ) { txtbl = PG_GETARG_TEXT_P(0); txcol = PG_GETARG_TEXT_P(1); } else { elog(ERROR, "estimated_extent() called with wrong number of arguments"); PG_RETURN_NULL(); } POSTGIS_DEBUG(2, "geomtery_estimated_extent called"); /* Connect to SPI manager */ SPIcode = SPI_connect(); if (SPIcode != SPI_OK_CONNECT) { elog(ERROR, "geometry_estimated_extent: couldnt open a connection to SPI"); PG_RETURN_NULL() ; } querysize = VARSIZE(txtbl)+VARSIZE(txcol)+516; if ( txnsp ) { nsp = text2cstring(txnsp); querysize += VARSIZE(txnsp); } else { querysize += 32; /* current_schema() */ } tbl = text2cstring(txtbl); col = text2cstring(txcol); #if POSTGIS_DEBUG_LEVEL > 0 if ( txnsp ) { POSTGIS_DEBUGF(3, " schema:%s table:%s column:%s", nsp, tbl, col); } else { POSTGIS_DEBUGF(3, " schema:current_schema() table:%s column:%s", tbl, col); } #endif query = palloc(querysize); /* Security check: because we access information in the pg_statistic table, we must run as the database superuser (by marking the function as SECURITY DEFINER) and check permissions ourselves */ if ( txnsp ) { sprintf(query, "SELECT has_table_privilege((SELECT usesysid FROM pg_user WHERE usename = session_user), '\"%s\".\"%s\"', 'select')", nsp, tbl); } else { sprintf(query, "SELECT has_table_privilege((SELECT usesysid FROM pg_user WHERE usename = session_user), '\"%s\"', 'select')", tbl); } POSTGIS_DEBUGF(4, "permission check sql query is: %s", query); SPIcode = SPI_exec(query, 1); if (SPIcode != SPI_OK_SELECT) { elog(ERROR, "geometry_estimated_extent: couldn't execute permission check sql via SPI"); SPI_finish(); PG_RETURN_NULL(); } tuptable = SPI_tuptable; tupdesc = SPI_tuptable->tupdesc; tuple = tuptable->vals[0]; if (!DatumGetBool(SPI_getbinval(tuple, tupdesc, 1, &isnull))) { elog(ERROR, "geometry_estimated_extent: permission denied for relation %s", tbl); SPI_finish(); PG_RETURN_NULL(); } /* Return the stats data */ if ( txnsp ) { sprintf(query, "SELECT s.stanumbers1[5:8], c.reltuples FROM pg_class c" " LEFT OUTER JOIN pg_namespace n ON (n.oid = c.relnamespace)" " LEFT OUTER JOIN pg_attribute a ON (a.attrelid = c.oid )" " LEFT OUTER JOIN pg_statistic s ON (s.starelid = c.oid AND " "s.staattnum = a.attnum )" " WHERE c.relname = '%s' AND a.attname = '%s' " " AND n.nspname = '%s';", tbl, col, nsp); } else { sprintf(query, "SELECT s.stanumbers1[5:8], c.reltuples FROM pg_class c" " LEFT OUTER JOIN pg_namespace n ON (n.oid = c.relnamespace)" " LEFT OUTER JOIN pg_attribute a ON (a.attrelid = c.oid )" " LEFT OUTER JOIN pg_statistic s ON (s.starelid = c.oid AND " "s.staattnum = a.attnum )" " WHERE c.relname = '%s' AND a.attname = '%s' " " AND n.nspname = current_schema();", tbl, col); } POSTGIS_DEBUGF(4, " query: %s", query); SPIcode = SPI_exec(query, 1); if (SPIcode != SPI_OK_SELECT ) { elog(ERROR,"geometry_estimated_extent: couldnt execute sql via SPI"); SPI_finish(); PG_RETURN_NULL(); } if (SPI_processed != 1) { POSTGIS_DEBUGF(3, " %d stat rows", SPI_processed); elog(ERROR, "Unexistent field \"%s\".\"%s\".\"%s\"", ( nsp ? nsp : "<current>" ), tbl, col); SPI_finish(); PG_RETURN_NULL() ; } tuptable = SPI_tuptable; tupdesc = SPI_tuptable->tupdesc; tuple = tuptable->vals[0]; /* Check if the table has zero rows first */ binval = SPI_getbinval(tuple, tupdesc, 2, &isnull); if (isnull) { POSTGIS_DEBUG(3, " reltuples is NULL"); elog(ERROR, "geometry_estimated_extent: null reltuples for table"); SPI_finish(); PG_RETURN_NULL(); } reltuples = DatumGetFloat4(binval); if ( ! reltuples ) { POSTGIS_DEBUG(3, "table has estimated zero rows"); /* * TODO: distinguish between empty and not analyzed ? */ elog(NOTICE, "\"%s\".\"%s\".\"%s\" is empty or not analyzed", ( nsp ? nsp : "<current>" ), tbl, col); SPI_finish(); PG_RETURN_NULL(); } binval = SPI_getbinval(tuple, tupdesc, 1, &isnull); if (isnull) { POSTGIS_DEBUG(3, " stats are NULL"); elog(ERROR, "geometry_estimated_extent: null statistics for table"); SPI_finish(); PG_RETURN_NULL(); } array = DatumGetArrayTypeP(binval); if ( ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array)) != 4 ) { elog(ERROR, " corrupted histogram"); PG_RETURN_NULL(); } POSTGIS_DEBUGF(3, " stats array has %d elems", ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array))); /* * Construct GBOX. * Must allocate this in upper executor context * to keep it alive after SPI_finish(). */ box = SPI_palloc(sizeof(GBOX)); FLAGS_SET_GEODETIC(box->flags, 0); FLAGS_SET_Z(box->flags, 0); FLAGS_SET_M(box->flags, 0); /* Construct the box */ memcpy(&(geomstats.xmin), ARR_DATA_PTR(array), sizeof(float)*4); box->xmin = geomstats.xmin; box->xmax = geomstats.xmax; box->ymin = geomstats.ymin; box->ymax = geomstats.ymax; POSTGIS_DEBUGF(3, " histogram extent = %g %g, %g %g", box->xmin, box->ymin, box->xmax, box->ymax); SPIcode = SPI_finish(); if (SPIcode != SPI_OK_FINISH ) { elog(ERROR, "geometry_estimated_extent: couldn't disconnect from SPI"); } /* TODO: enlarge the box by some factor */ PG_RETURN_POINTER(box); }