From 271213517b5c335787050f4f4167811724e3e1e9 Mon Sep 17 00:00:00 2001 From: Renan William Alves de Paula Date: Mon, 8 Sep 2025 17:29:50 -0300 Subject: [PATCH] Add support for separate Node.js and Java character encodings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes issue with special characters (accents, cedillas) when connecting to databases using legacy encodings like Windows-1252. Changes: - Add optional javaEncoding parameter to SybaseDB constructor - Pass -Dfile.encoding to Java process when javaEncoding is specified - Update Java classes to accept encoding parameter with full backward compatibility - Add comprehensive Mocha/Chai tests for encoding functionality - Update documentation with encoding usage examples The new API allows separate control of Node.js IPC encoding and Java database encoding, resolving character encoding mismatches while maintaining 100% backward compatibility. Usage: new Sybase(host, port, db, user, pass, false, null, { encoding: 'latin1', // Node.js IPC encoding javaEncoding: 'Cp1252' // Java database encoding }); 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- JavaSybaseLink/dist/JavaSybaseLink.jar | Bin 14547 -> 8344 bytes JavaSybaseLink/manifest.mf | 2 +- JavaSybaseLink/src/Main.java | 17 +++-- JavaSybaseLink/src/StdInputReader.java | 15 +++- README.md | 38 +++++++++- src/SybaseDB.js | 13 +++- test/test_encoding.js | 98 +++++++++++++++++++++++++ 7 files changed, 172 insertions(+), 11 deletions(-) create mode 100644 test/test_encoding.js diff --git a/JavaSybaseLink/dist/JavaSybaseLink.jar b/JavaSybaseLink/dist/JavaSybaseLink.jar index 56215addec37b36dd4fe312588662950df781f08..14195e8406123967a0d59342050b424fe9e7bb5b 100644 GIT binary patch literal 8344 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 A3;+NC literal 14547 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 G;(r0=KEu`k diff --git a/JavaSybaseLink/manifest.mf b/JavaSybaseLink/manifest.mf index 328e8e5..eea5ca7 100644 --- a/JavaSybaseLink/manifest.mf +++ b/JavaSybaseLink/manifest.mf @@ -1,3 +1,3 @@ Manifest-Version: 1.0 +Main-Class: Main X-COMMENT: Main-Class will be added automatically by build - diff --git a/JavaSybaseLink/src/Main.java b/JavaSybaseLink/src/Main.java index 101f423..f81523d 100644 --- a/JavaSybaseLink/src/Main.java +++ b/JavaSybaseLink/src/Main.java @@ -21,25 +21,32 @@ public static void main(String[] args) { Main m; String pw = ""; - if (args.length != 5 && args.length != 4) + String encoding = null; + if (args.length < 4 || args.length > 6) { - System.err.println("Expecting the arguments: host, port, dbname, username, password"); + System.err.println("Expecting the arguments: host, port, dbname, username, [password], [encoding]"); System.exit(1); } - if (args.length == 5) + if (args.length >= 5) pw = args[4]; + if (args.length == 6) + encoding = args[5]; - m = new Main(args[0], Integer.parseInt(args[1]), args[2], args[3], pw); + m = new Main(args[0], Integer.parseInt(args[1]), args[2], args[3], pw, encoding); } public Main(String host, Integer port, String dbname, String username, String password) { + this(host, port, dbname, username, password, null); + } + + public Main(String host, Integer port, String dbname, String username, String password, String encoding) { this.host = host; this.port = port; this.dbname = dbname; this.username = username; this.password = password; - input = new StdInputReader(); + input = new StdInputReader(encoding); input.addListener(this); MyProperties props = new MyProperties("sybaseConfig.properties"); diff --git a/JavaSybaseLink/src/StdInputReader.java b/JavaSybaseLink/src/StdInputReader.java index b99bf3e..c0d2f86 100644 --- a/JavaSybaseLink/src/StdInputReader.java +++ b/JavaSybaseLink/src/StdInputReader.java @@ -14,10 +14,23 @@ public class StdInputReader { private List listeners = new ArrayList(); - private BufferedReader inputBuffer = new BufferedReader(new InputStreamReader(System.in)); + private BufferedReader inputBuffer; public StdInputReader() { + this(null); + } + public StdInputReader(String encoding) { + try { + if (encoding != null && !encoding.isEmpty()) { + inputBuffer = new BufferedReader(new InputStreamReader(System.in, encoding)); + } else { + inputBuffer = new BufferedReader(new InputStreamReader(System.in)); + } + } catch (Exception e) { + System.err.println("Error setting encoding '" + encoding + "', falling back to default: " + e.getMessage()); + inputBuffer = new BufferedReader(new InputStreamReader(System.in)); + } } public void startReadLoop() diff --git a/README.md b/README.md index e4e31bb..8c6d1f4 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,8 @@ new Sybase(host: string, port: int, dbName: string, username: string, password: Where the SybaseOptions interface includes: ``` SybaseOptions { - encoding: string, // defaults to "utf8" + encoding: string, // Node.js IPC encoding, defaults to "utf8" + javaEncoding: string, // Java database communication encoding, defaults to null (uses system default) extraLogs: boolean // defaults to false } ``` @@ -71,4 +72,37 @@ var logTiming = true, The java Bridge now optionally looks for a "sybaseConfig.properties" file in which you can configure jconnect properties to be included in the connection. This should allow setting properties like: ```properties ENCRYPT_PASSWORD=true -``` \ No newline at end of file +``` + +### Character Encoding Support + +For databases using legacy character encodings (like Windows-1252), you can specify separate encoding configurations: + +```javascript +var Sybase = require('sybase'), + db = new Sybase('host', port, 'dbName', 'username', 'pw', false, null, { + encoding: 'latin1', // Node.js IPC encoding + javaEncoding: 'Cp1252', // Java database communication encoding + extraLogs: false + }); + +db.connect(function (err) { + if (err) return console.log(err); + + // Now queries with special characters (accents, cedillas, etc.) should work correctly + db.query('SELECT * FROM usuarios WHERE nome = "José"', function (err, data) { + if (err) console.log(err); + console.log(data); + db.disconnect(); + }); +}); +``` + +**Encoding Parameters:** +- `encoding`: Controls Node.js stdin/stdout encoding for communication with the Java process +- `javaEncoding`: Sets the Java system encoding (`-Dfile.encoding`) for database communication + +Common encoding combinations: +- **Windows-1252 databases**: `encoding: 'latin1', javaEncoding: 'Cp1252'` +- **ISO-8859-1 databases**: `encoding: 'latin1', javaEncoding: 'ISO-8859-1'` +- **UTF-8 databases** (default): `encoding: 'utf8'` (javaEncoding not needed) \ No newline at end of file diff --git a/src/SybaseDB.js b/src/SybaseDB.js index 5b825ea..938c454 100644 --- a/src/SybaseDB.js +++ b/src/SybaseDB.js @@ -4,7 +4,7 @@ var fs = require("fs"); var path = require("path"); -function Sybase(host, port, dbname, username, password, logTiming, pathToJavaBridge, { encoding = "utf8", extraLogs = false } = {}) +function Sybase(host, port, dbname, username, password, logTiming, pathToJavaBridge, { encoding = "utf8", javaEncoding = null, extraLogs = false } = {}) { this.connected = false; this.host = host; @@ -14,6 +14,7 @@ function Sybase(host, port, dbname, username, password, logTiming, pathToJavaBri this.password = password; this.logTiming = (logTiming == true); this.encoding = encoding; + this.javaEncoding = javaEncoding; this.extraLogs = extraLogs; this.pathToJavaBridge = pathToJavaBridge; @@ -38,7 +39,15 @@ Sybase.prototype.log = function(msg) Sybase.prototype.connect = function(callback) { var that = this; - this.javaDB = spawn('java',["-jar",this.pathToJavaBridge, this.host, this.port, this.dbname, this.username, this.password]); + var javaArgs = ["-jar", this.pathToJavaBridge, this.host, this.port, this.dbname, this.username, this.password]; + + // Add Java encoding parameter if specified + if (this.javaEncoding) { + javaArgs.splice(1, 0, "-Dfile.encoding=" + this.javaEncoding); + javaArgs.push(this.javaEncoding); // Pass encoding as additional parameter to Java app + } + + this.javaDB = spawn('java', javaArgs); var hrstart = process.hrtime(); this.javaDB.stdout.once("data", function(data) { diff --git a/test/test_encoding.js b/test/test_encoding.js new file mode 100644 index 0000000..3625a60 --- /dev/null +++ b/test/test_encoding.js @@ -0,0 +1,98 @@ +var expect = require("chai").expect; +var Sybase = require("../src/SybaseDB.js"); + +describe("Character Encoding Support", function() { + + describe("Constructor Compatibility", function() { + + it("Should support backward compatibility without encoding parameters", function() { + var db = new Sybase('localhost', 5000, 'test', 'user', 'password'); + + expect(db.encoding).to.equal('utf8'); + expect(db.javaEncoding).to.equal(null); + expect(db.extraLogs).to.equal(false); + }); + + it("Should support legacy constructor with logTiming", function() { + var db = new Sybase('localhost', 5000, 'test', 'user', 'password', true); + + expect(db.logTiming).to.equal(true); + expect(db.encoding).to.equal('utf8'); + expect(db.javaEncoding).to.equal(null); + }); + + it("Should accept encoding parameter only", function() { + var db = new Sybase('localhost', 5000, 'test', 'user', 'password', false, null, { + encoding: 'latin1' + }); + + expect(db.encoding).to.equal('latin1'); + expect(db.javaEncoding).to.equal(null); + expect(db.extraLogs).to.equal(false); + }); + + it("Should accept javaEncoding parameter only", function() { + var db = new Sybase('localhost', 5000, 'test', 'user', 'password', false, null, { + javaEncoding: 'Cp1252' + }); + + expect(db.encoding).to.equal('utf8'); // default + expect(db.javaEncoding).to.equal('Cp1252'); + expect(db.extraLogs).to.equal(false); + }); + + it("Should accept both encoding parameters (main feature)", function() { + var db = new Sybase('localhost', 5000, 'test', 'user', 'password', false, null, { + encoding: 'latin1', + javaEncoding: 'Cp1252', + extraLogs: true + }); + + expect(db.encoding).to.equal('latin1'); + expect(db.javaEncoding).to.equal('Cp1252'); + expect(db.extraLogs).to.equal(true); + }); + + it("Should preserve all other constructor parameters", function() { + var customJarPath = './custom/path/JavaSybaseLink.jar'; + var db = new Sybase('testhost', 9999, 'testdb', 'testuser', 'testpass', true, customJarPath, { + encoding: 'latin1', + javaEncoding: 'Cp1252' + }); + + expect(db.host).to.equal('testhost'); + expect(db.port).to.equal(9999); + expect(db.dbname).to.equal('testdb'); + expect(db.username).to.equal('testuser'); + expect(db.password).to.equal('testpass'); + expect(db.logTiming).to.equal(true); + expect(db.pathToJavaBridge).to.equal(customJarPath); + expect(db.encoding).to.equal('latin1'); + expect(db.javaEncoding).to.equal('Cp1252'); + }); + }); + + describe("Java Arguments Generation", function() { + + it("Should not modify Java args when javaEncoding is null", function() { + var db = new Sybase('localhost', 5000, 'test', 'user', 'password'); + + // We can't easily test the exact spawn arguments without mocking, + // but we can verify the object properties are set correctly + expect(db.javaEncoding).to.equal(null); + }); + + it("Should prepare for Java encoding when javaEncoding is set", function() { + var db = new Sybase('localhost', 5000, 'test', 'user', 'password', false, null, { + javaEncoding: 'Cp1252' + }); + + expect(db.javaEncoding).to.equal('Cp1252'); + // The actual spawn args modification happens in connect() method + // and would require a real database connection to test fully + }); + }); + + // Note: Actual database connection tests would require a real Sybase instance + // and are not included here to keep tests runnable without external dependencies +}); \ No newline at end of file