Skip to content
Closed
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
Binary file modified JavaSybaseLink/dist/JavaSybaseLink.jar
Binary file not shown.
2 changes: 1 addition & 1 deletion JavaSybaseLink/manifest.mf
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
Manifest-Version: 1.0
Main-Class: Main
X-COMMENT: Main-Class will be added automatically by build

17 changes: 12 additions & 5 deletions JavaSybaseLink/src/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
15 changes: 14 additions & 1 deletion JavaSybaseLink/src/StdInputReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,23 @@
public class StdInputReader {

private List<SQLRequestListener> listeners = new ArrayList<SQLRequestListener>();
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()
Expand Down
38 changes: 36 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
```
Expand All @@ -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
```
```

### 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)
13 changes: 11 additions & 2 deletions src/SybaseDB.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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) {
Expand Down
98 changes: 98 additions & 0 deletions test/test_encoding.js
Original file line number Diff line number Diff line change
@@ -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
});