VoltDB provides standard datatypes for storing common numeric and textual content. It also provides support for JSON within VARCHAR columns to handle semi-structured content, as described in the preceding chapter. But not all application data can be efficiently managed using just the standard datatypes.

One example of an application area requiring special handling is geospatial data — that is, information about locations and regions on the earth. It is possible to store geospatial data using standard datatypes; for example, storing longitude and latitude as two separate FLOAT columns. However, by storing the data in generic datatype columns the information loses its context. For example, using separate columns it is impossible to tell how far apart two points are or whether those points are part of a larger geometric shape.

To simplify the use of geospatial information, VoltDB includes two geospatial datatypes and a number of functions that help you evaluate and operate on that data. This chapter describes the new datatypes and provides basic information on how to input and use that data in stored procedures and SQL queries.

VoltDB supports two geospatial datatypes:

GEOGRAPHY

GEOGRAPHY_POINT

The GEOGRAPHY datatype supports geographical regions defined as polygons. The GEOGRAPHY_POINT datatype defines a single point using a pair of longitude and latitude values. Both datatypes can be represented as text in an industry format known as Well Known Text (WKT) defined by the Open Geospatial Consortium (OGC). VoltDB provides functions for converting WKT representations to both GEOGRAPHY and GEOGRPAHY_POINT values. WKT is also how values of these types are displayed by sqlcmd and the VoltDB Management Center. Since GEOGRAPHY_POINT is the simpler of the two points, we will discuss it first.

A GEOGRAPHY_POINT represents a single point on earth as defined by a longitude and latitude value. The WKT representation of a GEOGRAPHY_POINT value is the following:

POINT ( * longitude-value* *latitude-value* )

The longitude is a floating point value between 180 and -180 inclusive. The latitude is a floating point value between 90 and -90 inclusive.

The GEOGRAPHY datatype defines a bounded region of the earth represented by one or more polygons. The first polygon,
or *ring*, describes the outer boundary of the region. Subsequent rings within the WKT representation
describe "holes" within the outer region. So, for example, the following shaded region is described by three rings:

The outer ring, A

Two inner rings, B and C

In the WKT representation, the outer ring must be listed first, with the vertices listed in counter-clockwise order (e.g. A5, A4, A3, A2, A1). The inner rings, if any, are listed next with the vertices in clockwise order (e.g. B1, B2, B3). The lines of the rings must not cross or overlap and the description of each ring must list the starting vertex twice: as both the first and last vertex.

Note that, although the individual rings must not cross and vertices must be in the correct order for the geospatial
functions to generate valid results, the correctness of the polygon is *not* checked by VoltDB when the
GEOGRAPHY data is inserted. If you are unsure of the correctness of the originating data, you can use the ISVALID() and
ISINVALIDREASON() functions to validate GEOGRAPHY values within a SQL query.

The WKT representation of a GEOGRAPHY value is the following, where each vertex-list is a comma-separated list of longitude and latitude values describing a single ring:

POLYGON ( ( *vertex-list* ) [ , ( *vertex-list* ) ]... )

For example, the simplest polygon, which consists of a single outer ring of three vertices, could be represented like this:

POLYGON ( ( 1.5 3.0, 0.0 0.0, 3.0 0.0, 1.5 3.0 ) )

For a polygon with two inner rings, the WKT might look like the following:

POLYGON ( ( 1.5 3.0, 0.0 0.0, 3.0 0.0, 1.5 3.0 ), ( 1.0 1.0, 1.5 0.5, 0.5 0.5, 1.0 1.0 ), ( 2.0 1.0, 2.5 0.5, 1.5 0.5, 2.0 1.0 ) )

GEOGRAPHY polygons, unlike GEOGRAPHY_POINT values, do not have a fixed size. The memory required to store a GEOGRAPHY column varies depending on the number of rings and the number of vertices in each ring. In this way, GEOGRAPHY columns are treated much like VARCHAR and VARBINARY columns when VoltDB manages their allocation and storage.

For convenience, VoltDB provides a default maximum size for GEOGRAPHY columns. So if you declare the column without a specific size, it is assigned a maximum size of 32 kilobytes (32768 bytes):

```
CREATE TABLE Country (
Name VARCHAR(32),
```**Border GEOGRAPHY**
);

However, for very large polygons, this default size may be too small. Or, if you have GEOGRAPHY columns mixed with large VARCHAR columns in a single table, the default may be too large because there is a two megabyte limit for the sum of the columns in a single table.

You can specify your own maximum size for a GEOGRAPHY column, in bytes, by including the maximum size in parentheses
after the datatype keyword, the same way you do for VARCHAR columns. For example, the following CREATE TABLE statement
defines the maximum size of the *border* column as 1024 bytes:

```
CREATE TABLE Country (
Name VARCHAR(32),
```**Border GEOGRAPHY(1024)**
);

To determine how much space is required to store any polygon, use the following calculation:

40 bytes for the polygon

43 bytes for every ring

24 bytes for every vertex

Note that when counting the vertices, although the starting vertex must be listed twice in the WKT representation, it is only stored once and therefore only counted once in the memory allocation. For example, the memory calculation for a polygon with an outer ring with 10 vertices and 3 inner rings with 8 vertices each would be the following:

40 bytes 172 bytes ( 43 X 4 rings ) 816 bytes ( 24 X 34 total vertices ) ------------ 1028 bytes total

The largest maximum size you can specify for a GEOGRAPHY column, or any column in VoltDB, is one megabyte.

The earth itself is not uniformly round. However, measurements accurate enough for most applications can be achieved by assuming a perfect sphere and mapping the longitude and latitude coordinates onto that sphere. For calculating distances between locations and areas of regions VoltDB assumes a sphere with a radius matching the mean radius of the earth, or 6,371,008.8 meters. Although an approximation, this model provides distance calculations accurate to within three tenths of a percent (0.3%) of other, more elaborate geospatial models. What this means is, when calculating the distance between two points that are a kilometer apart, the answer computed by the DISTANCE() function may vary up to 3 meters from calculations using other techniques.