Skip to content

Commit

Permalink
BUG#35690736: Encode date time operator units correctly
Browse files Browse the repository at this point in the history
X DevAPI expressions support a simplified syntax for date time
operators. Creating CRUD statements using this syntax for retrieving
records containing date time columns whose values fall within a given
range is yield an unexpected error, which is caused by a bad protocol
encoding of the corresponding interval units.

This patch introduces the changes required to encode interval units as X
Protocol V_OCTETS, which is the convention established by the X
Plugin.

Change-Id: I2b3bd7517cbd8c1eede0463d65c31e0f623e6141
  • Loading branch information
ruiquelhas committed Aug 23, 2023
1 parent 708d13d commit 12daae7
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 11 deletions.
1 change: 1 addition & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ v8.0.35
=======

- Rows can now be inserted in a table using CRUD with an X DevAPI expression
- Date and time operators are now allowed in X DevAPI expressions

v8.0.33
=======
Expand Down
4 changes: 2 additions & 2 deletions lib/ExprParser/lib/grammar/booleanExpressions/interval.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2022, Oracle and/or its affiliates.
* Copyright (c) 2017, 2023, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2.0, as
Expand Down Expand Up @@ -52,7 +52,7 @@ const PARSER_NAME = 'INTERVAL';
const parser = _ => r => r.INTERVAL_K.then(
Pa.seq(
r.expr.trim(Pa.whitespace),
r.INTERVAL_UNIT.map(value => ({ type: 'literal', value }))
r.INTERVAL_UNIT.map(value => ({ type: 'intervalUnit', value }))
)
);

Expand Down
7 changes: 4 additions & 3 deletions lib/Protocol/Wrappers/Messages/Expr/Expr.js
Original file line number Diff line number Diff line change
Expand Up @@ -381,9 +381,10 @@ const createFromExpression = ({ type, value, placeholders = [] }) => {
proto.setLiteral(scalar.create({ value }).valueOf());
break;
case 'castType':
// The cast type is a special case because, from the MySQL server
// standpoint, it is not a meaningless literal, but a keyword instead,
// and it needs be encoded as an opaque value.
case 'intervalUnit':
// The cast and interval unit types are special cases because, from the
// MySQL server standpoint, they are not a meaningless literal, but
// keywords instead, and they need to be encoded as opaque values.
proto.setType(ExprStub.Expr.Type.LITERAL);
proto.setLiteral(scalar.create({ value, opaque: true }).valueOf());
break;
Expand Down
40 changes: 39 additions & 1 deletion test/functional/default/relational-tables/misc.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2022, Oracle and/or its affiliates.
* Copyright (c) 2020, 2023, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2.0, as
Expand Down Expand Up @@ -817,4 +817,42 @@ describe('relational miscellaneous tests', () => {
});
});
});

context('date and time manipulation', () => {
context('BUG#35690736 date unit encoding', () => {
beforeEach('create table', async () => {
await session.sql(`CREATE TABLE test (
name VARCHAR(3),
createdAt DATE)`)
.execute();
});

beforeEach('add fixtures', async () => {
await session.sql("INSERT INTO test (name, createdAt) values ('foo', CURDATE())")
.execute();
await session.sql("INSERT INTO test (name, createdAt) values ('bar', DATE_ADD(CURDATE(), INTERVAL 3 DAY))")
.execute();
});

it('retrieves the appropriate data within a given temporal range', async () => {
const diff = 3;
const now = new Date();
const then = new Date();
then.setUTCDate(now.getUTCDate() + diff);
then.setUTCHours(0);
then.setUTCMinutes(0);
then.setUTCSeconds(0);
then.setUTCMilliseconds(0);
const want = [['bar', then]];

const res = await schema.getTable('test')
.select()
.where(`createdAt > CURDATE() + INTERVAL ${diff - 1} DAY`)
.execute();
const got = res.fetchAll();

expect(got).to.deep.equal(want);
});
});
});
});
10 changes: 5 additions & 5 deletions test/unit/ExprParser/intervalExpr.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates.
* Copyright (c) 2022, 2023, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2.0, as
Expand Down Expand Up @@ -52,7 +52,7 @@ const assertDateIntervalExpr = (expr, { datetimeFunction, interval, unit }) => {
type: 'literal',
value: interval
}, {
type: 'literal',
type: 'intervalUnit',
value: unit
}]
}
Expand All @@ -76,7 +76,7 @@ const assertTimeIntervalExpr = (expr, { datetimeFunction, interval, unit }) => {
type: 'literal',
value: interval
}, {
type: 'literal',
type: 'intervalUnit',
value: unit
}]
}
Expand Down Expand Up @@ -233,15 +233,15 @@ describe('ExprParser', () => {
type: 'literal',
value: 2
}, {
type: 'literal',
type: 'intervalUnit',
value: 'MONTH'
}]
}
}, {
type: 'literal',
value: 25
}, {
type: 'literal',
type: 'intervalUnit',
value: 'SECOND'
}]
}
Expand Down
13 changes: 13 additions & 0 deletions test/unit/Protocol/Wrappers/Messages/Expr/Expr.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,19 @@ describe('Mysqlx.Expr.Expr wrapper', () => {
// eslint-disable-next-line no-unused-expressions
expect(expr.valueOf().getObject().getFldList()).to.be.an('array').and.be.empty;
});

it('returns an opaque strings for an interval unit', () => {
const unit = 'foo';
const expr = Expr.create({ isLiteral: false, value: { type: 'intervalUnit', value: unit } });

expect(expr.valueOf).to.be.a('function');
expect(expr.valueOf().getType).to.be.a('function');
expect(expr.valueOf().getType()).to.equal(ExprStub.Expr.Type.LITERAL);
expect(expr.valueOf().getLiteral().getType).to.be.a('function');
expect(expr.valueOf().getLiteral().getType()).to.equal(ScalarStub.Type.V_OCTETS);
expect(expr.valueOf().getLiteral().getVOctets().getValue).to.be.a('function');
expect(expr.valueOf().getLiteral().getVOctets().getValue()).to.deep.equal(Buffer.from(unit));
});
});
});

Expand Down

0 comments on commit 12daae7

Please sign in to comment.