RFC 31:OGR 64位整数字段和fid

作者:弗兰克·温特丹,甚至鲁奥

联系方式:warmerdam@pobox.com,甚至是spatialys.com上的dot rouault

状态:采用,在GDAL 2.0中实现

总结

此RFC解决了升级OGR以支持64位整数字段和功能ID的步骤。许多特性数据格式支持宽整数,而无法通过OGR转换这些特性会导致越来越多的问题。

64位FID、特征索引和特征计数

功能id在内部将被处理为“GIntBig”类型而不是“long”。这将包括OGRFeature的nFID字段。OGRFeature上现有的GetFID()和SetFID()方法使用类型long,并改为返回(分别接受)GIntBig。更改GetFID()的返回类型将需要应用程序代码仔细调整以避免潜在的问题(例如,如果在类似printf的表达式中使用GetFID())。SetFID()更改应该主要是透明的。因此OGRFeature类中的更改是:

GIntBig  GetFID();
OGRErr   SetFID(GIntBig nFID );

在C API级别:

GIntBig CPL_DLL OGR_F_GetFID( OGRFeatureH );
OGRErr CPL_DLL OGR_F_SetFID( OGRFeatureH, GIntBig );

请注意,使用“long”的旧接口在64位操作系统上已经是64位的(不包括Windows目标编译器,即使在64位版本上,long也是32位的),因此对继续在64位操作系统上使用这些接口的应用程序没有什么危害。

如果一个层能够以相对便宜的方式发现它拥有64位FID的特性,那么它应该将OLMDu FID64元数据项公布为“YES”,这样ogr2ogr就可以将FID64创建选项传递给支持它的驱动程序。

OGRLayer类允许基于FID的多个操作。这些签名将是 改变了的 接受吉特比格而不是长。理论上,这不需要对应用程序代码进行任何更改,因为long可以无损地转换为GIntBig。但是,所有现有的OGR驱动程序都需要更改,包括私有驱动程序。这也将导致C ABI的向后不兼容更改。我们希望GetFeatureCount()能够返回超过20亿条记录(当前返回32位整数),从而返回GIntBig。与GetFID()类似,这种返回类型的更改需要在应用程序代码中小心。

所以在OGLeLtC++类级别:

virtual OGRFeature *GetFeature( GIntBig nFID );
virtual OGRErr      DeleteFeature( GIntBig nFID );
virtual OGRErr      SetNextByIndex( GIntBig nIndex );
virtual GIntBig     GetFeatureCount( int bForce = TRUE );

在C API级别:

OGRFeatureH CPL_DLL OGR_L_GetFeature( OGRLayerH, GIntBig );
OGRErr CPL_DLL OGR_L_DeleteFeature( OGRLayerH, GIntBig );
OGRErr CPL_DLL OGR_L_SetNextByIndex( OGRLayerH, GIntBig );
GIntBig CPL_DLL OGR_L_GetFeatureCount( OGRLayerH, int );

64位字段

将为64位整数引入新的字段类型:

OFTInteger64 = 12
OFTInteger64List = 13

奥格菲尔德工会将扩大到包括:

GIntBig     Integer64;
struct {
    int nCount;
    GIntBig *paList;
} Integer64List;

OGRFeature类将使用以下新方法进行扩展:

GIntBig             GetFieldAsInteger64( int i );
GIntBig             GetFieldAsInteger64( const char *pszFName );
const int          *GetFieldAsInteger64List( const char *pszFName,
                                           int *pnCount );
const int          *GetFieldAsInteger64List( int i, int *pnCount );

void                SetField( int i, GIntBig nValue );
void                SetField( int i, int nCount, const GIntBig * panValues );
void                SetField( const char *pszFName, GIntBig nValue )
void                SetField( const char *pszFName, int nCount,
                              const GIntBig * panValues )

在C级,添加了以下功能:

GIntBig CPL_DLL OGR_F_GetFieldAsInteger64( OGRFeatureH, int );
const GIntBig CPL_DLL *OGR_F_GetFieldAsInteger64List( OGRFeatureH, int, int * );
void   CPL_DLL OGR_F_SetFieldInteger64( OGRFeatureH, int, GIntBig );
void   CPL_DLL OGR_F_SetFieldInteger64List( OGRFeatureH, int, int, const GIntBig * );

此外,新的接口将在内部支持设置/获取整型字段,整型字段方法将支持获取/设置64位整型字段,以便在方便的情况下对这两种字段类型都使用一个case(GetFieldAsInteger64List()除外,它只能对Integer64List字段进行操作)

添加一个GDAL_DMD_CREATIONFIELDDATATYPES=“DMD_CREATIONFIELDDATATYPES”驱动程序元数据项,以便驱动程序能够声明它们在创建时支持的字段类型。例如“Integer Integer64 Real String Date Time IntegerList Integer64List RealList StringList Binary”。常用的驱动程序将被更新以声明它。

OGR-SQL

添加了SWQ_INTEGER64内部类型,以便能够映射/来自oftinger64字段。swq_expr_node类的int_value成员从int扩展到GIntBig(因此swq_INTEGER和swq_INTEGER64都引用该成员)。

Python/Java/C#/perl更改

已完成以下更改:

  • GetFID(),GetFeatureCount()已更改为返回64位整数

  • SetFID()、GetFeature()、DeleteFeature()、SetNextByIndex()已更改为接受64位整数作为参数

  • 已添加GetFieldAsInteger64()和SetFieldInteger64()

  • 在Python中,GetField(),SetField()可以接受/返回64位值

  • 已添加GetFieldAsInteger64List()和SetFieldInteger64List()(仅限Python,因为缺少其他语言的相关类型映射,但可能会完成)

GetFID()和GetFeatureCount()返回类型的更改可能会在某些语言(Java是、Python不相关、Perl/C#?)的编译时引起警告。对现有方法的所有更改都是对Java字节码的ABI更改。

公用事业

更新了ogr2ogr和ogrinfo以支持新的64位接口。

A new option is added to ogr2ogr : -mapFieldType. Can be used like this -mapFieldType Integer64=Integer,Date=String to mean that Integer64 field in the source layer should be created as Integer, and Date as String. ogr2ogr will also warn if attempting to create a field in an output driver that advertises a GDAL_DMD_CREATIONFIELDDATATYPES metadata item that does not mention the required field type. For Integer64 fields, if it is not advertized in GDAL_DMD_CREATIONFIELDDATATYPES metadata item or GDAL_DMD_CREATIONFIELDDATATYPES is missing, conversion to Real is done by default with a warning. ogr2ogr will also query the source layer to check if the OLMD_FID64 metadata item is declared and if the output driver has the FID64 layer creation option. In which case it will set it.

文档

新的/修改过的API被记录在案。有新选项/行为的驾驶员更新记录在案。MIGRATION_GUIDE.TXT扩展了与此RFC相关的部分。更新了OGR API。

文件格式

适当时,现有的OGR驱动程序已经更新,以支持新的/更新的接口。特别是,已经努力更新了一些数据库驱动程序,以支持64位整数列用作功能id,尽管它们在创建新图层时并不总是默认地将FID列创建为64位,因为这可能会给其他应用程序带来问题。

除了因界面变化引起的机械变化外,详细的变化列表如下:

  • Shapefile:OFTInteger字段在默认情况下是以9个字符的宽度创建的,因此可以明确地读作OFTInteger(如果指定需要10或11个字符的整数)。该字段是动态扩展的,就像托管的(因为有几个版本)。默认情况下,OFTInteger64字段的宽度为18位,因此可以像OFTInteger64一样清晰地读取,如果需要,可以扩展到19或20。宽度介于10和18之间的整数字段将从Integer64开始读取。在上面他们将被视为真正的。在以前的GDAL版本中,整数字段是用默认值10创建的,因此现在将作为OFTInteger64读取。可以指定一个open选项DETECTu TYPE=YES,以便OGR对DBF文件进行完整扫描,以查看大小为10或11的整数字段是否包含32位或64位值,并相应地调整类型(对于大小为19或20的整数字段也是如此,如果64位整数溢出,则选择OFTReal)

  • PG:更新为读取并创建oftinger64作为INT8,oftinger64list作为bigint[]。支持64位fid。默认情况下,在创建图层时,会将FID字段创建为串行(32位整数)以避免兼容性问题。可以传递FID64=YES创建选项,将其创建为BIGSERIAL。如果需要,驱动程序将动态改变模式,将32位整数FID字段扩展到64位。修改GetFeatureCount()以返回64位值。OLMD_FID64=“YES”在FID列为64位时立即播发。

  • PGDump:读/写支持Integer64、Integer64List和64位FID。FID64=YES创建选项可用。

  • GeoJSON:读/写支持Integer64、Integer64List和64位FID。只有在需要时才会报告64位变量,否则将使用oftinger/oftingerlist。OLMD_FID64=“是”如有需要,请在广告中注明

  • CSV:Integer64支持读/写,包括字段类型的自动检测功能。

  • GPKG:读/写支持整数64位和64位FID。与GeoPackage规范一致,“INT”或“INTEGER”列被视为64位,而“MEDIUMINT”被视为32位。OLMD_FID64=“YES”在MAX(fid_列)为64位时立即播发。修改GetFeatureCount()以返回64位值。

  • SQLite:读/写支持整数64位和64位FID。写入时,Integer64被创建为“BIGINT”,读取时,BIGINT或INT8被视为Integer64。但是,其他工具生成的数据库可能是用“INTEGER”创建的,并保存64位值,在这种情况下,OGR将无法检测到它。然后可以传递OGR_PROMOTE_TO_INTEGER64=YES配置选项来解决该问题。OLMD_FID64=“YES”在MAX(fid_列)为64位时立即播发。修改GetFeatureCount()以返回64位值。

  • MySQL:读/写支持整数64位和64位FID。与PG类似,默认情况下FID列创建为32位,除非指定了FID64=YES创建选项。OLMD_FID64=“YES”在FID列为64位时立即播发。修改GetFeatureCount()以返回64位值。

  • OCI:读/写支持64位和64位FID整数。在读取时检测Integer/Integer64很棘手,因为只有一个具有字段宽度的数字SQL类型。假设如果宽度<=9或是未指定的值(38),则它是一个整数。在创建时,OGR将oftinger64的宽度设置为20,因此没有小数部分且宽度为20的数字将被视为整数64。

  • MEM:读/写支持整数64位和64位FID。修改GetFeatureCount()以返回64位值。

  • VRT:读/写支持Integer64、Integer64List和64位FID。修改GetFeatureCount()以返回64位值。

  • JML:Integer64支持创建(创建为“OBJECT”)。读取时,以字符串形式返回

  • GML:读/写支持Integer64、Integer64List和64位FID。修改GetFeatureCount()以返回64位值。

  • WFS:读/写支持Integer64、Integer64List和64位FID。修改GetFeatureCount()以返回64位值。

  • CartoDB: Integer64 supported on creation. On read returned as Real (CartoDB only advertises a 'Number' type). GetFeatureCount() modified to return 64 bit values.

  • XLSX:读/写支持整数64。

  • ODS:读/写支持整数64。

  • mssqlspace:GetFeatureCount()已修改以返回64位值。虽然可能实现,但未实现Integer64支持。

  • OSM:即使在sizeof(long)时,FID也总是被设置的!=8个

  • LIBKML:KML'uint'广告为Integer64。

  • MITAB:改变无缝表的FID生成方式,通过使用全64位宽度的IDs,使其更健壮,并接受由任意数量的特性组成的任意数量的索引表

测试套件

扩展测试套件以测试新功能:

  • 核心SetField/GetField方法

  • 更新的驱动程序:Shapefile、PG、GeoJSON、CSV、GPKG、SQLite、MySQL、VRT、GML、XLSX、ODS、MITAB

  • OGR-SQL

  • 选项-ogr2ogr的mapFieldType

兼容性问题

驱动程序代码更改

  • 实现SetNextByIndex()、DeleteFeature()、GetFeature()和GetFeatureCount()的所有驱动程序都需要更改其原型并进行适当的更改。

  • 如果没有其他可用的(并且bApproxOK为TRUE),则支持CreateField()的驱动程序可能应该扩展为支持整数/real/string字段。如果不注意Integer64支持,ogr2ogr将把Integer64转换为Real

  • 通过调试语句、printf或使用类似sprintfs的语句对FID进行格式化输出的驱动程序已经更新为使用CPLu FRMTu GIB对FID进行格式化。未能进行这些更改可能会导致代码崩溃。由于在CPL函数中使用GCC注解来公布printf()格式语法,我们有理由相信已经对树内驱动程序进行了所需的更改(除了一些专有驱动程序,如SDE、IDB、ingre、ArcObjects,这些驱动程序无法编译和检查)。GetFeatureCount()也是如此

应用程序代码

  • 可能需要更新应用程序代码,以便使用GIntBig作为fid和功能计数,以避免有关下推的警告。

  • 使用类似printf的工具格式化fid或特性计数的应用程序代码也可能需要显式更改为downcast或使用CPL FRMT GIB。

  • 应用程序代码可能需要添加Integer64处理以利用宽字段。

行为改变

  • 以前被shapefile驱动程序视为“real”或integer的宽整型字段现在将被视为Integer64,这可能对某些应用程序不起作用,转换为其他格式可能会失败。

实施

实施将由甚至鲁奥完成 (Spatialys _),并由 LINZ (Land Information New Zealand) .

建议的实现位于 https://github.com/rouault/gdal2/tree/rfc31_64bit 储存库。

更改列表: https://github.com/rouault/gdal2/compare/rfc31_64bit

投票历史

+1名来自JukkaR,DanielM,TamasS,HowardB和Ever