Skip to content

Commit 55ccc7a

Browse files
committed
Fix #8890 - WITH TIME ZONE types store non-zero garbage for padding instead of 0x00
1 parent b2c9cfc commit 55ccc7a

2 files changed

Lines changed: 92 additions & 1 deletion

File tree

src/common/cvt.cpp

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737

3838
#include "firebird.h"
3939
#include <cmath>
40+
#include <cstddef>
4041
#include <stdio.h>
4142
#include <string.h>
4243
#include <stdlib.h>
@@ -293,6 +294,32 @@ static void timeStampToUtc(ISC_TIMESTAMP_TZ& timestampTZ, USHORT sessionTimeZone
293294
}
294295

295296

297+
static void zeroTzPadding(dsc* to)
298+
{
299+
if (!to || !to->dsc_address)
300+
return;
301+
302+
size_t logicalLength = 0;
303+
304+
switch (to->dsc_dtype)
305+
{
306+
case dtype_sql_time_tz:
307+
logicalLength = offsetof(ISC_TIME_TZ, time_zone) + sizeof(ISC_USHORT);
308+
break;
309+
310+
case dtype_timestamp_tz:
311+
logicalLength = offsetof(ISC_TIMESTAMP_TZ, time_zone) + sizeof(ISC_USHORT);
312+
break;
313+
314+
default:
315+
return;
316+
}
317+
318+
if (to->dsc_length > logicalLength)
319+
memset(to->dsc_address + logicalLength, 0, to->dsc_length - logicalLength);
320+
}
321+
322+
296323
static void float_to_text(const dsc* from, dsc* to, Callbacks* cb)
297324
{
298325
/**************************************
@@ -1680,6 +1707,7 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
16801707
if (length) {
16811708
memcpy(p, q, length);
16821709
}
1710+
zeroTzPadding(to);
16831711
return;
16841712
}
16851713

@@ -1770,31 +1798,37 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
17701798
CVT_string_to_datetime(from, &date, NULL, expect_timestamp_tz, true, cb);
17711799
*((ISC_TIMESTAMP_TZ*) to->dsc_address) = date;
17721800
}
1801+
zeroTzPadding(to);
17731802
return;
17741803

17751804
case dtype_sql_time:
17761805
*(ISC_TIMESTAMP_TZ*) to->dsc_address =
17771806
TimeZoneUtil::timeToTimeStampTz(*(ISC_TIME*) from->dsc_address, cb);
1807+
zeroTzPadding(to);
17781808
return;
17791809

17801810
case dtype_ex_time_tz:
17811811
case dtype_sql_time_tz:
17821812
*((ISC_TIMESTAMP_TZ*) to->dsc_address) =
17831813
TimeZoneUtil::timeTzToTimeStampTz(*(ISC_TIME_TZ*) from->dsc_address, cb);
1814+
zeroTzPadding(to);
17841815
return;
17851816

17861817
case dtype_ex_timestamp_tz:
17871818
*((ISC_TIMESTAMP_TZ*) to->dsc_address) = *((ISC_TIMESTAMP_TZ*) from->dsc_address);
1819+
zeroTzPadding(to);
17881820
return;
17891821

17901822
case dtype_sql_date:
17911823
*(ISC_TIMESTAMP_TZ*) to->dsc_address =
17921824
TimeZoneUtil::dateToTimeStampTz(*(GDS_DATE*) from->dsc_address, cb);
1825+
zeroTzPadding(to);
17931826
return;
17941827

17951828
case dtype_timestamp:
17961829
*(ISC_TIMESTAMP_TZ*) to->dsc_address =
17971830
TimeZoneUtil::timeStampToTimeStampTz(*(ISC_TIMESTAMP*) from->dsc_address, cb);
1831+
zeroTzPadding(to);
17981832
return;
17991833

18001834
default:
@@ -1878,26 +1912,31 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
18781912
((ISC_TIME_TZ*) to->dsc_address)->utc_time = date.utc_timestamp.timestamp_time;
18791913
((ISC_TIME_TZ*) to->dsc_address)->time_zone = date.time_zone;
18801914
}
1915+
zeroTzPadding(to);
18811916
return;
18821917

18831918
case dtype_sql_time:
18841919
*(ISC_TIME_TZ*) to->dsc_address = TimeZoneUtil::timeToTimeTz(*(ISC_TIME*) from->dsc_address, cb);
1920+
zeroTzPadding(to);
18851921
return;
18861922

18871923
case dtype_timestamp:
18881924
*(ISC_TIME_TZ*) to->dsc_address =
18891925
TimeZoneUtil::timeStampToTimeTz(*(ISC_TIMESTAMP*) from->dsc_address, cb);
1926+
zeroTzPadding(to);
18901927
return;
18911928

18921929
case dtype_timestamp_tz:
18931930
case dtype_ex_timestamp_tz:
18941931
*(ISC_TIME_TZ*) to->dsc_address =
18951932
TimeZoneUtil::timeStampTzToTimeTz(*(ISC_TIMESTAMP_TZ*) from->dsc_address);
1933+
zeroTzPadding(to);
18961934
return;
18971935

18981936
case dtype_ex_time_tz:
18991937
*(ISC_TIME_TZ*) to->dsc_address = *(ISC_TIME_TZ*) from->dsc_address;
1900-
return;
1938+
zeroTzPadding(to);
1939+
return;
19011940

19021941
default:
19031942
CVT_conversion_error(from, cb->err);

src/common/tests/CvtTest.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
#include "boost/test/unit_test.hpp"
2+
#include <cstddef>
3+
#include <cstring>
24
#include "../common/tests/CvtTestUtils.h"
35

46
#include "../common/StatusArg.h"
57
#include "../common/CvtFormat.h"
8+
#include "../jrd/intl.h"
69

710
using namespace Firebird;
811
using namespace Jrd;
@@ -218,6 +221,55 @@ BOOST_AUTO_TEST_CASE(CVTDatetimeToFormatStringTest_TIME_TZ)
218221
testCVTDatetimeToFormatString(createTimeTZ(0, 0, 0, -160), "TZH MI TZM", "-02 00 -40", cb);
219222
}
220223

224+
BOOST_AUTO_TEST_CASE(CVTMoveCommonZeroPadding_TZ)
225+
{
226+
const char* tsText = "2026-02-08 14:32 +00:00";
227+
UCHAR tsBuffer[sizeof(ISC_TIMESTAMP_TZ)];
228+
memset(tsBuffer, 0xA5, sizeof(tsBuffer));
229+
230+
dsc fromTs;
231+
fromTs.dsc_dtype = dtype_text;
232+
fromTs.dsc_length = strlen(tsText);
233+
fromTs.dsc_scale = 0;
234+
fromTs.dsc_address = (UCHAR*) tsText;
235+
fromTs.dsc_ttype() = ttype_ascii;
236+
237+
dsc toTs;
238+
toTs.dsc_dtype = dtype_timestamp_tz;
239+
toTs.dsc_length = sizeof(tsBuffer);
240+
toTs.dsc_scale = 0;
241+
toTs.dsc_address = tsBuffer;
242+
243+
CVT_move_common(&fromTs, &toTs, 0, &cb);
244+
245+
const size_t tsLogical = offsetof(ISC_TIMESTAMP_TZ, time_zone) + sizeof(ISC_USHORT);
246+
for (size_t i = tsLogical; i < sizeof(tsBuffer); ++i)
247+
BOOST_TEST(tsBuffer[i] == 0);
248+
249+
const char* timeText = "14:32 +00:00";
250+
UCHAR timeBuffer[sizeof(ISC_TIME_TZ)];
251+
memset(timeBuffer, 0xA5, sizeof(timeBuffer));
252+
253+
dsc fromTime;
254+
fromTime.dsc_dtype = dtype_text;
255+
fromTime.dsc_length = strlen(timeText);
256+
fromTime.dsc_scale = 0;
257+
fromTime.dsc_address = (UCHAR*) timeText;
258+
fromTime.dsc_ttype() = ttype_ascii;
259+
260+
dsc toTime;
261+
toTime.dsc_dtype = dtype_sql_time_tz;
262+
toTime.dsc_length = sizeof(timeBuffer);
263+
toTime.dsc_scale = 0;
264+
toTime.dsc_address = timeBuffer;
265+
266+
CVT_move_common(&fromTime, &toTime, 0, &cb);
267+
268+
const size_t timeLogical = offsetof(ISC_TIME_TZ, time_zone) + sizeof(ISC_USHORT);
269+
for (size_t i = timeLogical; i < sizeof(timeBuffer); ++i)
270+
BOOST_TEST(timeBuffer[i] == 0);
271+
}
272+
221273
BOOST_AUTO_TEST_CASE(CVTDatetimeToFormatStringTest_TIMESTAMP_TZ)
222274
{
223275
ISC_TIMESTAMP_TZ timestampTZ = createTimeStampTZ(1982, 4, 21, 1, 34, 15, 0, 500);

0 commit comments

Comments
 (0)