Skip to content

Commit 3b1304c

Browse files
authored
Merge pull request OSGeo#9798 from rouault/OGRCloneArrowArray_tss
OGRCloneArrowArray(): add missing support for 'tss:' Arrow type
2 parents b8aa812 + 8546004 commit 3b1304c

File tree

2 files changed

+70
-52
lines changed

2 files changed

+70
-52
lines changed

autotest/ogr/ogr_arrow.py

+18
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,24 @@ def test_ogr_arrow_test_ogrsf_test_feather():
184184
assert "ERROR" not in ret
185185

186186

187+
###############################################################################
188+
# Run test_ogrsf on a Feather file
189+
190+
191+
def test_ogr_arrow_test_ogrsf_test_feather_all_types():
192+
import test_cli_utilities
193+
194+
if test_cli_utilities.get_test_ogrsf_path() is None:
195+
pytest.skip()
196+
197+
ret = gdaltest.runexternal(
198+
test_cli_utilities.get_test_ogrsf_path() + " -ro data/arrow/test.feather"
199+
)
200+
201+
assert "INFO" in ret
202+
assert "ERROR" not in ret
203+
204+
187205
###############################################################################
188206
# Run test_ogrsf on a IPC stream file
189207

ogr/ogrsf_frmts/generic/ogrlayerarrow.cpp

+52-52
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,43 @@ static inline bool IsLargeBinary(const char *format)
202202
return format[0] == ARROW_LETTER_LARGE_BINARY && format[1] == 0;
203203
}
204204

205+
static inline bool IsTimestampInternal(const char *format, char chType)
206+
{
207+
return format[0] == 't' && format[1] == 's' && format[2] == chType &&
208+
format[3] == ':';
209+
}
210+
211+
static inline bool IsTimestampSeconds(const char *format)
212+
{
213+
return IsTimestampInternal(format, 's');
214+
}
215+
216+
static inline bool IsTimestampMilliseconds(const char *format)
217+
{
218+
return IsTimestampInternal(format, 'm');
219+
}
220+
221+
static inline bool IsTimestampMicroseconds(const char *format)
222+
{
223+
return IsTimestampInternal(format, 'u');
224+
}
225+
226+
static inline bool IsTimestampNanoseconds(const char *format)
227+
{
228+
return IsTimestampInternal(format, 'n');
229+
}
230+
231+
static inline bool IsTimestamp(const char *format)
232+
{
233+
return IsTimestampSeconds(format) || IsTimestampMilliseconds(format) ||
234+
IsTimestampMicroseconds(format) || IsTimestampNanoseconds(format);
235+
}
236+
237+
static inline const char *GetTimestampTimezone(const char *format)
238+
{
239+
return IsTimestamp(format) ? format + strlen("tm?:") : "";
240+
}
241+
205242
/************************************************************************/
206243
/* TestBit() */
207244
/************************************************************************/
@@ -2820,20 +2857,9 @@ static bool IsHandledSchema(bool bTopLevel, const struct ArrowSchema *schema,
28202857
return true;
28212858
}
28222859

2823-
const char *const apszHandledFormatsPrefix[] = {
2824-
"w:", // fixed width binary
2825-
"tss:", // timestamp [seconds] with timezone
2826-
"tsm:", // timestamp [milliseconds] with timezone
2827-
"tsu:", // timestamp [microseconds] with timezone
2828-
"tsn:", // timestamp [nanoseconds] with timezone
2829-
};
2830-
2831-
for (const char *pszHandledFormat : apszHandledFormatsPrefix)
2860+
if (IsFixedWidthBinary(format) || IsTimestamp(format))
28322861
{
2833-
if (strncmp(format, pszHandledFormat, strlen(pszHandledFormat)) == 0)
2834-
{
2835-
return true;
2836-
}
2862+
return true;
28372863
}
28382864

28392865
CPLDebug("OGR", "Field %s has unhandled format '%s'",
@@ -4303,37 +4329,30 @@ static bool SetFieldForOtherFormats(OGRFeature &oFeature,
43034329
static_cast<GIntBig>(static_cast<const int64_t *>(
43044330
array->buffers[1])[nOffsettedIndex]));
43054331
}
4306-
else if (format[0] == 't' && format[1] == 's' && format[2] == 's' &&
4307-
format[3] == ':') // STARTS_WITH(format, "tss:")
4332+
else if (IsTimestampSeconds(format))
43084333
{
4309-
// timestamp [seconds] with timezone
43104334
ArrowTimestampToOGRDateTime(
43114335
static_cast<const int64_t *>(array->buffers[1])[nOffsettedIndex], 1,
4312-
format + strlen("tss:"), oFeature, iOGRFieldIndex);
4336+
GetTimestampTimezone(format), oFeature, iOGRFieldIndex);
43134337
}
4314-
else if (format[0] == 't' && format[1] == 's' && format[2] == 'm' &&
4315-
format[3] == ':') // STARTS_WITH(format, "tsm:"))
4338+
else if (IsTimestampMilliseconds(format))
43164339
{
4317-
// timestamp [milliseconds] with timezone
43184340
ArrowTimestampToOGRDateTime(
43194341
static_cast<const int64_t *>(array->buffers[1])[nOffsettedIndex],
4320-
1000, format + strlen("tsm:"), oFeature, iOGRFieldIndex);
4342+
1000, GetTimestampTimezone(format), oFeature, iOGRFieldIndex);
43214343
}
4322-
else if (format[0] == 't' && format[1] == 's' && format[2] == 'u' &&
4323-
format[3] == ':') // STARTS_WITH(format, "tsu:"))
4344+
else if (IsTimestampMicroseconds(format))
43244345
{
4325-
// timestamp [microseconds] with timezone
43264346
ArrowTimestampToOGRDateTime(
43274347
static_cast<const int64_t *>(array->buffers[1])[nOffsettedIndex],
4328-
1000 * 1000, format + strlen("tsu:"), oFeature, iOGRFieldIndex);
4348+
1000 * 1000, GetTimestampTimezone(format), oFeature,
4349+
iOGRFieldIndex);
43294350
}
4330-
else if (format[0] == 't' && format[1] == 's' && format[2] == 'n' &&
4331-
format[3] == ':') // STARTS_WITH(format, "tsn:"))
4351+
else if (IsTimestampNanoseconds(format))
43324352
{
4333-
// timestamp [nanoseconds] with timezone
43344353
ArrowTimestampToOGRDateTime(
43354354
static_cast<const int64_t *>(array->buffers[1])[nOffsettedIndex],
4336-
1000 * 1000 * 1000, format + strlen("tsn:"), oFeature,
4355+
1000 * 1000 * 1000, GetTimestampTimezone(format), oFeature,
43374356
iOGRFieldIndex);
43384357
}
43394358
else if (IsFixedSizeList(format))
@@ -5227,9 +5246,7 @@ static bool OGRCloneArrowArray(const struct ArrowSchema *schema,
52275246
}
52285247
else if (IsUInt64(format) || IsInt64(format) || IsFloat64(format) ||
52295248
strcmp(format, "tdm") == 0 || strcmp(format, "ttu") == 0 ||
5230-
strcmp(format, "ttn") == 0 || strcmp(format, "tss") == 0 ||
5231-
STARTS_WITH(format, "tsm:") ||
5232-
STARTS_WITH(format, "tsu:") || STARTS_WITH(format, "tsn:"))
5249+
strcmp(format, "ttn") == 0 || IsTimestamp(format))
52335250
{
52345251
nEltSize = sizeof(uint64_t);
52355252
}
@@ -5692,21 +5709,9 @@ static bool IsArrowSchemaSupportedInternal(const struct ArrowSchema *schema,
56925709
}
56935710
}
56945711

5695-
if (IsFixedWidthBinary(format))
5712+
if (IsFixedWidthBinary(format) || IsTimestamp(format))
56965713
return true;
56975714

5698-
const char *const apszTimestamps[] = {
5699-
"tss:", // timestamp[s]
5700-
"tsm:", // timestamp[ms]
5701-
"tsu:", // timestamp[us]
5702-
"tsn:" // timestamp[ns]
5703-
};
5704-
for (const char *pszSupported : apszTimestamps)
5705-
{
5706-
if (STARTS_WITH(format, pszSupported))
5707-
return true;
5708-
}
5709-
57105715
AppendError("Type '" + std::string(format) + "' for field " +
57115716
osFieldPrefix + fieldName + " is not supported.");
57125717
return false;
@@ -5991,10 +5996,7 @@ bool OGRLayer::CreateFieldFromArrowSchemaInternal(
59915996
return AddField(OFTString, OFSTJSON, 0, 0);
59925997
}
59935998

5994-
if (STARTS_WITH(format, "tss:") || // timestamp[s]
5995-
STARTS_WITH(format, "tsm:") || // timestamp[ms]
5996-
STARTS_WITH(format, "tsu:") || // timestamp[us]
5997-
STARTS_WITH(format, "tsn:")) // timestamp[ns]
5999+
if (IsTimestamp(format))
59986000
{
59996001
return AddField(OFTDateTime, OFSTNone, 0, 0);
60006002
}
@@ -6401,9 +6403,7 @@ static bool BuildOGRFieldInfo(
64016403
}
64026404
}
64036405

6404-
if (!bTypeOK &&
6405-
(STARTS_WITH(format, "tss:") || STARTS_WITH(format, "tsm:") ||
6406-
STARTS_WITH(format, "tsu:") || STARTS_WITH(format, "tsn:")))
6406+
if (!bTypeOK && IsTimestamp(format))
64076407
{
64086408
sInfo.eNominalFieldType = OFTDateTime;
64096409
if (eOGRType == sInfo.eNominalFieldType)

0 commit comments

Comments
 (0)