/* align a stringbuffer on begin and end columns. */ void stringbuffer_align(stringbuffer_t *sb, int begin, int end) { char *ptr, *word_string; stringbuffer_t *aligned_string; int len, i; stringbuffer_zap_newline(sb); aligned_string = stringbuffer_create(); ptr = sb->buf; while (1) { word_string = get_string_align(ptr, end, &len); if (word_string == NULL) break; ptr += len; for (i = 0; i < begin; i++) stringbuffer_append(aligned_string, " "); stringbuffer_append(aligned_string, word_string); stringbuffer_append(aligned_string, "\n"); free(word_string); } stringbuffer_copy(sb, aligned_string); stringbuffer_destroy(aligned_string); return; }
char * pc_point_to_string(const PCPOINT *pt) { /* { "pcid":1, "values":[<dim1>, <dim2>, <dim3>, <dim4>] }*/ stringbuffer_t *sb = stringbuffer_create(); char *str; int i; stringbuffer_aprintf(sb, "{\"pcid\":%d,\"pt\":[", pt->schema->pcid); for ( i = 0; i < pt->schema->ndims; i++ ) { double d; if ( ! pc_point_get_double_by_index(pt, i, &d) ) { pcerror("pc_point_to_string: unable to read double at position %d", i); } if ( i ) { stringbuffer_append(sb, ","); } stringbuffer_aprintf(sb, "%g", d); } stringbuffer_append(sb, "]}"); str = stringbuffer_getstringcopy(sb); stringbuffer_destroy(sb); return str; }
char * pc_patch_uncompressed_to_string(const PCPATCH_UNCOMPRESSED *patch) { stringbuffer_t *sb = stringbuffer_create(); char *str; if ( PC_FAILURE == pc_patch_uncompressed_to_stringbuffer(patch, sb) ) return NULL; str = stringbuffer_release_string(sb); stringbuffer_destroy(sb); return str; }
/** Convert a PCSCHEMA to a human-readable JSON string */ char * pc_schema_to_json(const PCSCHEMA *pcs) { int i; char *str; stringbuffer_t *sb = stringbuffer_create(); stringbuffer_append(sb, "{"); if ( pcs->pcid ) stringbuffer_aprintf(sb, "\"pcid\" : %d,\n", pcs->pcid); if ( pcs->srid ) stringbuffer_aprintf(sb, "\"srid\" : %d,\n", pcs->srid); if ( pcs->compression ) stringbuffer_aprintf(sb, "\"compression\" : %d,\n", pcs->compression); if ( pcs->ndims ) { stringbuffer_append(sb, "\"dims\" : [\n"); for ( i = 0; i < pcs->ndims; i++ ) { if ( pcs->dims[i] ) { PCDIMENSION *d = pcs->dims[i]; if ( i ) stringbuffer_append(sb, ","); stringbuffer_append(sb, "\n { \n"); if ( d->name ) stringbuffer_aprintf(sb, " \"name\" : \"%s\",\n", d->name); if ( d->description ) stringbuffer_aprintf(sb, " \"description\" : \"%s\",\n", d->description); stringbuffer_aprintf(sb, " \"size\" : %d,\n", d->size); stringbuffer_aprintf(sb, " \"byteoffset\" : %d,\n", d->byteoffset); stringbuffer_aprintf(sb, " \"scale\" : %g,\n", d->scale); stringbuffer_aprintf(sb, " \"interpretation\" : \"%s\",\n", pc_interpretation_string(d->interpretation)); stringbuffer_aprintf(sb, " \"offset\" : %g,\n", d->offset); stringbuffer_aprintf(sb, " \"active\" : %d\n", d->active); stringbuffer_append(sb, " }"); } } stringbuffer_append(sb, "\n]\n"); } stringbuffer_append(sb, "}\n"); str = stringbuffer_getstringcopy(sb); stringbuffer_destroy(sb); return str; }
/* Return a pointer to an allocated string containing the header for the specified loader state */ int ShpLoaderGetSQLFooter(SHPLOADERSTATE *state, char **strfooter) { stringbuffer_t *sb; char *ret; /* Create the stringbuffer containing the header; we use this API as it's easier for handling string resizing during append */ sb = stringbuffer_create(); stringbuffer_clear(sb); /* Create gist index if specified and not in "prepare" mode */ if (state->config->readshape && state->config->createindex) { stringbuffer_aprintf(sb, "CREATE INDEX ON "); /* Schema is optional, include if present. */ if (state->config->schema) { stringbuffer_aprintf(sb, "\"%s\".",state->config->schema); } stringbuffer_aprintf(sb, "\"%s\" USING GIST (\"%s\")", state->config->table, state->geo_col); /* Tablespace is also optional. */ if (state->config->idxtablespace != NULL) { stringbuffer_aprintf(sb, " TABLESPACE \"%s\"", state->config->idxtablespace); } stringbuffer_aprintf(sb, ";\n"); } /* End the transaction if there is one. */ if (state->config->usetransaction) { stringbuffer_aprintf(sb, "COMMIT;\n"); } /* Always ANALYZE the resulting table, for better stats */ stringbuffer_aprintf(sb, "ANALYZE "); if (state->config->schema) { stringbuffer_aprintf(sb, "\"%s\".", state->config->schema); } stringbuffer_aprintf(sb, "\"%s\";\n", state->config->table); /* Copy the string buffer into a new string, destroying the string buffer */ ret = (char *)malloc(strlen((char *)stringbuffer_getstring(sb)) + 1); strcpy(ret, (char *)stringbuffer_getstring(sb)); stringbuffer_destroy(sb); *strfooter = ret; return SHPLOADEROK; }
/* Return a pointer to an allocated string containing the header for the specified loader state */ int ShpLoaderGetSQLFooter(SHPLOADERSTATE *state, char **strfooter) { stringbuffer_t *sb; char *ret; char *ops; if ( state->config->geography ) ops = "gist_geography_ops"; else ops = "gist_geometry_ops"; /* Create the stringbuffer containing the header; we use this API as it's easier for handling string resizing during append */ sb = stringbuffer_create(); stringbuffer_clear(sb); /* Create gist index if specified and not in "prepare" mode */ if (state->config->createindex) { if (state->config->schema) { vasbappend(sb, "CREATE INDEX \"%s_%s_gist\" ON \"%s\".\"%s\" using gist (\"%s\" %s);\n", state->config->table, state->config->geom, state->config->schema, state->config->table, state->config->geom, ops); } else { vasbappend(sb, "CREATE INDEX \"%s_%s_gist\" ON \"%s\" using gist (\"%s\" %s);\n", state->config->table, state->config->geom, state->config->table, state->config->geom, ops); } } /* End the transaction */ vasbappend(sb, "COMMIT;\n"); /* Copy the string buffer into a new string, destroying the string buffer */ ret = (char *)malloc(strlen((char *)stringbuffer_getstring(sb)) + 1); strcpy(ret, (char *)stringbuffer_getstring(sb)); stringbuffer_destroy(sb); *strfooter = ret; return SHPLOADEROK; }
/** Convert a PCSCHEMA to a human-readable JSON string */ char * pc_schema_to_json(const PCSCHEMA *pcs) { int i; char *str; stringbuffer_t *sb = stringbuffer_create(); stringbuffer_append(sb, "{"); if ( pcs->pcid ) stringbuffer_aprintf(sb, "\"pcid\" : %d,\n", pcs->pcid); if ( pcs->ndims ) stringbuffer_aprintf(sb, "\"ndims\" : %d,\n", pcs->ndims); if ( pcs->srid ) stringbuffer_aprintf(sb, "\"srid\" : %d,\n", pcs->srid); if ( pcs->compression ) stringbuffer_aprintf(sb, "\"compression\" : %d,\n", pcs->compression); if ( pcs->size ) stringbuffer_aprintf(sb, "\"size\" : %zu,\n", pcs->size); if ( pcs->x_position>=0 ) stringbuffer_aprintf(sb, "\"x_position\" : %d,\n", pcs->x_position); if ( pcs->y_position >=0) stringbuffer_aprintf(sb, "\"y_position\" : %d,\n", pcs->y_position); if ( pcs->namehash->entrycount ) stringbuffer_aprintf(sb, "\"namehash->entrycount\" : %d,\n", pcs->namehash->entrycount); if ( pcs->ndims ) { stringbuffer_append(sb, "\"dims\" : [\n"); for ( i = 0; i < pcs->ndims; i++ ) { stringbuffer_append(sb,pc_dimension_to_json(pcs->dims[i] ) ); } stringbuffer_append(sb, "\n]\n"); } stringbuffer_append(sb, "}\n"); str = stringbuffer_getstringcopy(sb); stringbuffer_destroy(sb); return str; }
/* append vprintf with alignment. */ void stringbuffer_avprintf_align(stringbuffer_t *sb, int start, int end, const char *fmt, va_list ap) { stringbuffer_t *tmp_sb; char *str; int total, len; /* our first malloc is bogus. */ len = 1; str = malloc(sizeof(char) * len); total = vsnprintf(str, len, fmt, ap); /* total is the real length needed. */ free(str); len = total + 1; str = malloc(sizeof(char) * len); vsnprintf(str, len, fmt, ap); /* now align if we want to align. */ if (start != 0 && end != 0) { tmp_sb = stringbuffer_create(); stringbuffer_append(tmp_sb, str); stringbuffer_align(tmp_sb, start, end); stringbuffer_append(sb, stringbuffer_getstring(tmp_sb)); stringbuffer_destroy(tmp_sb); } else { stringbuffer_append(sb, str); } free(str); return; }
/** * WKT emitter function. Allocates a new *char and fills it with the WKT * representation. If size_out is not NULL, it will be set to the size of the * allocated *char. * * @param variant Bitmasked value, accepts one of WKT_ISO, WKT_SFSQL, WKT_EXTENDED. * @param precision Number of significant digits in the output doubles. * @param size_out If supplied, will return the size of the returned string, * including the null terminator. */ char* lwgeom_to_wkt(const LWGEOM *geom, uint8_t variant, int precision, size_t *size_out) { stringbuffer_t *sb; char *str = NULL; if ( geom == NULL ) return NULL; sb = stringbuffer_create(); /* Extended mode starts with an "SRID=" section for geoms that have one */ if ( (variant & WKT_EXTENDED) && lwgeom_has_srid(geom) ) { stringbuffer_aprintf(sb, "SRID=%d;", geom->srid); } lwgeom_to_wkt_sb(geom, sb, precision, variant); if ( stringbuffer_getstring(sb) == NULL ) { lwerror("Uh oh"); return NULL; } str = stringbuffer_getstringcopy(sb); if ( size_out ) *size_out = stringbuffer_getlength(sb) + 1; stringbuffer_destroy(sb); return str; }
/**@brief * Convert a PCSDIMENSION to a human-readable JSON string * @param the PCDIMENSION we want to print * @return q pointer to the string buff describing the object * */ char * pc_dimension_to_json(const PCDIMENSION *d) { int i; char *str; stringbuffer_t *sb = stringbuffer_create(); stringbuffer_append(sb, "{"); if ( d ) { if ( i ) stringbuffer_append(sb, ","); stringbuffer_append(sb, "\n { \n"); if ( d->name ) stringbuffer_aprintf(sb, " \"name\" : \"%s\",\n", d->name); if ( d->description ) stringbuffer_aprintf(sb, " \"description\" : \"%s\",\n", d->description); stringbuffer_aprintf(sb, " \"size\" : %d,\n", d->size); stringbuffer_aprintf(sb, " \"byteoffset\" : %d,\n", d->byteoffset); stringbuffer_aprintf(sb, " \"scale\" : %g,\n", d->scale); stringbuffer_aprintf(sb, " \"interpretation\" : \"%s\",\n", pc_interpretation_string(d->interpretation)); stringbuffer_aprintf(sb, " \"offset\" : %g,\n", d->offset); stringbuffer_aprintf(sb, " \"active\" : %d\n", d->active); stringbuffer_append(sb, " }"); } stringbuffer_append(sb, "}\n"); str = stringbuffer_getstringcopy(sb); stringbuffer_destroy(sb); return str; }
/* Return a pointer to an allocated string containing the header for the specified loader state */ int ShpLoaderGetSQLHeader(SHPLOADERSTATE *state, char **strheader) { stringbuffer_t *sb; char *ret; int j; /* Create the stringbuffer containing the header; we use this API as it's easier for handling string resizing during append */ sb = stringbuffer_create(); stringbuffer_clear(sb); /* Set the client encoding if required */ if (state->config->encoding) { stringbuffer_aprintf(sb, "SET CLIENT_ENCODING TO UTF8;\n"); } /* Use SQL-standard string escaping rather than PostgreSQL standard */ stringbuffer_aprintf(sb, "SET STANDARD_CONFORMING_STRINGS TO ON;\n"); /* Drop table if requested */ if (state->config->opt == 'd') { /** * TODO: if the table has more then one geometry column * the DROP TABLE call will leave spurious records in * geometry_columns. * * If the geometry column in the table being dropped * does not match 'the_geom' or the name specified with * -g an error is returned by DropGeometryColumn. * * The table to be dropped might not exist. */ if (state->config->schema) { if (state->config->readshape == 1 && (! state->config->geography) ) { stringbuffer_aprintf(sb, "SELECT DropGeometryColumn('%s','%s','%s');\n", state->config->schema, state->config->table, state->geo_col); } stringbuffer_aprintf(sb, "DROP TABLE \"%s\".\"%s\";\n", state->config->schema, state->config->table); } else { if (state->config->readshape == 1 && (! state->config->geography) ) { stringbuffer_aprintf(sb, "SELECT DropGeometryColumn('','%s','%s');\n", state->config->table, state->geo_col); } stringbuffer_aprintf(sb, "DROP TABLE \"%s\";\n", state->config->table); } } /* Start of transaction if we are using one */ if (state->config->usetransaction) { stringbuffer_aprintf(sb, "BEGIN;\n"); } /* If not in 'append' mode create the spatial table */ if (state->config->opt != 'a') { /* * Create a table for inserting the shapes into with appropriate * columns and types */ if (state->config->schema) { stringbuffer_aprintf(sb, "CREATE TABLE \"%s\".\"%s\" (gid serial", state->config->schema, state->config->table); } else { stringbuffer_aprintf(sb, "CREATE TABLE \"%s\" (gid serial", state->config->table); } /* Generate the field types based upon the shapefile information */ for (j = 0; j < state->num_fields; j++) { stringbuffer_aprintf(sb, ",\n\"%s\" ", state->field_names[j]); /* First output the raw field type string */ stringbuffer_aprintf(sb, "%s", state->pgfieldtypes[j]); /* Some types do have typmods though... */ if (!strcmp("varchar", state->pgfieldtypes[j])) stringbuffer_aprintf(sb, "(%d)", state->widths[j]); if (!strcmp("numeric", state->pgfieldtypes[j])) { /* Doubles we just allow PostgreSQL to auto-detect the size */ if (state->types[j] != FTDouble) stringbuffer_aprintf(sb, "(%d,0)", state->widths[j]); } } /* Add the geography column directly to the table definition, we don't need to do an AddGeometryColumn() call. */ if (state->config->readshape == 1 && state->config->geography) { char *dimschar; if (state->pgdims == 4) dimschar = "ZM"; else dimschar = ""; if (state->to_srid != SRID_UNKNOWN && state->to_srid != 4326) { snprintf(state->message, SHPLOADERMSGLEN, _("Invalid SRID for geography type: %d"), state->to_srid); stringbuffer_destroy(sb); return SHPLOADERERR; } stringbuffer_aprintf(sb, ",\n\"%s\" geography(%s%s,%d)", state->geo_col, state->pgtype, dimschar, 4326); } stringbuffer_aprintf(sb, ")"); /* Tablespace is optional. */ if (state->config->tablespace != NULL) { stringbuffer_aprintf(sb, " TABLESPACE \"%s\"", state->config->tablespace); } stringbuffer_aprintf(sb, ";\n"); /* Create the primary key. This is done separately because the index for the PK needs * to be in the correct tablespace. */ /* TODO: Currently PostgreSQL does not allow specifying an index to use for a PK (so you get * a default one called table_pkey) and it does not provide a way to create a PK index * in a specific tablespace. So as a hacky solution we create the PK, then move the * index to the correct tablespace. Eventually this should be: * CREATE INDEX table_pkey on table(gid) TABLESPACE tblspc; * ALTER TABLE table ADD PRIMARY KEY (gid) USING INDEX table_pkey; * A patch has apparently been submitted to PostgreSQL to enable this syntax, see this thread: * http://archives.postgresql.org/pgsql-hackers/2011-01/msg01405.php */ stringbuffer_aprintf(sb, "ALTER TABLE "); /* Schema is optional, include if present. */ if (state->config->schema) { stringbuffer_aprintf(sb, "\"%s\".",state->config->schema); } stringbuffer_aprintf(sb, "\"%s\" ADD PRIMARY KEY (gid);\n", state->config->table); /* Tablespace is optional for the index. */ if (state->config->idxtablespace != NULL) { stringbuffer_aprintf(sb, "ALTER INDEX "); if (state->config->schema) { stringbuffer_aprintf(sb, "\"%s\".",state->config->schema); } /* WARNING: We're assuming the default "table_pkey" name for the primary * key index. PostgreSQL may use "table_pkey1" or similar in the * case of a name conflict, so you may need to edit the produced * SQL in this rare case. */ stringbuffer_aprintf(sb, "\"%s_pkey\" SET TABLESPACE \"%s\";\n", state->config->table, state->config->idxtablespace); } /* Create the geometry column with an addgeometry call */ if (state->config->readshape == 1 && (!state->config->geography)) { /* If they didn't specify a target SRID, see if they specified a source SRID. */ int srid = state->to_srid; if (state->config->schema) { stringbuffer_aprintf(sb, "SELECT AddGeometryColumn('%s','%s','%s','%d',", state->config->schema, state->config->table, state->geo_col, srid); } else { stringbuffer_aprintf(sb, "SELECT AddGeometryColumn('','%s','%s','%d',", state->config->table, state->geo_col, srid); } stringbuffer_aprintf(sb, "'%s',%d);\n", state->pgtype, state->pgdims); } } /* Copy the string buffer into a new string, destroying the string buffer */ ret = (char *)malloc(strlen((char *)stringbuffer_getstring(sb)) + 1); strcpy(ret, (char *)stringbuffer_getstring(sb)); stringbuffer_destroy(sb); *strheader = ret; return SHPLOADEROK; }
static void test_ght_node_serialization(void) { GhtCoordinate coord; int x, y; GhtNode *node1, *node2, *node3; GhtErr err; GhtWriter *writer; GhtReader *reader; const uint8_t *bytes; size_t bytes_size; stringbuffer_t *sb1, *sb2; GhtAttribute *attr; char *hex; /* ght_node_new_from_coordinate(const GhtCoordinate *coord, unsigned int resolution, GhtNode **node); */ coord.x = -127.4123; coord.y = 49.23141; err = ght_node_new_from_coordinate(&coord, GHT_MAX_HASH_LENGTH, &node1); CU_ASSERT_STRING_EQUAL(node1->hash, "c0v2hdm1wpzpy4vtv4"); CU_ASSERT_EQUAL(err, GHT_OK); err = ght_writer_new_mem(&writer); err = ght_node_write(node1, writer); bytes = bytebuffer_getbytes(writer->bytebuffer); bytes_size = bytebuffer_getsize(writer->bytebuffer); err = ght_reader_new_mem(bytes, bytes_size, schema, &reader); err = ght_node_read(reader, &node2); CU_ASSERT_STRING_EQUAL(node1->hash, node2->hash); ght_node_free(node2); /* add a child */ coord.x = -127.4125; coord.y = 49.23144; err = ght_node_new_from_coordinate(&coord, GHT_MAX_HASH_LENGTH, &node3); err = ght_attribute_new_from_double(schema->dims[3], 88.88, &attr); err = ght_node_add_attribute(node3, attr); err = ght_node_insert_node(node1, node3, GHT_DUPES_YES); CU_ASSERT_EQUAL(err, GHT_OK); /* add another (dupe) child */ err = ght_node_new_from_coordinate(&coord, GHT_MAX_HASH_LENGTH, &node3); err = ght_node_insert_node(node1, node3, GHT_DUPES_YES); /* add another (dupe) child with an attribute */ err = ght_node_new_from_coordinate(&coord, GHT_MAX_HASH_LENGTH, &node3); err = ght_attribute_new_from_double(schema->dims[2], 99.99, &attr); err = ght_node_add_attribute(node3, attr); err = ght_node_insert_node(node1, node3, GHT_DUPES_YES); sb1 = stringbuffer_create(); err = ght_node_to_string(node1, sb1, 0); // printf("ORIGINAL\n%s\n", stringbuffer_getstring(sb1)); err = ght_writer_new_mem(&writer); err = ght_node_write(node1, writer); bytes = bytebuffer_getbytes(writer->bytebuffer); bytes_size = bytebuffer_getsize(writer->bytebuffer); err = hexbytes_from_bytes(bytes, bytes_size, &hex); CU_ASSERT_STRING_EQUAL("086330763268646D3100020A77707A7079347674763400000A6374643463637839796201035800020000000001020F27000000", hex); // printf("\n\n%s\n", hex); err = ght_reader_new_mem(bytes, bytes_size, schema, &reader); err = ght_node_read(reader, &node2); sb2 = stringbuffer_create(); err = ght_node_to_string(node2, sb2, 0); // printf("COPY\n%s\n", stringbuffer_getstring(sb2)); CU_ASSERT_STRING_EQUAL(stringbuffer_getstring(sb1), stringbuffer_getstring(sb2)); stringbuffer_destroy(sb2); stringbuffer_destroy(sb1); ght_node_free(node1); ght_node_free(node2); ght_writer_free(writer); ght_reader_free(reader); }
static void test_ght_build_tree_with_attributes(void) { int i; static const char *simpledata = "test/data/simple-data.tsv"; GhtNodeList *nodelist; GhtNode *root, *node; GhtErr err; GhtAttribute attr; stringbuffer_t *sb; double d; /* Read a nodelist from a TSV file */ nodelist = tsv_file_to_node_list(simpledata, simpleschema); CU_ASSERT_EQUAL(nodelist->num_nodes, 8); /* Build node list into a tree */ root = nodelist->nodes[0]; for ( i = 1; i < nodelist->num_nodes; i++ ) { err = ght_node_insert_node(root, nodelist->nodes[i], GHT_DUPES_YES); } /* Write the tree to string: c0n0e q m m7 dvy8yz9 Z=123.4:Intensity=5 ky667sj Z=123.4:Intensity=5 qw00rg068 Z=123.4:Intensity=5 hekkhnhj3b Z=123.4:Intensity=5 6myj870p99 Z=123.3:Intensity=5 46jybv17y1 Z=123.4:Intensity=5 r 980jtyf1dh Z=123.4:Intensity=5 2khvpfu13f Z=123.4:Intensity=5 */ sb = stringbuffer_create(); ght_node_to_string(root, sb, 0); // printf("\n%s\n", stringbuffer_getstring(sb)); stringbuffer_destroy(sb); /* Compact the tree on both attributes: c0n0e Intensity=5 q m Z=123.4 m7 dvy8yz9 ky667sj qw00rg068 hekkhnhj3b Z=123.4 6myj870p99 Z=123.3 46jybv17y1 Z=123.4 r Z=123.4 980jtyf1dh 2khvpfu13f */ sb = stringbuffer_create(); ght_node_compact_attribute(root, simpleschema->dims[2], &attr); ght_node_compact_attribute(root, simpleschema->dims[3], &attr); ght_node_to_string(root, sb, 0); // printf("\n%s\n", stringbuffer_getstring(sb)); stringbuffer_destroy(sb); /* Check that Intensity=5 has migrated all the way to the top of the tree */ CU_ASSERT_STRING_EQUAL(root->attributes->dim->name, "Intensity"); ght_attribute_get_value(root->attributes, &d); CU_ASSERT_DOUBLE_EQUAL(d, 5, 0.00000001); ght_node_free(root); ght_nodelist_free_shallow(nodelist); }
/* Return an allocated string representation of a specified record item */ int ShpLoaderGenerateSQLRowStatement(SHPLOADERSTATE *state, int item, char **strrecord) { SHPObject *obj = NULL; stringbuffer_t *sb; stringbuffer_t *sbwarn; char val[MAXVALUELEN]; char *escval; char *geometry=NULL, *ret; char *utf8str; int res, i; int rv; /* Clear the stringbuffers */ sbwarn = stringbuffer_create(); stringbuffer_clear(sbwarn); sb = stringbuffer_create(); stringbuffer_clear(sb); /* If we are reading the DBF only and the record has been marked deleted, return deleted record status */ if (state->config->readshape == 0 && DBFIsRecordDeleted(state->hDBFHandle, item)) { *strrecord = NULL; return SHPLOADERRECDELETED; } /* If we are reading the shapefile, open the specified record */ if (state->config->readshape == 1) { obj = SHPReadObject(state->hSHPHandle, item); if (!obj) { snprintf(state->message, SHPLOADERMSGLEN, _("Error reading shape object %d"), item); return SHPLOADERERR; } /* If we are set to skip NULLs, return a NULL record status */ if (state->config->null_policy == POLICY_NULL_SKIP && obj->nVertices == 0 ) { SHPDestroyObject(obj); *strrecord = NULL; return SHPLOADERRECISNULL; } } /* If not in dump format, generate the INSERT string */ if (!state->config->dump_format) { if (state->config->schema) { stringbuffer_aprintf(sb, "INSERT INTO \"%s\".\"%s\" %s VALUES (", state->config->schema, state->config->table, state->col_names); } else { stringbuffer_aprintf(sb, "INSERT INTO \"%s\" %s VALUES (", state->config->table, state->col_names); } } /* Read all of the attributes from the DBF file for this item */ for (i = 0; i < DBFGetFieldCount(state->hDBFHandle); i++) { /* Special case for NULL attributes */ if (DBFIsAttributeNULL(state->hDBFHandle, item, i)) { if (state->config->dump_format) stringbuffer_aprintf(sb, "\\N"); else stringbuffer_aprintf(sb, "NULL"); } else { /* Attribute NOT NULL */ switch (state->types[i]) { case FTInteger: case FTDouble: rv = snprintf(val, MAXVALUELEN, "%s", DBFReadStringAttribute(state->hDBFHandle, item, i)); if (rv >= MAXVALUELEN || rv == -1) { stringbuffer_aprintf(sbwarn, "Warning: field %d name truncated\n", i); val[MAXVALUELEN - 1] = '\0'; } /* If the value is an empty string, change to 0 */ if (val[0] == '\0') { val[0] = '0'; val[1] = '\0'; } /* If the value ends with just ".", remove the dot */ if (val[strlen(val) - 1] == '.') val[strlen(val) - 1] = '\0'; break; case FTString: case FTLogical: case FTDate: rv = snprintf(val, MAXVALUELEN, "%s", DBFReadStringAttribute(state->hDBFHandle, item, i)); if (rv >= MAXVALUELEN || rv == -1) { stringbuffer_aprintf(sbwarn, "Warning: field %d name truncated\n", i); val[MAXVALUELEN - 1] = '\0'; } break; default: snprintf(state->message, SHPLOADERMSGLEN, _("Error: field %d has invalid or unknown field type (%d)"), i, state->types[i]); SHPDestroyObject(obj); stringbuffer_destroy(sbwarn); stringbuffer_destroy(sb); return SHPLOADERERR; } if (state->config->encoding) { char *encoding_msg = _("Try \"LATIN1\" (Western European), or one of the values described at http://www.postgresql.org/docs/current/static/multibyte.html."); rv = utf8(state->config->encoding, val, &utf8str); if (rv != UTF8_GOOD_RESULT) { if ( rv == UTF8_BAD_RESULT ) snprintf(state->message, SHPLOADERMSGLEN, _("Unable to convert data value \"%s\" to UTF-8 (iconv reports \"%s\"). Current encoding is \"%s\". %s"), utf8str, strerror(errno), state->config->encoding, encoding_msg); else if ( rv == UTF8_NO_RESULT ) snprintf(state->message, SHPLOADERMSGLEN, _("Unable to convert data value to UTF-8 (iconv reports \"%s\"). Current encoding is \"%s\". %s"), strerror(errno), state->config->encoding, encoding_msg); else snprintf(state->message, SHPLOADERMSGLEN, _("Unexpected return value from utf8()")); if ( rv == UTF8_BAD_RESULT ) free(utf8str); return SHPLOADERERR; } strncpy(val, utf8str, MAXVALUELEN); free(utf8str); } /* Escape attribute correctly according to dump format */ if (state->config->dump_format) { escval = escape_copy_string(val); stringbuffer_aprintf(sb, "%s", escval); } else { escval = escape_insert_string(val); stringbuffer_aprintf(sb, "'%s'", escval); } /* Free the escaped version if required */ if (val != escval) free(escval); } /* Only put in delimeter if not last field or a shape will follow */ if (state->config->readshape == 1 || i < DBFGetFieldCount(state->hDBFHandle) - 1) { if (state->config->dump_format) stringbuffer_aprintf(sb, "\t"); else stringbuffer_aprintf(sb, ","); } /* End of DBF attribute loop */ } /* Add the shape attribute if we are reading it */ if (state->config->readshape == 1) { /* Handle the case of a NULL shape */ if (obj->nVertices == 0) { if (state->config->dump_format) stringbuffer_aprintf(sb, "\\N"); else stringbuffer_aprintf(sb, "NULL"); } else { /* Handle all other shape attributes */ switch (obj->nSHPType) { case SHPT_POLYGON: case SHPT_POLYGONM: case SHPT_POLYGONZ: res = GeneratePolygonGeometry(state, obj, &geometry); break; case SHPT_POINT: case SHPT_POINTM: case SHPT_POINTZ: res = GeneratePointGeometry(state, obj, &geometry, 0); break; case SHPT_MULTIPOINT: case SHPT_MULTIPOINTM: case SHPT_MULTIPOINTZ: /* Force it to multi unless using -S */ res = GeneratePointGeometry(state, obj, &geometry, state->config->simple_geometries ? 0 : 1); break; case SHPT_ARC: case SHPT_ARCM: case SHPT_ARCZ: res = GenerateLineStringGeometry(state, obj, &geometry); break; default: snprintf(state->message, SHPLOADERMSGLEN, _("Shape type is not supported, type id = %d"), obj->nSHPType); SHPDestroyObject(obj); stringbuffer_destroy(sbwarn); stringbuffer_destroy(sb); return SHPLOADERERR; } /* The default returns out of the function, so res will always have been set. */ if (res != SHPLOADEROK) { /* Error message has already been set */ SHPDestroyObject(obj); stringbuffer_destroy(sbwarn); stringbuffer_destroy(sb); return SHPLOADERERR; } /* Now generate the geometry string according to the current configuration */ if (!state->config->dump_format) { if (state->to_srid != state->from_srid) { stringbuffer_aprintf(sb, "ST_Transform("); } stringbuffer_aprintf(sb, "'"); } stringbuffer_aprintf(sb, "%s", geometry); if (!state->config->dump_format) { stringbuffer_aprintf(sb, "'"); /* Close the ST_Transform if reprojecting. */ if (state->to_srid != state->from_srid) { /* We need to add an explicit cast to geography/geometry to ensure that PostgreSQL doesn't get confused with the ST_Transform() raster function. */ if (state->config->geography) stringbuffer_aprintf(sb, "::geometry, %d)::geography", state->to_srid); else stringbuffer_aprintf(sb, "::geometry, %d)", state->to_srid); } } free(geometry); } /* Tidy up everything */ SHPDestroyObject(obj); } /* Close the line correctly for dump/insert format */ if (!state->config->dump_format) stringbuffer_aprintf(sb, ");"); /* Copy the string buffer into a new string, destroying the string buffer */ ret = (char *)malloc(strlen((char *)stringbuffer_getstring(sb)) + 1); strcpy(ret, (char *)stringbuffer_getstring(sb)); stringbuffer_destroy(sb); *strrecord = ret; /* If any warnings occurred, set the returned message string and warning status */ if (strlen((char *)stringbuffer_getstring(sbwarn)) > 0) { snprintf(state->message, SHPLOADERMSGLEN, "%s", stringbuffer_getstring(sbwarn)); stringbuffer_destroy(sbwarn); return SHPLOADERWARN; } else { /* Everything went okay */ stringbuffer_destroy(sbwarn); return SHPLOADEROK; } }
/* replace in stringbuffer occurances of c with replace */ void stringbuffer_replace(stringbuffer_t *sb, const char *string, const char *replace) { char *ptr; int i; int str_len = strlen(string); stringbuffer_t *sb_replace; if (string[0] == 0) return; /* nothing to replace. */ sb_replace = stringbuffer_create(); ptr = sb->buf; for (i = 0; i < sb->len; i++) { if ((sb->len - i) < str_len) { /* copy in. */ stringbuffer_copy(sb, sb_replace); /* append what's left. */ stringbuffer_append(sb, &ptr[i]); /* free up. */ stringbuffer_destroy(sb_replace); /* we're done. */ return; } if (ptr[i] == string[0]) { /* we know that we have at least enough to complete string. */ if (!memcmp(&ptr[i], string, str_len)) { /* we have a match, replace. */ stringbuffer_append(sb_replace, replace); i += (str_len - 1); continue; } } stringbuffer_append_c(sb_replace, ptr[i]); } /* we're done: we should only get here if the last string to be replaced ended the string itself. */ /* copy in. */ stringbuffer_copy(sb, sb_replace); /* free up. */ stringbuffer_destroy(sb_replace); /* we're done. */ return; }
/* Return an allocated string representation of a specified record item */ int ShpLoaderGenerateSQLRowStatement(SHPLOADERSTATE *state, int item, char **strrecord) { SHPObject *obj = NULL; stringbuffer_t *sb; stringbuffer_t *sbwarn; char val[MAXVALUELEN]; char *escval; char *geometry=NULL, *ret; char *utf8str; int res, i; int rv; /* Clear the stringbuffers */ sbwarn = stringbuffer_create(); stringbuffer_clear(sbwarn); sb = stringbuffer_create(); stringbuffer_clear(sb); /* If we are reading the DBF only and the record has been marked deleted, return deleted record status */ if (state->config->readshape == 0 && DBFReadDeleted(state->hDBFHandle, item)) { *strrecord = NULL; return SHPLOADERRECDELETED; } /* If we are reading the shapefile, open the specified record */ if (state->config->readshape == 1) { obj = SHPReadObject(state->hSHPHandle, item); if (!obj) { snprintf(state->message, SHPLOADERMSGLEN, "Error reading shape object %d", item); return SHPLOADERERR; } /* If we are set to skip NULLs, return a NULL record status */ if (state->config->null_policy == POLICY_NULL_SKIP && obj->nVertices == 0 ) { SHPDestroyObject(obj); *strrecord = NULL; return SHPLOADERRECISNULL; } } /* If not in dump format, generate the INSERT string */ if (!state->config->dump_format) { if (state->config->schema) { vasbappend(sb, "INSERT INTO \"%s\".\"%s\" %s VALUES (", state->config->schema, state->config->table, state->col_names); } else { vasbappend(sb, "INSERT INTO \"%s\" %s VALUES (", state->config->table, state->col_names); } } /* Read all of the attributes from the DBF file for this item */ for (i = 0; i < DBFGetFieldCount(state->hDBFHandle); i++) { /* Special case for NULL attributes */ if (DBFIsAttributeNULL(state->hDBFHandle, item, i)) { if (state->config->dump_format) vasbappend(sb, "\\N"); else vasbappend(sb, "NULL"); } else { /* Attribute NOT NULL */ switch (state->types[i]) { case FTInteger: case FTDouble: rv = snprintf(val, MAXVALUELEN, "%s", DBFReadStringAttribute(state->hDBFHandle, item, i)); if (rv >= MAXVALUELEN || rv == -1) { vasbappend(sbwarn, "Warning: field %d name truncated\n", i); val[MAXVALUELEN - 1] = '\0'; } /* If the value is an empty string, change to 0 */ if (val[0] == '\0') { val[0] = '0'; val[1] = '\0'; } /* If the value ends with just ".", remove the dot */ if (val[strlen(val) - 1] == '.') val[strlen(val) - 1] = '\0'; break; case FTString: case FTLogical: case FTDate: rv = snprintf(val, MAXVALUELEN, "%s", DBFReadStringAttribute(state->hDBFHandle, item, i)); if (rv >= MAXVALUELEN || rv == -1) { vasbappend(sbwarn, "Warning: field %d name truncated\n", i); val[MAXVALUELEN - 1] = '\0'; } break; default: snprintf(state->message, SHPLOADERMSGLEN, "Error: field %d has invalid or unknown field type (%d)", i, state->types[i]); SHPDestroyObject(obj); stringbuffer_destroy(sbwarn); stringbuffer_destroy(sb); return SHPLOADERERR; } if (state->config->encoding) { static char *encoding_msg = "Try \"LATIN1\" (Western European), or one of the values described at http://www.postgresql.org/docs/current/static/multibyte.html."; /* If we are converting from another encoding to UTF8, convert the field value to UTF8 */ int rv = utf8(state->config->encoding, val, &utf8str); if ( !UTF8_DROP_BAD_CHARACTERS && rv != UTF8_GOOD_RESULT ) { if( rv == UTF8_BAD_RESULT ) snprintf(state->message, SHPLOADERMSGLEN, "Unable to convert data value \"%s\" to UTF-8 (iconv reports \"%s\"). Current encoding is \"%s\". %s", utf8str, strerror(errno), state->config->encoding, encoding_msg); else if( rv == UTF8_NO_RESULT ) snprintf(state->message, SHPLOADERMSGLEN, "Unable to convert data value to UTF-8 (iconv reports \"%s\"). Current encoding is \"%s\". %s", strerror(errno), state->config->encoding, encoding_msg); else snprintf(state->message, SHPLOADERMSGLEN, "Unexpected return value from utf8()"); if( rv == UTF8_BAD_RESULT ) free(utf8str); return SHPLOADERERR; } /* Optionally (compile-time) suppress bad UTF8 values */ if ( UTF8_DROP_BAD_CHARACTERS && rv != UTF8_GOOD_RESULT ) { val[0] = '.'; val[1] = '\0'; } /* The utf8str buffer is only alloc'ed if the UTF8 conversion works */ if ( rv == UTF8_GOOD_RESULT ) { strncpy(val, utf8str, MAXVALUELEN); free(utf8str); } } /* Escape attribute correctly according to dump format */ if (state->config->dump_format) { escval = escape_copy_string(val); vasbappend(sb, "%s", escval); } else { escval = escape_insert_string(val); vasbappend(sb, "'%s'", escval); } /* Free the escaped version if required */ if (val != escval) free(escval); } /* Only put in delimeter if not last field or a shape will follow */ if (state->config->readshape == 1 || i < DBFGetFieldCount(state->hDBFHandle) - 1) { if (state->config->dump_format) vasbappend(sb, "\t"); else vasbappend(sb, ","); } /* End of DBF attribute loop */ } /* Add the shape attribute if we are reading it */ if (state->config->readshape == 1) { /* Handle the case of a NULL shape */ if (obj->nVertices == 0) { if (state->config->dump_format) vasbappend(sb, "\\N"); else vasbappend(sb, "NULL"); } else { /* Handle all other shape attributes */ switch (obj->nSHPType) { case SHPT_POLYGON: case SHPT_POLYGONM: case SHPT_POLYGONZ: res = GeneratePolygonGeometry(state, obj, &geometry); if (res != SHPLOADEROK) { /* Error message has already been set */ SHPDestroyObject(obj); stringbuffer_destroy(sbwarn); stringbuffer_destroy(sb); return SHPLOADERERR; } break; case SHPT_POINT: case SHPT_POINTM: case SHPT_POINTZ: case SHPT_MULTIPOINT: case SHPT_MULTIPOINTM: case SHPT_MULTIPOINTZ: res = GeneratePointGeometry(state, obj, &geometry); if (res != SHPLOADEROK) { /* Error message has already been set */ SHPDestroyObject(obj); stringbuffer_destroy(sbwarn); stringbuffer_destroy(sb); return SHPLOADERERR; } break; case SHPT_ARC: case SHPT_ARCM: case SHPT_ARCZ: res = GenerateLineStringGeometry(state, obj, &geometry); if (res != SHPLOADEROK) { /* Error message has already been set */ SHPDestroyObject(obj); stringbuffer_destroy(sbwarn); stringbuffer_destroy(sb); return SHPLOADERERR; } break; default: snprintf(state->message, SHPLOADERMSGLEN, "Shape type is NOT SUPPORTED, type id = %d", obj->nSHPType); SHPDestroyObject(obj); stringbuffer_destroy(sbwarn); stringbuffer_destroy(sb); return SHPLOADERERR; } /* Now generate the geometry string according to the current configuration */ if (state->config->hwgeom) { /* Old-style hwgeom (WKT) */ if (!state->config->dump_format) vasbappend(sb, "GeomFromText('"); else { /* Output SRID if relevant */ if (state->config->sr_id != 0) vasbappend(sb, "SRID=%d;", state->config->sr_id); } vasbappend(sb, "%s", geometry); if (!state->config->dump_format) { vasbappend(sb, "'"); /* Output SRID if relevant */ if (state->config->sr_id != 0) vasbappend(sb, ", %d)", state->config->sr_id); else vasbappend(sb, ")"); } } else { /* New style lwgeom (HEXEWKB) */ if (!state->config->dump_format) vasbappend(sb, "'"); vasbappend(sb, "%s", geometry); if (!state->config->dump_format) vasbappend(sb, "'"); } free(geometry); } /* Tidy up everything */ SHPDestroyObject(obj); } /* Close the line correctly for dump/insert format */ if (!state->config->dump_format) vasbappend(sb, ");"); /* Copy the string buffer into a new string, destroying the string buffer */ ret = (char *)malloc(strlen((char *)stringbuffer_getstring(sb)) + 1); strcpy(ret, (char *)stringbuffer_getstring(sb)); stringbuffer_destroy(sb); *strrecord = ret; /* If any warnings occurred, set the returned message string and warning status */ if (strlen((char *)stringbuffer_getstring(sbwarn)) > 0) { snprintf(state->message, SHPLOADERMSGLEN, "%s", stringbuffer_getstring(sbwarn)); stringbuffer_destroy(sbwarn); return SHPLOADERWARN; } else { /* Everything went okay */ stringbuffer_destroy(sbwarn); return SHPLOADEROK; } }
/* Return a pointer to an allocated string containing the header for the specified loader state */ int ShpLoaderGetSQLHeader(SHPLOADERSTATE *state, char **strheader) { stringbuffer_t *sb; char *ret; int j; /* Create the stringbuffer containing the header; we use this API as it's easier for handling string resizing during append */ sb = stringbuffer_create(); stringbuffer_clear(sb); /* Set the client encoding if required */ if (state->config->encoding) { vasbappend(sb, "SET CLIENT_ENCODING TO UTF8;\n"); } /* Use SQL-standard string escaping rather than PostgreSQL standard */ vasbappend(sb, "SET STANDARD_CONFORMING_STRINGS TO ON;\n"); /* Drop table if requested */ if (state->config->opt == 'd') { /** * TODO: if the table has more then one geometry column * the DROP TABLE call will leave spurious records in * geometry_columns. * * If the geometry column in the table being dropped * does not match 'the_geom' or the name specified with * -g an error is returned by DropGeometryColumn. * * The table to be dropped might not exist. */ if (state->config->schema) { if (state->config->readshape == 1 && (! state->config->geography) ) { vasbappend(sb, "SELECT DropGeometryColumn('%s','%s','%s');\n", state->config->schema, state->config->table, state->config->geom); } vasbappend(sb, "DROP TABLE \"%s\".\"%s\";\n", state->config->schema, state->config->table); } else { if (state->config->readshape == 1 && (! state->config->geography) ) { vasbappend(sb, "SELECT DropGeometryColumn('','%s','%s');\n", state->config->table, state->config->geom); } vasbappend(sb, "DROP TABLE \"%s\";\n", state->config->table); } } /* Start of transaction */ vasbappend(sb, "BEGIN;\n"); /* If not in 'append' mode create the spatial table */ if (state->config->opt != 'a') { /* * Create a table for inserting the shapes into with appropriate * columns and types */ if (state->config->schema) { vasbappend(sb, "CREATE TABLE \"%s\".\"%s\" (gid serial PRIMARY KEY", state->config->schema, state->config->table); } else { vasbappend(sb, "CREATE TABLE \"%s\" (gid serial PRIMARY KEY", state->config->table); } /* Generate the field types based upon the shapefile information */ for (j = 0; j < state->num_fields; j++) { vasbappend(sb, ",\n\"%s\" ", state->field_names[j]); switch (state->types[j]) { case FTString: /* use DBF attribute size as maximum width */ vasbappend(sb, "varchar(%d)", state->widths[j]); break; case FTDate: vasbappend(sb, "date"); break; case FTInteger: /* Determine exact type based upon field width */ if (state->config->forceint4) { vasbappend(sb, "int4"); } else if (state->widths[j] < 5) { vasbappend(sb, "int2"); } else if (state->widths[j] < 10) { vasbappend(sb, "int4"); } else { vasbappend(sb, "numeric(%d,0)", state->widths[j]); } break; case FTDouble: /* Determine exact type based upon field width */ if (state->widths[j] > 18) { vasbappend(sb, "numeric"); } else { vasbappend(sb, "float8"); } break; case FTLogical: vasbappend(sb, "boolean"); break; default: snprintf(state->message, SHPLOADERMSGLEN, "Invalid type %x in DBF file", state->types[j]); stringbuffer_destroy(sb); return SHPLOADERERR; } } /* Add the geography column directly to the table definition, we don't need to do an AddGeometryColumn() call. */ if (state->config->readshape == 1 && state->config->geography) { char *dimschar; if ( state->pgdims == 4 ) dimschar = "ZM"; else dimschar = ""; if (state->config->sr_id != -1 && state->config->sr_id != 4326) { snprintf(state->message, SHPLOADERMSGLEN, "Invalid SRID for geography type: %x", state->config->sr_id); stringbuffer_destroy(sb); return SHPLOADERERR; } vasbappend(sb, ",\n\"%s\" geography(%s%s,%d)", state->config->geom, state->pgtype, dimschar, 4326); } vasbappend(sb, ");\n"); /* Create the geometry column with an addgeometry call */ if (state->config->readshape == 1 && (!state->config->geography)) { if (state->config->schema) { vasbappend(sb, "SELECT AddGeometryColumn('%s','%s','%s','%d',", state->config->schema, state->config->table, state->config->geom, state->config->sr_id); } else { vasbappend(sb, "SELECT AddGeometryColumn('','%s','%s','%d',", state->config->table, state->config->geom, state->config->sr_id); } vasbappend(sb, "'%s',%d);\n", state->pgtype, state->pgdims); } } /* Copy the string buffer into a new string, destroying the string buffer */ ret = (char *)malloc(strlen((char *)stringbuffer_getstring(sb)) + 1); strcpy(ret, (char *)stringbuffer_getstring(sb)); stringbuffer_destroy(sb); *strheader = ret; return SHPLOADEROK; }