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

LDEV-4753 handle empty numeric values with CFUPDATE / CFINSERT #2427

Open
wants to merge 4 commits into
base: 6.2
Choose a base branch
from
Open
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions core/src/main/java/lucee/runtime/tag/Insert.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import lucee.runtime.ext.tag.TagImpl;
import lucee.runtime.functions.displayFormatting.DecimalFormat;
import lucee.runtime.op.Caster;
import lucee.runtime.type.Collection.Key;
import lucee.runtime.type.QueryImpl;
import lucee.runtime.type.Struct;
import lucee.runtime.type.StructImpl;
Expand Down Expand Up @@ -231,12 +232,12 @@ public static Struct getMeta(DatasourceConnection dc, String tableQualifier, Str
Struct sct = new StructImpl();
try {
DatabaseMetaData md = dc.getConnection().getMetaData();
columns = md.getColumns(tableQualifier, tableOwner, tableName, null);
columns = md.getColumns(StringUtil.emptyAsNull(tableQualifier, true), StringUtil.emptyAsNull(tableOwner, true), tableName, "%");

String name;
while (columns.next()) {
name = columns.getString("COLUMN_NAME");
sct.setEL(name, new ColumnInfo(name, getInt(columns, "DATA_TYPE"), getBoolean(columns, "IS_NULLABLE")));
sct.setEL(Caster.toKey(name), new ColumnInfo(name, getInt(columns, "DATA_TYPE"), getBoolean(columns, "NULLABLE")));
}
}
catch (SQLException sqle) {
Expand All @@ -259,7 +260,7 @@ private static int getInt(ResultSet columns, String columnLabel) throws PageExce

private static boolean getBoolean(ResultSet columns, String columnLabel) throws PageException, SQLException {
try {
return columns.getBoolean(columnLabel);
return Caster.toBoolean(columns.getInt(columnLabel));
}
catch (Exception e) {
return Caster.toBooleanValue(columns.getObject(columnLabel));
Expand Down Expand Up @@ -292,9 +293,17 @@ private SQL createSQL(Struct meta) throws PageException {
}
names.append(field);
values.append('?');
ColumnInfo ci = (ColumnInfo) meta.get(field, null);
if (ci != null) items.add(new SQLItemImpl(form.get(field, null), ci.getType()));
else items.add(new SQLItemImpl(form.get(field, null)));
Key fieldKey = Caster.toKey(field);
ColumnInfo ci = (ColumnInfo) meta.get(fieldKey, null);
if (ci != null){
Object val = form.get(fieldKey, null);
SQLItemImpl item = new SQLItemImpl(val, ci.getType());
if (ci.isNullable() && StringUtil.isEmpty(val))
item.setNulls(true);
items.add(item);
} else {
items.add(new SQLItemImpl(form.get(fieldKey, null)));
}
}
}
if (items.size() == 0) return null;
Expand Down
26 changes: 17 additions & 9 deletions core/src/main/java/lucee/runtime/tag/Update.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import lucee.runtime.ext.tag.TagImpl;
import lucee.runtime.functions.displayFormatting.DecimalFormat;
import lucee.runtime.op.Caster;
import lucee.runtime.type.Collection.Key;
import lucee.runtime.type.QueryImpl;
import lucee.runtime.type.Struct;
import lucee.runtime.type.scope.Form;
Expand Down Expand Up @@ -280,29 +281,36 @@ private SQL createSQL(DatasourceConnection dc, String[] keys, Struct meta) throw

StringBuffer set = new StringBuffer();
StringBuffer where = new StringBuffer();
ArrayList setItems = new ArrayList();
ArrayList whereItems = new ArrayList();
ArrayList<SQLItem> setItems = new ArrayList<SQLItem>();
ArrayList<SQLItem> whereItems = new ArrayList<SQLItem>();
String field;
for (int i = 0; i < fields.length; i++) {
field = StringUtil.trim(fields[i], null);
if (StringUtil.startsWithIgnoreCase(field, "form.")) field = field.substring(5);

if (!field.equalsIgnoreCase("fieldnames")) {
Key fieldKey = Caster.toKey(field);
if (ArrayUtil.indexOfIgnoreCase(keys, field) == -1) {
if (set.length() == 0) set.append(" set ");
else set.append(",");
set.append(field);
set.append("=?");
ColumnInfo ci = (ColumnInfo) meta.get(field);
if (ci != null) setItems.add(new SQLItemImpl(form.get(field, null), ci.getType()));
else setItems.add(new SQLItemImpl(form.get(field, null)));
ColumnInfo ci = (ColumnInfo) meta.get(fieldKey);
if (ci != null){
Object val = form.get(fieldKey, null);
SQLItemImpl item = new SQLItemImpl(val, ci.getType());
if (ci.isNullable() && StringUtil.isEmpty(val)) item.setNulls(true);
setItems.add(item);
} else {
setItems.add(new SQLItemImpl(form.get(fieldKey, null)));
}
}
else {
if (where.length() == 0) where.append(" where ");
else where.append(" and ");
where.append(field);
where.append("=?");
whereItems.add(new SQLItemImpl(form.get(field, null)));
whereItems.add(new SQLItemImpl(form.get(fieldKey, null)));
}
}
}
Expand All @@ -328,19 +336,19 @@ private SQL createSQL(DatasourceConnection dc, String[] keys, Struct meta) throw
return new SQLImpl(sql.toString(), arrayMerge(setItems, whereItems));
}

private SQLItem[] arrayMerge(ArrayList setItems, ArrayList whereItems) {
private SQLItem[] arrayMerge(ArrayList<SQLItem> setItems, ArrayList<SQLItem> whereItems) {
SQLItem[] items = new SQLItem[setItems.size() + whereItems.size()];

int index = 0;
// Item
int size = setItems.size();
for (int i = 0; i < size; i++) {
items[index++] = (SQLItem) setItems.get(i);
items[index++] = setItems.get(i);
}
// Where
size = whereItems.size();
for (int i = 0; i < size; i++) {
items[index++] = (SQLItem) whereItems.get(i);
items[index++] = whereItems.get(i);
}
return items;
}
Expand Down
67 changes: 45 additions & 22 deletions test/tickets/LDEV4753.cfc
Original file line number Diff line number Diff line change
@@ -1,37 +1,65 @@
component extends="org.lucee.cfml.test.LuceeTestCase" skip=true {
component extends="org.lucee.cfml.test.LuceeTestCase" labels="mssql" {
function beforeAll() {
if(isNotSupported()) return;
request.mssql = getCredentials();
request.mssql.storage = true;
variables.str = request.mssql;
var mssql = getCredentials();
mssql.storage = true;
variables.datasource = mssql;
tableCreation();
}

function afterAll() {
if(isNotSupported()) return;
query datasource=variables.datasource{
echo("DROP TABLE IF EXISTS LDEV4753");
}
}

function run( testResults , testBox ) {
describe( title = "Test suite for LDEV-4753", body = function() {
it( title = "checking CFUPDATE for LDEV-4753", body = function( currentSpec ) {
describe( title = "Test suite for LDEV-4753 with mssql", body = function() {
it( title = "checking CFINSERT for LDEV-4753 with empty numeric cols", body = function( currentSpec ) {
param name="form.id" default="1";
param name="form.myValue" default="LuceeTestCase";
param name="form.seqno" default="";
expect( function() {
cfupdate(tableName = "cfupdatetbl" formFields = "form.id,form.myValue,form.seqno" datasource=str);
}).notToThrow();
cfinsert(tableName = "LDEV4753" formFields = "form.id,form.myValue,form.seqno" datasource=variables.datasource);
checkTable( 1 );
});

it( title = "checking CFUPDATE for LDEV-4753 with empty numeric cols", body = function( currentSpec ) {
param name="form.id" default="1";
param name="form.myValue" default="LDEV-4753";
param name="form.seqno" default="";
cfupdate(tableName = "LDEV4753" formFields = "form.id,form.myValue,form.seqno" datasource=variables.datasource);
checkTable( 1 );

form.seqno="3";
form.myValue="";
cfupdate(tableName = "LDEV4753" formFields = "form.id,form.myValue,form.seqno" datasource=variables.datasource);
checkTable( 1 );
});
});
}


private function tableCreation() {
query datasource=str{
echo("DROP TABLE IF EXISTS cfupdatetbl");
query datasource=variables.datasource{
echo("DROP TABLE IF EXISTS LDEV4753");
}
query datasource=str{
echo("
create table cfupdatetbl (id numeric(18, 0) primary key,myValue nvarchar(50),seqno numeric(18, 0))"
);
query datasource=variables.datasource{
echo("create table LDEV4753 (id numeric(18, 0) primary key,myValue nvarchar(50),seqno numeric(18, 0))");
}
}

private function checkTable( id ){
var params = {
id = {value: arguments.id, sql_type: "numeric" }
}
query name="local.q" datasource=variables.datasource params=params {
echo("select * from LDEV4753 where id = :id");
}
expect ( q.recordcount ).toBe( 1, "recordcount" );
loop list="id,myvalue,seqno" item="local.c"{
expect( q[ c ] ).toBe( form[ c ] );
}
}

private boolean function isNotSupported() {
var cred=getCredentials();
Expand All @@ -42,10 +70,5 @@ component extends="org.lucee.cfml.test.LuceeTestCase" skip=true {
return server.getDatasource("mssql");
}

function afterAll() {
if(isNotSupported()) return;
query datasource=str{
echo("DROP TABLE IF EXISTS cfupdatetbl");
}
}

}
73 changes: 73 additions & 0 deletions test/tickets/LDEV4753_mysql.cfc
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
component extends="org.lucee.cfml.test.LuceeTestCase" labels="mysql" {
function beforeAll() {
if(isNotSupported()) return;
var mysql = getCredentials();
mysql.storage = true;
variables.datasource = mysql;
tableCreation();
}

function afterAll() {
if(isNotSupported()) return;
query datasource=variables.datasource{
echo("DROP TABLE IF EXISTS LDEV4753");
}
}

function run( testResults , testBox ) {
describe( title = "Test suite for LDEV-4753 with MSSQL", body = function() {
it( title = "checking CFINSERT for LDEV-4753 with empty numeric cols", body = function( currentSpec ) {
param name="form.id" default="1";
param name="form.myValue" default="LuceeTestCase";
param name="form.seqno" default="";
cfinsert(tableName = "LDEV4753" formFields = "form.id,form.myValue,form.seqno" datasource=variables.datasource);
checkTable( 1 );
});
it( title = "checking CFUPDATE for LDEV-4753 with empty numeric cols", body = function( currentSpec ) {
param name="form.id" default="1";
param name="form.myValue" default="LDEV-4753";
param name="form.seqno" default="";
cfupdate(tableName = "LDEV4753" formFields = "form.id,form.myValue,form.seqno" datasource=variables.datasource);
checkTable( 1 );
form.seqno="3";
form.myValue="";
cfupdate(tableName = "LDEV4753" formFields = "form.id,form.myValue,form.seqno" datasource=variables.datasource);
checkTable( 1 );
});
});
}


private function tableCreation() {
query datasource=variables.datasource{
echo("DROP TABLE IF EXISTS LDEV4753");
}
query datasource=variables.datasource{
echo("create table LDEV4753 (id numeric(18, 0) primary key,myValue nvarchar(50),seqno numeric(18, 0))");
}
}

private function checkTable( id ){
var params = {
id = {value: arguments.id, sql_type: "numeric" }
}
query name="local.q" datasource=variables.datasource params=params {
echo("select * from LDEV4753 where id = :id");
}
systemOutput( q, true );
loop list="id,myvalue,seqno" item="local.c"{
expect( q[ c ] ).toBe( form[ c ] );
}
}

private boolean function isNotSupported() {
var cred=getCredentials();
return isNull(cred) || structCount(cred)==0;
}

private struct function getCredentials() {
return server.getDatasource("mysql");
}


}
Loading