【demo1】
This program shows the basic functionality that will be required for most SpatiaLite programs 大多数SpatiaLite程序所需的基本功能
- how to connect an SQLite+SpatiaLite database 如何连接SQLite+SpatiaLite数据库
- executing an SQL query 执行SQL查询
- fetching values from a result set 从结果集中获取值
- transforming BLOB-values into GEOMETRY 将BLOB值转换为GEOMETRY
- elementary processing GEOMETRY 基本处理GEOMETRY
#Q:SRID可以一样?
gpkg文件数据:
========= table 'HighWays' ========================
“高速公路”表:UID, Name, Geometry, SRID, length
PK_UID = 1
Name = 'Unknown'
Geometry = LINESTRING SRID=32632 length=8697.57
========= table 'Regions' ========================
“区域”表:UID, Name, Geometry, SRID, area
PK_UID = 1
Name = 'VENETO'
Geometry = MULTIPOLYGON SRID=32632 area=646397.81
========= table 'Towns' ========================
"城镇"表:UID, Name, Peoples, Localcounc, county, region, Geometry, SRID
PK_UID = 1
Name = 'Brozolo'
Peoples = 435
LocalCounc = 1
County = 0
Region = 0
Geometry = POINT SRID=32632
支持SQLite/SpatiaLite所需要的头文件
#include <spatialite/gaiaconfig.h>
#include <sqlite3.h>
#include <spatialite/gaiageo.h> //放在sqlite3后,否则报错
#include <spatialite.h>
尝试连接测试DB:(只读)
代码:
sqlite3 *handle;
int ret = sqlite3_open_v2(DB文件地址, &handle, SQLITE_OPEN_READONLY, NULL);
函数解释sqlite3_open_v2:
int sqlite3_open_v2( //打开由filename参数指定的SQLite数据库文件。
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb, /* OUT: SQLite db handle */
int flags, /* Flags */
const char *zVfs /* Name of VFS module to use */ NULL-使用默认的sqlite3_vfs对象。
);
flag参数:
SQLITE_OPEN_READONLY 只读(数据库必须已经存在)
SQLITE_OPEN_READWRITE 读取和写入(数据库必须已经存在)
SQLITE_OPEN_READWRITE OR SQLITE_OPEN_CREATE阅读和写入(如果数据库不存在,则创建)
非常重要:
初始化SpatiaLite扩展(在尝试执行任何其他SQLite调用之前)
==========================================================
请注意:从4.1.0开始,这是完全仓促的:
-每个连接需要一个单独的内存块(内部缓存)
-分配/释放此块属于处理连接的程序的责任
--在多线程程序中,一个连接永远不能被不同的线程共享;内部缓存块必须由持有该连接的同一个线程分配
代码:
void *cache = spatialite_alloc_connection();
spatialite_init_ex(handle, cache, 0);
【demo2】
如何在Spatialite中操作Geometry。
-创建Geometry
-扩展Geometry
-查询Geometry的基本属性
step#1: POINT Dimension=0 IsValid=1
POINT 0/1 x=1.5000 y=2.7500
step#2: LINESTRING Dimension=1 IsValid=1
LINESTRING 0/1 has 5 vertices
vertex 0/5 x=1.0000 y=1.0000
vertex 1/5 x=2.0000 y=1.0000
vertex 2/5 x=2.0000 y=2.0000
vertex 3/5 x=100.0000 y=2.0000
vertex 4/5 x=100.0000 y=100.0000
step#3: POLYGON Dimension=2 IsValid=1
POLYGON 0/1 has 2 holes
ExteriorRing has 5 vertices
vertex 0/5 x=0.0000 y=0.0000
vertex 1/5 x=50.0000 y=0.0000
vertex 2/5 x=50.0000 y=50.0000
vertex 3/5 x=0.0000 y=50.0000
vertex 4/5 x=0.0000 y=0.0000
InteriorRing 0/2 has 5 vertices
vertex 0/5 x=40.0000 y=40.0000
vertex 1/5 x=41.0000 y=40.0000
vertex 2/5 x=41.0000 y=41.0000
vertex 3/5 x=40.0000 y=41.0000
vertex 4/5 x=40.0000 y=40.0000
InteriorRing 1/2 has 5 vertices
vertex 0/5 x=30.0000 y=30.0000
vertex 1/5 x=31.0000 y=30.0000
vertex 2/5 x=31.0000 y=31.0000
vertex 3/5 x=30.0000 y=31.0000
vertex 4/5 x=30.0000 y=30.0000
step#4: MULTIPOINT Dimension=0 IsValid=1
POINT 0/5 x=5.0000 y=5.0000
POINT 1/5 x=15.0000 y=5.0000
POINT 2/5 x=5.0000 y=15.0000
POINT 3/5 x=25.0000 y=5.0000
POINT 4/5 x=5.0000 y=25.0000
step#5: MULTILINESTRING Dimension=1 IsValid=1
LINESTRING 0/2 has 2 vertices
vertex 0/2 x=30.0000 y=10.0000
vertex 1/2 x=10.0000 y=30.0000
LINESTRING 1/2 has 2 vertices
vertex 0/2 x=40.0000 y=50.0000
vertex 1/2 x=50.0000 y=40.0000
step#6: MULTIPOLYGON Dimension=2 IsValid=1
POLYGON 0/2 has 0 holes
ExteriorRing has 5 vertices
vertex 0/5 x=60.0000 y=60.0000
vertex 1/5 x=70.0000 y=60.0000
vertex 2/5 x=70.0000 y=70.0000
vertex 3/5 x=60.0000 y=70.0000
vertex 4/5 x=60.0000 y=60.0000
POLYGON 1/2 has 0 holes
ExteriorRing has 5 vertices
vertex 0/5 x=80.0000 y=80.0000
vertex 1/5 x=90.0000 y=80.0000
vertex 2/5 x=90.0000 y=90.0000
vertex 3/5 x=80.0000 y=90.0000
vertex 4/5 x=80.0000 y=80.0000
step#7: GEOMETRYCOLLECTION Dimension=2 IsValid=1
POINT 0/2 x=100.0000 y=100.0000
POINT 1/2 x=100.0000 y=0.0000
LINESTRING 0/2 has 2 vertices
vertex 0/2 x=130.0000 y=110.0000
vertex 1/2 x=110.0000 y=130.0000
LINESTRING 1/2 has 2 vertices
vertex 0/2 x=140.0000 y=150.0000
vertex 1/2 x=150.0000 y=140.0000
POLYGON 0/2 has 0 holes
ExteriorRing has 5 vertices
vertex 0/5 x=160.0000 y=160.0000
vertex 1/5 x=170.0000 y=160.0000
vertex 2/5 x=170.0000 y=170.0000
vertex 3/5 x=160.0000 y=170.0000
vertex 4/5 x=160.0000 y=160.0000
POLYGON 1/2 has 0 holes
ExteriorRing has 5 vertices
vertex 0/5 x=180.0000 y=180.0000
vertex 1/5 x=190.0000 y=180.0000
vertex 2/5 x=190.0000 y=190.0000
vertex 3/5 x=180.0000 y=190.0000
vertex 4/5 x=180.0000 y=180.0000
step#8: checking WKT representations
GEOMETRYCOLLECTION(POINT(1.5 2.75))
GEOMETRYCOLLECTION(LINESTRING(1 1, 2 1, 2 2, 100 2, 100 100))
GEOMETRYCOLLECTION(POLYGON((0 0, 50 0, 50 50, 0 50, 0 0), (40 40, 41 40, 41 41, 40 41, 40 40), (30 30, 31 30, 31 31, 30 31, 30 30)))
GEOMETRYCOLLECTION(POINT(5 5), POINT(15 5), POINT(5 15), POINT(25 5), POINT(5 25))
GEOMETRYCOLLECTION(LINESTRING(30 10, 10 30), LINESTRING(40 50, 50 40))
GEOMETRYCOLLECTION(POLYGON((60 60, 70 60, 70 70, 60 70, 60 60)), POLYGON((80 80, 90 80, 90 90, 80 90, 80 80)))
GEOMETRYCOLLECTION(POINT(100 100), POINT(100 0), LINESTRING(130 110, 110 130), LINESTRING(140 150, 150 140), POLYGON((160 160, 170 160, 170 170, 160 170, 160 160)), POLYGON((180 180, 190 180, 190 190, 180 190, 180 180)))
【sqlite3】 *handle;
CAPI3REF:数据库连接句柄
关键字:{数据库连接}{数据库连接}
每个打开的SQLite数据库由指向名为"sqlite3"的不透明结构实例的指针表示。 将sqlite3指针视为对象是很有用的。
构造函数:Sqlite3_open()、sqlite3_open16()和sqlite3_open_v2()接口
析构函数:sqlite3_close()和sqlite3_close_v2()
其他接口:sqlite3_prepare_v2(),sqlite3_create_function()和sqlite3_busy_timeout()
此演示不严格要求建立任何数据库连接
但是,您必须初始化SpatiaLite扩展[和相关]
而你*必须*建立一个"假"DB连接,以便正确初始化SpatiaLite和GEOS库 ":memory:"
ret = sqlite3_open_v2 (":memory:", &handle, SQLITE_OPEN_READONLY, NULL);
if (ret != SQLITE_OK)
{
printf ("cannot open '%s': %s\n", ":memory:", sqlite3_errmsg (handle));
sqlite3_close (handle);
return -1;
}
cache = spatialite_alloc_connection ();
spatialite_init_ex (handle, cache, 0);
//demo2
#pragma region demo2
gaiaGeomCollPtr geo_pt = NULL; //Container for OGC GEOMETRYCOLLECTION Geometry
gaiaGeomCollPtr geo_ln = NULL;
gaiaGeomCollPtr geo_pg = NULL;
gaiaGeomCollPtr geo_mpt = NULL;
gaiaGeomCollPtr geo_mln = NULL;
gaiaGeomCollPtr geo_mpg = NULL;
gaiaGeomCollPtr geo_coll = NULL;
gaiaLinestringPtr line; //Typedef for OGC LINESTRING structure
gaiaPolygonPtr polyg; //Typedef for OGC POLYGON structure
gaiaRingPtr ring; //Typedef for OGC RING structure
gaiaOutBuffer wkt; //Container for dynamically growing output buffer
int ret;
sqlite3 *handle;
void *cache;
//建立“虚拟”链接,读取缓存,初始化
ret = sqlite3_open_v2(":memory:", &handle, SQLITE_OPEN_READONLY, NULL);
cout << ret << endl;
if (ret != SQLITE_OK)
{
printf("cannot open '%s': %s\n", ":memory:",
sqlite3_errmsg(handle));
sqlite3_close(handle);
return -1;
}
cache = spatialite_alloc_connection();
spatialite_init_ex(handle, cache, 0);
//Step #1 创建和检查POINT(分配一个Geometry对象)
geo_pt = gaiaAllocGeomColl(); //分配一个2D Geometry,返回指向新创建的Geometry对象的指针
gaiaAddPointToGeomColl(geo_pt, 1.5, 2.75); //插入一个POINT到新创建的Geometry对象中,并传递其坐标
//gaiaAddPointToGeomColl(geo_pt, 1.8, 2.75);
printf("step#1: %s\t\tDimension=%d IsValid=%d\n", //打印POINT的主要属性
geom_type(gaiaGeometryType(geo_pt)), //确定Geometry对象的相应类型,失败时返回GAIA_NONE
gaiaDimension(geo_pt), //确定Geometry对象的OGC维度,-1-无,0-点,1-点/linestring,2-polygon
gaiaIsValid_r(cache, geo_pt)); //检查Geometry对象是否表示OGC有效Geometry
geometry_printout(geo_pt); //打印通用Geometry对象
//Step #2 创建和检查LINESTRING(分配一个Geometry对象)
geo_ln = gaiaAllocGeomColl(); //分配一个2D Geometry,返回指向新创建的Geometry对象的指针
line = gaiaAddLinestringToGeomColl(geo_ln, 5); //插入一个LINESTRING到新创建的Geometry对象中,并指定其包含的顶点数,返回指向新创建的Linestring的指针
gaiaSetPoint(line->Coords, 0, 1.0, 1.0); //用line指针引用刚刚插入的LINESTRING,为每个顶点设置坐标
gaiaSetPoint(line->Coords, 1, 2.0, 1.0);
gaiaSetPoint(line->Coords, 2, 2.0, 2.0);
gaiaSetPoint(line->Coords, 3, 100.0, 2.0);
gaiaSetPoint(line->Coords, 4, 100.0, 100.0);
printf("\nstep#2: %s\tDimension=%d IsValid=%d\n", //打印LINESTRING的主要属性
geom_type(gaiaGeometryType(geo_ln)),
gaiaDimension(geo_ln),
gaiaIsValid_r(cache, geo_ln));
geometry_printout(geo_ln);
//Step #3 创建和检查POLYGON(分配一个Geometry对象)
geo_pg = gaiaAllocGeomColl(); //分配一个2D Geometry,返回指向新创建的Geometry对象的指针
polyg = gaiaAddPolygonToGeomColl(geo_pg, 5, 2); //插入一个POLYGON到新创建的Geometry对象中,指定为外环分配的顶点数vertices,指定内环Interior Rings的数量
ring = polyg->Exterior; //指向外环Exterior ring的指针
gaiaSetPoint(ring->Coords, 0, 0.0, 0.0); //为每个外环顶点设置坐标
gaiaSetPoint(ring->Coords, 1, 50.0, 0.0);
gaiaSetPoint(ring->Coords, 2, 50.0, 50.0);
gaiaSetPoint(ring->Coords, 3, 0.0, 50.0);
gaiaSetPoint(ring->Coords, 4, 0.0, 0.0); //环是一个封闭的图形,所以最后一个和第一个顶点必须重合
ring = gaiaAddInteriorRing(polyg, 0, 5); //指向第一个内环的指针,为每个顶点设置坐标
gaiaSetPoint(ring->Coords, 0, 40.0, 40.0);
gaiaSetPoint(ring->Coords, 1, 41.0, 40.0);
gaiaSetPoint(ring->Coords, 2, 41.0, 41.0);
gaiaSetPoint(ring->Coords, 3, 40.0, 41.0);
gaiaSetPoint(ring->Coords, 4, 40.0, 40.0);
ring = gaiaAddInteriorRing(polyg, 1, 5); //指向第二个内环的指针,为每个顶点设置坐标
gaiaSetPoint(ring->Coords, 0, 30.0, 30.0);
gaiaSetPoint(ring->Coords, 1, 31.0, 30.0);
gaiaSetPoint(ring->Coords, 2, 31.0, 31.0);
gaiaSetPoint(ring->Coords, 3, 30.0, 31.0);
gaiaSetPoint(ring->Coords, 4, 30.0, 30.0);
printf("\nstep#3: %s\tDimension=%d IsValid=%d\n", //打印POLYGON的主要属性
geom_type(gaiaGeometryType(geo_pg)),
gaiaDimension(geo_pg),
gaiaIsValid_r(cache, geo_pg));
geometry_printout(geo_pg);
//Step #4 创建和检查MULTIPOINT(分配一个Geometry对象)
geo_mpt = gaiaAllocGeomColl(); //分配一个2D Geometry,返回指向新创建的Geometry对象的指针
gaiaAddPointToGeomColl(geo_mpt, 5.0, 5.0); //插入多个点坐标
gaiaAddPointToGeomColl(geo_mpt, 15.0, 5.0);
gaiaAddPointToGeomColl(geo_mpt, 5.0, 15.0);
gaiaAddPointToGeomColl(geo_mpt, 25.0, 5.0);
gaiaAddPointToGeomColl(geo_mpt, 5.0, 25.0);
printf("\nstep#4: %s\tDimension=%d IsValid=%d\n", //打印MULTIPOINT的主要属性
geom_type(gaiaGeometryType(geo_mpt)),
gaiaDimension(geo_mpt),
gaiaIsValid_r(cache, geo_mpt));
geometry_printout(geo_mpt);
//Step #5 创建和检查MULTILINESTRING(分配一个Geometry对象)
geo_mln = gaiaAllocGeomColl(); //分配一个2D Geometry,返回指向新创建的Geometry对象的指针
line = gaiaAddLinestringToGeomColl(geo_mln, 2); //插入第一个LINESTRING
gaiaSetPoint(line->Coords, 0, 30.0, 10.0);
gaiaSetPoint(line->Coords, 1, 10.0, 30.0);
line = gaiaAddLinestringToGeomColl(geo_mln, 2); //插入第二个LINESTRING
gaiaSetPoint(line->Coords, 0, 40.0, 50.0);
gaiaSetPoint(line->Coords, 1, 50.0, 40.0);
printf("\nstep#5: %s\tDimension=%d IsValid=%d\n", //打印MULTILINESTRING的主要属性
geom_type(gaiaGeometryType(geo_mln)),
gaiaDimension(geo_mln),
gaiaIsValid_r(cache, geo_mln));
geometry_printout(geo_mln);
//Step #6 创建和检查MULTIPOLYGON(分配一个Geometry对象)
geo_mpg = gaiaAllocGeomColl(); //分配一个2D Geometry,返回指向新创建的Geometry对象的指针
polyg = gaiaAddPolygonToGeomColl(geo_mpg, 5, 0); //插入第一个POLYGON
ring = polyg->Exterior;
gaiaSetPoint(ring->Coords, 0, 60.0, 60.0);
gaiaSetPoint(ring->Coords, 1, 70.0, 60.0);
gaiaSetPoint(ring->Coords, 2, 70.0, 70.0);
gaiaSetPoint(ring->Coords, 3, 60.0, 70.0);
gaiaSetPoint(ring->Coords, 4, 60.0, 60.0);
polyg = gaiaAddPolygonToGeomColl(geo_mpg, 5, 0); //插入第二个POLYGON
ring = polyg->Exterior;
gaiaSetPoint(ring->Coords, 0, 80.0, 80.0);
gaiaSetPoint(ring->Coords, 1, 90.0, 80.0);
gaiaSetPoint(ring->Coords, 2, 90.0, 90.0);
gaiaSetPoint(ring->Coords, 3, 80.0, 90.0);
gaiaSetPoint(ring->Coords, 4, 80.0, 80.0);
printf("\nstep#6: %s\tDimension=%d IsValid=%d\n", //打印MULTIPOLYGON的主要属性
geom_type(gaiaGeometryType(geo_mpg)),
gaiaDimension(geo_mpg),
gaiaIsValid_r(cache, geo_mpg));
geometry_printout(geo_mpg);
//Step #7 创建和检查GEOMETRYCOLLECTION(分配一个Geometry对象)
geo_coll = gaiaAllocGeomColl(); //分配一个2D Geometry,返回指向新创建的Geometry对象的指针
gaiaAddPointToGeomColl(geo_coll, 100.0, 100.0); //插入第一个POINT
gaiaAddPointToGeomColl(geo_coll, 100.0, 0.0); //插入第二个POINT
line = gaiaAddLinestringToGeomColl(geo_coll, 2); //插入第一个LINESTRING
gaiaSetPoint(line->Coords, 0, 130.0, 110.0);
gaiaSetPoint(line->Coords, 1, 110.0, 130.0);
line = gaiaAddLinestringToGeomColl(geo_coll, 2); //插入第二个LINESTRING
gaiaSetPoint(line->Coords, 0, 140.0, 150.0);
gaiaSetPoint(line->Coords, 1, 150.0, 140.0);
polyg = gaiaAddPolygonToGeomColl(geo_coll, 5, 0); //插入第一个POLYGON
ring = polyg->Exterior;
gaiaSetPoint(ring->Coords, 0, 160.0, 160.0);
gaiaSetPoint(ring->Coords, 1, 170.0, 160.0);
gaiaSetPoint(ring->Coords, 2, 170.0, 170.0);
gaiaSetPoint(ring->Coords, 3, 160.0, 170.0);
gaiaSetPoint(ring->Coords, 4, 160.0, 160.0);
polyg = gaiaAddPolygonToGeomColl(geo_coll, 5, 0); //插入第二个POLYGON
ring = polyg->Exterior;
gaiaSetPoint(ring->Coords, 0, 180.0, 180.0);
gaiaSetPoint(ring->Coords, 1, 190.0, 180.0);
gaiaSetPoint(ring->Coords, 2, 190.0, 190.0);
gaiaSetPoint(ring->Coords, 3, 180.0, 190.0);
gaiaSetPoint(ring->Coords, 4, 180.0, 180.0);
printf("\nstep#7: %s\tDimension=%d IsValid=%d\n", //打印GEOMETRYCOLLECTION的主要属性
geom_type(gaiaGeometryType(geo_coll)),
gaiaDimension(geo_coll),
gaiaIsValid_r(cache, geo_coll));
geometry_printout(geo_coll);
//Step #8 将每个Geometry对象用WKT格式打印
printf("\nstep#8: checking WKT representations\n");
gaiaOutBufferInitialize(&wkt); //初始化 动态增长的文本输出 缓冲区
gaiaOutWkt(&wkt, geo_pt); //将 Geometry对象 编码为 WKT表示
if (wkt.Error == 0 && wkt.Buffer != NULL) //检查WKT表示是否为NULL
{
printf("\n%s\n", wkt.Buffer); //打印WKT表示
gaiaOutBufferReset(&wkt); //释放wkt临时存储分配
}
gaiaOutBufferInitialize(&wkt);
gaiaOutWkt(&wkt, geo_ln);
if (wkt.Error == 0 && wkt.Buffer != NULL)
{
printf("\n%s\n", wkt.Buffer);
gaiaOutBufferReset(&wkt);
}
gaiaOutBufferInitialize(&wkt);
gaiaOutWkt(&wkt, geo_pg);
if (wkt.Error == 0 && wkt.Buffer != NULL)
{
printf("\n%s\n", wkt.Buffer);
gaiaOutBufferReset(&wkt);
}
gaiaOutBufferInitialize(&wkt);
gaiaOutWkt(&wkt, geo_mpt);
if (wkt.Error == 0 && wkt.Buffer != NULL)
{
printf("\n%s\n", wkt.Buffer);
gaiaOutBufferReset(&wkt);
}
gaiaOutBufferInitialize(&wkt);
gaiaOutWkt(&wkt, geo_mln);
if (wkt.Error == 0 && wkt.Buffer != NULL)
{
printf("\n%s\n", wkt.Buffer);
gaiaOutBufferReset(&wkt);
}
gaiaOutBufferInitialize(&wkt);
gaiaOutWkt(&wkt, geo_mpg);
if (wkt.Error == 0 && wkt.Buffer != NULL)
{
printf("\n%s\n", wkt.Buffer);
gaiaOutBufferReset(&wkt);
}
gaiaOutBufferInitialize(&wkt);
gaiaOutWkt(&wkt, geo_coll);
if (wkt.Error == 0 && wkt.Buffer != NULL)
{
printf("\n%s\n", wkt.Buffer);
gaiaOutBufferReset(&wkt);
}
//清理内存,销毁每个对象的临时存储
if (geo_pt)
gaiaFreeGeomColl(geo_pt);
if (geo_ln)
gaiaFreeGeomColl(geo_ln);
if (geo_pg)
gaiaFreeGeomColl(geo_pg);
if (geo_mpt)
gaiaFreeGeomColl(geo_mpt);
if (geo_mln)
gaiaFreeGeomColl(geo_mln);
if (geo_mpg)
gaiaFreeGeomColl(geo_mpg);
if (geo_coll)
gaiaFreeGeomColl(geo_coll);
sqlite3_close(handle); //关闭数据库连接
spatialite_cleanup_ex(cache); //清理SpatiaLite连接
spatialite_shutdown(); //终止spatialite库
#pragma endregion demo2
【demo3】
how to use the SQLite / SpatiaLite Spatial Index [RTree]. 空间索引[RTree]
It follows on from demo1.c.
The main steps in this example are:
- creating a new database创建一个新的数据库
- creating a sample geo-table 创建示例地理表
- inserting 1 million rows into this table将100万行插入此表
- performing some spatial queries without Spatial Indexing在没有空间索引的情况下执行一些空间查询
- performing the same queries using the Spatial Index使用空间索引执行相同的查询
注意与使用适当索引相关的经过时间的显着差异。
sqlite3_stmt *stmt; //已编译为二进制形式并准备进行计算的单个SQL语句
将每个SQL语句视为单独的计算机程序。原始SQL文本是源代码。准备好的语句对象是编译的目标代码。所有SQL都必须转换为准备好的语句才能运行。
-使用sqlite3_prepare_v2()创建准备好的语句对象
-使用sqlite3_bind_*()将值绑定到[参数]接口
-通过调用sqlite3_step()一次或多次来运行SQL
-使用sqlite3_reset()重置准备好的语句,然后返回步骤2
-使用sqlite3_finalize()销毁对象
//空DB,需要创建Spatial Metadata
char sql[256];
strcpy(sql, "SELECT InitSpatialMetadata(1)");
ret = sqlite3_exec(handle, sql, NULL, NULL, &err_msg);
【SQL指令:SELECT InitSpatialMetadata()函数】
-创建geometry_columns和spatial_ref_sys元数据表
返回类型为Integer,1-TRUE,0-FALSE
可选参数transaction=TRUE,则整个操作将作为单个事务处理(更快):默认设置为transaction=FALSE(更慢,但更安全)。
未指定可选参数模式,则所有可能的ASPX SRID定义都将插入到spatial_ref_sys表中。
如果指定了模式arg'WGS84'(别名'WGS84_ONLY'),则只会插入与WGS84相关的EPSG SRIDs
如果指定了模式arg'NONE'(别名'EMPTY'),则根本不会插入EPSG SRID
【sqlite3_exec()函数】 一步sqlite3查询执行接口
SQLITE_API int sqlite3_exec(
sqlite3*, /* An open database */
const char *sql, /* SQL to be evaluated */
int (*callback)(void*,int,char**,char**), /* Callback function */
void *, /* 1st argument to callback */
char **errmsg /* Error msg written here */
);
-Sqlite3_exec()接口是围绕sqlite3_prepare_v2()、sqlite3_step()和sqlite3_finalize()的方便包装器,允许应用程序运行SQL的多个语句,而无需使用大量C代码。
-在作为第一个参数传入的[连接数据库]中,运行零个或多个UTF-8编码、分号分隔的sql语句。
-如果第三个参数的回调函数不为NULL,则会为计算后的SQL语句中的每个结果行调用该回调函数,第4个参数将传递到每个回调调用的第1个参数;如果指向sqlite3_exec()的回调指针为NULL,则不会调用回调,并忽略结果行
-如果在计算传入sqlite3_exec()的SQL语句时发生错误,则停止执行当前语句,并跳过后续语句
-如果第5个参数不为NULL,则将任何错误消息写入从[sqlite3_malloc()]获得的内存中,并通过第5个参数传回
-为避免内存泄漏,应用程序应在不再需要错误消息字符串后,对通过sqlite3_exec()的第5个参数返回的错误消息字符串调用sqlite3_free()
-如果sqlite3_exec()的第5个参数不是NULL并且没有发生错误,那么sqlite3_exec()在返回之前将其第5个参数中的指针设置为NULL
-如果sqlite3_exec()回调返回非零,则sqlite3_exec()例程返回SQLITE_ABORT,而不会再次调用回调,也不会运行任何后续SQL语句
-Sqlite3_exec()回调函数的第二个参数是结果中的列数
-Sqlite3_exec()回调的第三个参数是一个指向字符串的指针数组,就像从[sqlite3_column_text()]获得的一样,每列一个。 -如果结果行的元素为NULL,则sqlite3_exec()回调的相应字符串指针为空指针
-Sqlite3_exec()回调的第4个参数是一个指向字符串的指针数组,其中每个条目表示从sqlite3_column_name()获得的相应结果列的名称
-如果sqlite3_exec()的第二个参数是空指针、指向空字符串的指针或仅包含空格和/或SQL注释的指针,则不会计算SQL语句,也不会更改数据库。
**限制:
-确保sqlite3_exec()的第一个参数是有效且打开的[数据库连接]
-在sqlite3_exec()运行时不得关闭由sqlite3_exec()第1个参数指定的[数据库连接]
-在sqlite3_exec()运行时不得修改传入sqlite3_exec()第二个参数的SQL语句文本
ret = sqlite3_get_table(handle, sql, &results, &n_rows, &n_columns, &err_msg);
【不用空间索引查找】 sqlite3_get_table函数
SQLITE_API int sqlite3_get_table(
sqlite3 *db, /* An open database */
const char *zSql, /* SQL to be evaluated */
char ***pazResult, /* Results of the query */
int *pnRow, /* Number of result rows written here */
int *pnColumn, /* Number of result columns written here */
char **pzErrmsg /* Error msg written here */
);
**
**这是为向后兼容而保留的遗留接口。不建议使用。
**定义:【结果表】是由sqlite3_get_table()接口创建的数据结构,记录来自一个或多个查询的完整查询结果。
**表在概念上有许多行和列,但这些数字并不是【结果表】本身的一部分,这些数字独立获得。设N行M列
**【结果表】是指向零端UTF-8字符串的指针数组,有(N+1)*m个元素,前M个指针指向包含【列名称】的以零结尾的字符串,其余条目均指向查询结果。 空值导致空指针。 所有其他值都是由sqlite3_column_text()返回的UTF-8零终止字符串表示形式。
**【结果表】可能包含一个或多个内存分配。
——将【结果表】直接传递给[sqlite3_free()]是不安全的,应使用[sqlite3_free_table()]释放结果表。
假设一个查询结果如下:两列(M==2)和三行(N==3),结果表有8个条目。
** <blockquote><pre>
** Name | Age
** -----------------------
** Alice | 43
** Bob | 28
** Cindy | 21
** </pre></blockquote>
假设【结果表】存储在名为azResult的数组中。 然后azResult持有这个内容:
** <blockquote><pre>
** azResult[0] = "Name";
** azResult[1] = "Age";
** azResult[2] = "Alice";
** azResult[3] = "43";
** azResult[4] = "Bob";
** azResult[5] = "28";
** azResult[6] = "Cindy";
** azResult[7] = "21";
** </pre></blockquote>)^
**Sqlite3_get_table()函数计算第二个参数的SQL语句,并返回结果表到其第三个参数中给出的指针。
**在应用程序完成sqlite3_get_table()的结果后,它必须将结果表指针传递给sqlite3_free_table(),以便释放被malloced的内存。 由于sqlite3_malloc()在sqlite3_get_table()内发生的方式,调用函数不得尝试直接调用sqlite3_free()。 只有[sqlite3_free_table()]能够正确安全地释放内存。
**Sqlite3_get_table()接口作为[sqlite3_exec()]的包装器实现。 Sqlite3_get_table()例程无权访问SQLite的任何内部数据结构。 它只使用这里定义的公共接口。 因此,在内部[sqlite3_exec()]调用之外的包装层中发生的错误不会反映在对[sqlite3_errcode()]或[sqlite3_errmsg()]的后续调用中。
不使用空间索引的按空间范围查询
SELECT tablename FROM fieldname
WHERE X(geom) > 730000 AND X(geom) < 734000
AND Y(geom) > 4810000 AND Y(geom) < 4850000;
使用空间索引的按空间范围查询
SELECT tablename FROM fieldname WHERE ROWID IN
(SELECT pkid FROM idx_ tablename_geom WHERE
xmin > 730000 AND xmax < 734000 AND ymin > 4810000 AND ymax < 4850000);
注意:这两种查询在数据条数少的时候性能区分是不明显的,当时如果数据量比较大(如上数据达到MILLION级)的时候速度回又几分钟变成几秒钟。
demo3运行结果
spatialite库版本:4.3.0-RC1
splite3库版本:3.10.2
执行SQL:SELECT InitSpatialMetadata(1)....成功!
执行SQL:CREATE TABLE test (PK INTEGER NOT NULL PRIMARY KEY)....成功!
执行SQL:SELECT AddGeometryColumn('test', 'geom', 3003, 'POINT', 2)....成功!
执行SQL:SELECT CreateSpatialIndex('test', 'geom')....成功!
now we are going to insert 0.5 million POINTs; wait, please ...
执行SQL:BEGIN....成功!
执行SQL:INSERT INTO test (pk, geom) VALUES (?, ?)....成功!
insert row: 25000 [elapsed time: 2.472]
insert row: 50000 [elapsed time: 5.235]
insert row: 75000 [elapsed time: 8.182]
insert row: 100000 [elapsed time: 10.856]
insert row: 125000 [elapsed time: 13.480]
insert row: 150000 [elapsed time: 16.169]
insert row: 175000 [elapsed time: 18.868]
insert row: 200000 [elapsed time: 21.995]
insert row: 225000 [elapsed time: 24.740]
insert row: 250000 [elapsed time: 27.316]
insert row: 275000 [elapsed time: 29.898]
insert row: 300000 [elapsed time: 32.694]
insert row: 325000 [elapsed time: 35.363]
insert row: 350000 [elapsed time: 38.116]
insert row: 375000 [elapsed time: 40.793]
insert row: 400000 [elapsed time: 43.667]
insert row: 425000 [elapsed time: 46.406]
insert row: 450000 [elapsed time: 49.083]
insert row: 475000 [elapsed time: 51.730]
insert row: 500000 [elapsed time: 54.506]
执行SQL:ANALYZE test....成功!
performing test#0 - not using Spatial Index
Count(*) = 25 [elapsed time: 1.1490]
performing test#1 - not using Spatial Index
Count(*) = 25 [elapsed time: 1.2720]
performing test#2 - not using Spatial Index
Count(*) = 25 [elapsed time: 0.9990]
performing test#0 - using the R*Tree Spatial Index
Count(*) = 25 [elapsed time: 0.0010]
performing test#1 - using the R*Tree Spatial Index
Count(*) = 25 [elapsed time: 0.0000]
performing test#2 - using the R*Tree Spatial Index
Count(*) = 25 [elapsed time: 0.0010]
sample successfully terminated
【demo4】
The main steps in this example are:
- creating a new database
- creating a sample geo-table
- inserting 1 million rows into this table
- performing some spatial queries without Spatial Indexing
- performing the same queries using the Spatial Index
The typical output of this demo is shown below (where test.sqlite does not
exist before the run).
-创建一个新的数据库
-创建示例地理表
-将100万行插入此表
-在没有空间索引的情况下执行一些空间查询
-使用空间索引执行相同的查询