I am working on a database for our project. Our back-end guys were able to insert ‘00.00.0000’ date into Oracle from Java (column data type is DATE). I guess it’s something to do with raw values as in this example:
alter session set nls_date_format='fmdd.month.yyyy hh24:mi:ss';
declare
d date;
begin
dbms_stats.convert_raw_value(hextoraw('7764057f7f77aa'), d);
dbms_output.put_line(d);
end;
/
127.may.1900 126:118:87
How can I prevent this?
Advertisement
Answer
You can use a function to check whether dates are valid by converting them to a string and back and add this to a CHECK constraint to your date columns to ensure all dates are valid.
However, you should not need to do this as you should be mandating that arbitrary code is not executed on your systems and all the application code should include input validation so that only sanitized values are inserted into the database.
An example:
Oracle Setup:
CREATE TABLE Dates (
d DATE
);
CREATE FUNCTION isValidDate( dt IN DATE ) RETURN NUMBER
IS
d DATE;
BEGIN
d := TO_DATE( TO_CHAR( dt, 'fxYYYY-MM-DD HH24:MI:SS' ), 'fxYYYY-MM-DD HH24:MI:SS' );
RETURN 1;
EXCEPTION
WHEN OTHERS THEN
RETURN 0;
END;
Insert Dates:
declare
d DATE;
FUNCTION createUnvalidatedDate(
centuries INT := 0,
years INT := 0,
months INT := 0,
days INT := 0,
hours INT := 0,
minutes INT := 0,
seconds INT := 0
) RETURN DATE
IS
dt DATE;
hex_string CHAR(14);
BEGIN
hex_string := LPAD( TO_CHAR( centuries + 100, 'fmXX' ), 2, '0' )
|| LPAD( TO_CHAR( years + 100, 'fmXX' ), 2, '0' )
|| LPAD( TO_CHAR( months, 'fmXX' ), 2, '0' )
|| LPAD( TO_CHAR( days, 'fmXX' ), 2, '0' )
|| LPAD( TO_CHAR( hours + 1, 'fmXX' ), 2, '0' )
|| LPAD( TO_CHAR( minutes + 1, 'fmXX' ), 2, '0' )
|| LPAD( TO_CHAR( seconds + 1, 'fmXX' ), 2, '0' );
dbms_stats.convert_raw_value(hextoraw(hex_string), dt);
RETURN dt;
END;
begin
d := createUnvalidatedDate( 19, 0, 5, 127, 126, 118, 87 );
INSERT INTO Dates ( d ) VALUES ( d );
d := createUnvalidatedDate( 0, 0, 0, 0, 0, 0, 0 );
INSERT INTO Dates ( d ) VALUES ( d );
d := createUnvalidatedDate( 20, 19, 6, 24, 10, 28, 30 );
INSERT INTO Dates ( d ) VALUES ( d );
end;
/
Check Validity:
SELECT d, isValidDate( d ) AS valid FROM Dates;
Outputs:
D | VALID :-------------------- | ----: 1900-5-127T126:118:87 | 0 0-0-0T0:0:0 | 0 2019-6-24T10:28:30 | 1
Which shows that the first two values are invalid and the last one is a valid date.
db<>fiddle here