Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sqlite3 Support #91

Merged
merged 4 commits into from
Oct 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
8 changes: 7 additions & 1 deletion api/src/main/java/com/force/formula/sql/FormulaSqlStyle.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,13 @@ default boolean isPrestoStyle() {
default boolean isGoogleStyle() {
return false;
}


/**
* @return whether or not to default to Sqlite style.
*/
default boolean isSqliteStyle() {
return false;
}

/**
* @return the function name for taking a substring.
Expand Down
14 changes: 12 additions & 2 deletions api/src/main/java/com/force/formula/util/BigDecimalHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@

package com.force.formula.util;

import java.math.*;
import java.sql.*;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
* BigDecimal helper class
Expand All @@ -31,6 +35,12 @@ public class BigDecimalHelper {
public static final int NUMBER_PRECISION_EXTERNAL = 33;
public static final MathContext MC_PRECISION_EXTERNAL = new MathContext(NUMBER_PRECISION_EXTERNAL, RoundingMode.HALF_UP);

/**
* For low-precision DBs, use this constant to prevent ROUND(,33) from causing Round/Ceil to get confused with
* integers
*/
public static final int DOUBLE_PRECISION = 16;

public static final BigDecimal getNonNullFromRs(ResultSet rs, String colName) throws SQLException {
BigDecimal bd = rs.getBigDecimal(colName);
return bd == null ? BigDecimal.ZERO : bd;
Expand Down
14 changes: 13 additions & 1 deletion api/src/main/java/com/force/formula/util/FormulaDateUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import java.util.function.Supplier;

import com.force.i18n.BaseLocalizer;
Expand All @@ -29,6 +31,7 @@ private FormulaDateUtil() {}


private static final ThreadLocal<SimpleDateFormat> ISO8601_FORMATTER = ThreadLocal.withInitial(sdfWithGMT("yyyy-MM-dd'T'HH:mm:ss'Z'"));
private static final ThreadLocal<SimpleDateFormat> SQL_TIMESTAMP_FORMATTER = ThreadLocal.withInitial(sdfWithGMT("yyyy-MM-dd HH:mm:ss"));
private static final ThreadLocal<SimpleDateFormat> ISO8601_MILLISECOND_FORMATTER = ThreadLocal.withInitial(sdfWithGMT("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"));

private static final ThreadLocal<SimpleDateFormat> SQL_FORMATTER = ThreadLocal.withInitial(() -> new SimpleDateFormat("dd-MM-yyyy"));
Expand Down Expand Up @@ -204,6 +207,15 @@ public static String formatDatetimeToISO8601(Date date) {
return ISO8601_FORMATTER.get().format(date);
}

/**
* Returns a string in SQL Literal format, with both date and time
* e.g. 2011-01-31 22:59:48
* @param date the date to format
* @return the value of the date formatted with ISO8601 format.
*/
public static String formatDatetimeToSqlLiteral(Date date) {
return SQL_TIMESTAMP_FORMATTER.get().format(date);
}

public static Calendar translateCal(Calendar from, Calendar to, Date date, boolean toMidnight) {
from.setTime(date);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ public ContextualFormulaFieldInfo lookup(String name, boolean isDynamicRefBase)
return originDateTime_PRESTO;
} else if (style != null && style.isGoogleStyle()) {
return originDateTime_GOOGLE;
} else if (style != null && style.isSqliteStyle()) {
return originDateTime_SQLITE;
}
return originDateTime;
} else {
Expand Down Expand Up @@ -143,6 +145,8 @@ public SQLPair getSQL(ITableAliasRegistry registry) {
FormulaEngine.getHooks().getDataTypeByName("DateTime"), new SQLPair("DATEFROMPARTS(1900,1,1)", null));
private static final SystemFormulaFieldInfo originDateTime_GOOGLE = new SystemFormulaFieldInfo(ORIGIN_DATE_TIME,
FormulaEngine.getHooks().getDataTypeByName("DateTime"), new SQLPair("DATE(1900,1,1)", null));
private static final SystemFormulaFieldInfo originDateTime_SQLITE = new SystemFormulaFieldInfo(ORIGIN_DATE_TIME,
FormulaEngine.getHooks().getDataTypeByName("DateTime"), new SQLPair("'1900-01-01 00:00:00'", null));
private static DisplayField[] displayFields = new DisplayField[] { new DisplayField(SYSTEM_NAMESPACE, SYSTEM_NAMESPACE, originDateTime) };

static {
Expand Down
10 changes: 10 additions & 0 deletions docs/coverage/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,16 @@
<artifactId>formula-engine-sqlserver-test</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.salesforce.formula</groupId>
<artifactId>formula-engine-google-test</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.salesforce.formula</groupId>
<artifactId>formula-engine-sqlite-test</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</profile>
</profiles>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
<result>
<inputvalues>No data</inputvalues>
<formula>Error: com.force.formula.FormulaDateException</formula>
<sql>Error: INVALID_ARGUMENT: Invalid column type to get as timestamp: INT64</sql>
<sql>Error: INVALID_ARGUMENT: Invalid column type to get as date: INT64</sql>
<formulaNullAsNull>Error: com.force.formula.FormulaDateException</formulaNullAsNull>
<sqlNullAsNull>Error: INVALID_ARGUMENT: Invalid column type to get as timestamp: INT64</sqlNullAsNull>
<sqlNullAsNull>Error: INVALID_ARGUMENT: Invalid column type to get as date: INT64</sqlNullAsNull>
</result>
</testInstance>
</testCase>
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
<result>
<inputvalues>No data</inputvalues>
<formula>Error: com.force.formula.FormulaDateException</formula>
<sql>Error: INVALID_ARGUMENT: Invalid column type to get as timestamp: INT64</sql>
<sql>Error: INVALID_ARGUMENT: Invalid column type to get as date: INT64</sql>
<formulaNullAsNull>Error: com.force.formula.FormulaDateException</formulaNullAsNull>
<sqlNullAsNull>Error: INVALID_ARGUMENT: Invalid column type to get as timestamp: INT64</sqlNullAsNull>
<sqlNullAsNull>Error: INVALID_ARGUMENT: Invalid column type to get as date: INT64</sqlNullAsNull>
</result>
</testInstance>
</testCase>
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
<result>
<inputvalues>No data</inputvalues>
<formula>null</formula>
<sql>Error: INVALID_ARGUMENT: Invalid column type to get as timestamp: INT64</sql>
<sql>Error: INVALID_ARGUMENT: Invalid column type to get as date: INT64</sql>
<formulaNullAsNull>null</formulaNullAsNull>
<sqlNullAsNull>Error: INVALID_ARGUMENT: Invalid column type to get as timestamp: INT64</sqlNullAsNull>
<sqlNullAsNull>Error: INVALID_ARGUMENT: Invalid column type to get as date: INT64</sqlNullAsNull>
</result>
</testInstance>
</testCase>
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
<result>
<inputvalues>No data</inputvalues>
<formula>null</formula>
<sql>Error: INVALID_ARGUMENT: Invalid column type to get as timestamp: INT64</sql>
<sql>Error: INVALID_ARGUMENT: Invalid column type to get as date: INT64</sql>
<formulaNullAsNull>null</formulaNullAsNull>
<sqlNullAsNull>Error: INVALID_ARGUMENT: Invalid column type to get as timestamp: INT64</sqlNullAsNull>
<sqlNullAsNull>Error: INVALID_ARGUMENT: Invalid column type to get as date: INT64</sqlNullAsNull>
</result>
</testInstance>
</testCase>
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@
<testCase name="testMillisecWithValidDateTimeString">
<testInstance formula="MilliSecond(TIMEVALUE(&quot;2015-03-17 17:00:00&quot;))" returntype="Double" precision="12" scale="2">
<SqlOutput nullAsNull="true">
<Sql>TRUNC((NULL -TRUNC(NULL/1000) * 1000))</Sql>
<Sql>TRUNC(NULL -TRUNC(NULL/1000) * 1000)</Sql>
<Guard>0=0</Guard>
</SqlOutput>
<SqlOutput nullAsNull="false">
<Sql>TRUNC((NULL -TRUNC(NULL/1000) * 1000))</Sql>
<Sql>TRUNC(NULL -TRUNC(NULL/1000) * 1000)</Sql>
<Guard>0=0</Guard>
</SqlOutput>
<result>
<inputvalues>No data</inputvalues>
<formula>Error: com.force.formula.FormulaDateException</formula>
<sql>Error: INVALID_ARGUMENT: io.grpc.StatusRuntimeException: INVALID_ARGUMENT: Operands of / cannot be literal NULL [at 1:62] ...WHEN 0=0 THEN NULL ELSE ROUND(TRUNC((NULL -TRUNC(NULL/1000) * 1000)), 32) ... ^ - Statement: 'SELECT CASE WHEN 0=0 THEN NULL ELSE ROUND(TRUNC((NULL -TRUNC(NULL/1000) * 1000)), 32) END FROM (SELECT 1 as fake) c'</sql>
<sql>Error: INVALID_ARGUMENT: io.grpc.StatusRuntimeException: INVALID_ARGUMENT: Operands of / cannot be literal NULL [at 1:61] ...WHEN 0=0 THEN NULL ELSE ROUND(TRUNC(NULL -TRUNC(NULL/1000) * 1000), 32) EN... ^ - Statement: 'SELECT CASE WHEN 0=0 THEN NULL ELSE ROUND(TRUNC(NULL -TRUNC(NULL/1000) * 1000), 32) END FROM (SELECT 1 as fake) c'</sql>
<formulaNullAsNull>Error: com.force.formula.FormulaDateException</formulaNullAsNull>
<sqlNullAsNull>Error: INVALID_ARGUMENT: io.grpc.StatusRuntimeException: INVALID_ARGUMENT: Operands of / cannot be literal NULL [at 1:62] ...WHEN 0=0 THEN NULL ELSE ROUND(TRUNC((NULL -TRUNC(NULL/1000) * 1000)), 32) ... ^ - Statement: 'SELECT CASE WHEN 0=0 THEN NULL ELSE ROUND(TRUNC((NULL -TRUNC(NULL/1000) * 1000)), 32) END FROM (SELECT 1 as fake) c'</sqlNullAsNull>
<sqlNullAsNull>Error: INVALID_ARGUMENT: io.grpc.StatusRuntimeException: INVALID_ARGUMENT: Operands of / cannot be literal NULL [at 1:61] ...WHEN 0=0 THEN NULL ELSE ROUND(TRUNC(NULL -TRUNC(NULL/1000) * 1000), 32) EN... ^ - Statement: 'SELECT CASE WHEN 0=0 THEN NULL ELSE ROUND(TRUNC(NULL -TRUNC(NULL/1000) * 1000), 32) END FROM (SELECT 1 as fake) c'</sqlNullAsNull>
</result>
</testInstance>
</testCase>
Loading