{ "id": "174910", "key": "MOD-2598", "fields": { "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false }, "project": { "id": "10034", "key": "MOD", "name": "Appcelerator Modules", "projectCategory": { "id": "10100", "description": "Titanium and related SDKs used in application development", "name": "Client" } }, "fixVersions": [], "resolution": null, "resolutiondate": null, "created": "2020-04-14T02:33:31.000+0000", "priority": { "name": "Low", "id": "4" }, "labels": [ "android", "database", "module", "parameter", "parity", "query", "type" ], "versions": [], "issuelinks": [ { "id": "58315", "type": { "id": "10003", "name": "Relates", "inward": "relates to", "outward": "relates to" }, "inwardIssue": { "id": "174909", "key": "TIMOB-27848", "fields": { "summary": "Android: Ti.Database wrongly stores booleans/numbers as strings via query parameters", "status": { "description": "The issue is open and ready for the assignee to start work on it.", "name": "Open", "id": "1", "statusCategory": { "id": 2, "key": "new", "colorName": "blue-gray", "name": "To Do" } }, "priority": { "name": "Low", "id": "4" }, "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false } } } } ], "assignee": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "updated": "2020-04-17T18:19:17.000+0000", "status": { "description": "The issue is open and ready for the assignee to start work on it.", "name": "Open", "id": "1", "statusCategory": { "id": 2, "key": "new", "colorName": "blue-gray", "name": "To Do" } }, "components": [ { "id": "13609", "name": "Encrypted SQLite DB" } ], "description": "*Summary:*\r\nThe \"appcelerator.encrypteddatabase\" module's {{DB.execute()}} method wrongly stores values of type {{boolean}} and {{number}} as type {{string}} when passed via query parameters.\r\n\r\n{code:javascript}\r\n// Will store boolean false as string \"false\". Should be stored as number 0.\r\ndb.execute(\"INSERT INTO data(value) VALUES (?)\", false);\r\n\r\n// Will store number as string \"123.456\". Should be stored as number.\r\ndb.execute(\"INSERT INTO data(value) VALUES (?)\", 123.456);\r\n{code}\r\n\r\n*Note:*\r\nThis is not an issue on iOS. Values of type {{boolean}} and {{number}} are stored as numbers. Also note that SQLite does not natively support boolean types and will be stored as integers instead.\r\n\r\n*Steps to reproduce:*\r\n# Build and run the below code on Android.\r\n# Look in the log.\r\n\r\n{code:javascript}\r\nvar database = require(\"appcelerator.encrypteddatabase\");\r\ndatabase.password = \"password\";\r\nvar dbConnection = database.open(\"test_encrypted.db\");\r\ndbConnection.execute(\"CREATE TABLE IF NOT EXISTS properties(name PRIMARY KEY, value);\");\r\nvar sqlInsertStatement = \"INSERT OR REPLACE INTO properties(name, value) VALUES (?, ?);\";\r\ndbConnection.execute(sqlInsertStatement, \"null\", null);\r\ndbConnection.execute(sqlInsertStatement, \"boolean-false\", false); // uh-oh!\r\ndbConnection.execute(sqlInsertStatement, \"boolean-true\", true); // uh-oh!\r\ndbConnection.execute(sqlInsertStatement, \"integer-0\", 0); // uh-oh!\r\ndbConnection.execute(sqlInsertStatement, \"integer-2\", 2); // uh-oh!\r\ndbConnection.execute(sqlInsertStatement, \"float\", 123.456); // uh-oh!\r\ndbConnection.execute(sqlInsertStatement, \"string-empty\", \"\");\r\ndbConnection.execute(sqlInsertStatement, \"string-not-empty\", \"Hello World\");\r\nvar resultSet = dbConnection.execute(\"SELECT name, value FROM properties;\");\r\nwhile (resultSet.isValidRow()) {\r\n\tvar name = resultSet.field(0);\r\n\tvar value = resultSet.field(1);\r\n\tTi.API.info(`@@@ db entry \"${name}\": ${value} (type ${typeof value})`);\r\n\tresultSet.next();\r\n}\r\ndbConnection.close();\r\n{code}\r\n\r\n*Results from Android:*\r\nNotice entries of type boolean, integer, and float are of type string. They should all be of type number.\r\n{code}\r\n[INFO] @@@ db entry \"null\": null (type object)\r\n[INFO] @@@ db entry \"boolean-false\": false (type string)\r\n[INFO] @@@ db entry \"boolean-true\": true (type string)\r\n[INFO] @@@ db entry \"integer-0\": 0 (type string)\r\n[INFO] @@@ db entry \"integer-2\": 2 (type string)\r\n[INFO] @@@ db entry \"float\": 123.456 (type string)\r\n[INFO] @@@ db entry \"string-empty\": (type string)\r\n[INFO] @@@ db entry \"string-not-empty\": Hello World (type string)\r\n{code}\r\n\r\n*Results from iOS:*\r\n{code}\r\n[INFO] @@@ db entry \"null\": null (type object)\r\n[INFO] @@@ db entry \"boolean-false\": 0 (type number)\r\n[INFO] @@@ db entry \"boolean-true\": 1 (type number)\r\n[INFO] @@@ db entry \"integer-0\": 0 (type number)\r\n[INFO] @@@ db entry \"integer-2\": 2 (type number)\r\n[INFO] @@@ db entry \"float\": 123.456 (type number)\r\n[INFO] @@@ db entry \"string-empty\": (type string)\r\n[INFO] @@@ db entry \"string-not-empty\": Hello World (type string)\r\n{code}\r\n\r\n*Work-Around:*\r\nWhen creating a table, assign the column a numeric affinity such as {{NUMERIC}}, {{INTEGER}}, or {{REAL}}. SQLite will automatically convert parameter values to that numeric affinity if possible. You can still store strings to a numeric column. However, a boolean will still be stored as a string.\r\n{code:sql}\r\nCREATE TABLE IF NOT EXISTS properties(name PRIMARY KEY, value NUMERIC);\r\n{code}\r\n", "attachment": [], "flagged": false, "summary": "Android: Encrypted DB wrongly stores booleans/numbers as strings via query parameters", "creator": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "subtasks": [], "reporter": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "environment": null, "comment": { "comments": [], "maxResults": 0, "total": 0, "startAt": 0 } } }