Beispiel #1
0
/* 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;
}
Beispiel #2
0
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;
}
Beispiel #4
0
/** 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;
}
Beispiel #7
0
/** 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;
}
Beispiel #8
0
/* 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;
}
Beispiel #9
0
/**
* 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;
}
Beispiel #10
0
/**@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;
}
Beispiel #11
0
/* 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;
}
Beispiel #12
0
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);
}
Beispiel #13
0
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);
}
Beispiel #14
0
/* 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;
	}
}
Beispiel #15
0
/* 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;
}