oracle / node-oracledb

Oracle Database driver for Node.js maintained by Oracle Corp.
http://oracle.github.io/node-oracledb/
Other
2.25k stars 1.07k forks source link

ISO 8601 Date Types #1455

Open bchr02 opened 2 years ago

bchr02 commented 2 years ago

Dates are serialized as strings in ISO 8601 format when being parsed from JSON. E.g when using express.json(), or when using JSON.parse(). To INSERT into DATE columns, one could use a reviver function as mentioned here or keep the IN binds as oracledb.STRING types and wrap the VALUES in TO_UTC_TIMESTAMP_TZ(:1) but it would be nice if within bindDefs there could be a special type for dates stored as strings in ISO 8601 format that are meant for DATETIME or DATE columns. I currently do not see anything documented that allows for this behavior (explicitly or implicitly), but I believe it would be extremely beneficial. Also, the examples/date.js would benefit by providing an example using the TO_UTC_TIMESTAMP_TZ function with the IN binds as oracledb.STRING.

cjbj commented 2 years ago

@bchr02 possibly @anthony-tuininga's favourite 'input type handler' concept?

I'm happy to take PRs on the examples and doc (or code!)

bchr02 commented 2 years ago

@cjbj Interesting concept indeed. Is this possible in Node.js too? Is it documented anywhere?

I was thinking if a bind in of the type date is specified and the provided value is a string that this should trigger an implicit conversion, and or explicitly having a stringdate type built into node-oracledb.

If I have some spare time I will try to send over a PR.

cjbj commented 2 years ago

@bchr02 there is no equivalent to the Python input type handler in node-oracledb.

sla100 commented 2 years ago

I tested such minor changes and it works: src/njsVariable.c

bool njsVariable_initForQuery(njsVariable *vars, uint32_t numVars,
        dpiStmt *handle, njsBaton *baton)
{
              case DPI_ORACLE_TYPE_TIMESTAMP_LTZ:
                if (vars[i].varTypeNum != DPI_ORACLE_TYPE_VARCHAR) {
                    vars[i].varTypeNum = DPI_ORACLE_TYPE_TIMESTAMP_LTZ;
                    // vars[i].nativeTypeNum = DPI_NATIVE_TYPE_DOUBLE;
                    vars[i].nativeTypeNum = DPI_NATIVE_TYPE_TIMESTAMP;
                }
                break;
}

bool njsVariable_getScalarValue(njsVariable *var, njsConnection *conn,
        njsVariableBuffer *buffer, uint32_t pos, njsBaton *baton, napi_env env,
        napi_value *value)
{
        case DPI_NATIVE_TYPE_TIMESTAMP: // (new case)
            char *dateString;

            if (var->dbTypeNum == DPI_ORACLE_TYPE_DATE)
            {
                dateString = malloc(19);
                sprintf(dateString, "%04hu-%02hu-%02huT%02hu:%02hu:%02hu",
                        data->value.asTimestamp.year,
                        data->value.asTimestamp.month,
                        data->value.asTimestamp.day,
                        data->value.asTimestamp.hour,
                        data->value.asTimestamp.minute,
                        data->value.asTimestamp.second);
            }
            else if (var->dbTypeNum == DPI_ORACLE_TYPE_TIMESTAMP)
            {
                dateString = malloc(29);
                sprintf(dateString, "%04hu-%02hu-%02huT%02hu:%02hu:%02hu.%u",
                                                            data->value.asTimestamp.year,
                                                            data->value.asTimestamp.month,
                                                            data->value.asTimestamp.day,
                                                            data->value.asTimestamp.hour,
                                                            data->value.asTimestamp.minute,
                                                            data->value.asTimestamp.second,
                                                            data->value.asTimestamp.fsecond);
            }else{
                dateString = malloc(100);
                sprintf(dateString, "%04hu-%02hu-%02huT%02hu:%02hu:%02hu.%u-%02hu:%02hu",
                        data->value.asTimestamp.year,
                        data->value.asTimestamp.month,
                        data->value.asTimestamp.day,
                        data->value.asTimestamp.hour,
                        data->value.asTimestamp.minute,
                        data->value.asTimestamp.second,
                        data->value.asTimestamp.fsecond,
                        data->value.asTimestamp.tzHourOffset,
                        data->value.asTimestamp.tzMinuteOffset);
            }
            NJS_CHECK_NAPI(env, napi_create_string_utf8(env, dateString, strlen(dateString), value));
            free(dateString);
            break;
}