Just installed MySQL locally, and created a db and one simple table. I'm now trying to connect to it from Google Sheets, but it fails with err:
{ [Exception: Invalid argument: url] name: 'Exception' } undefined
Much googling later, it seems that because Sheets runs on google servers, it can't resolve localhost as a Host.
Is there a way around this?
var HOST = 'localhost';
var PORT = '3306';
var USERNAME = 'xxxx';
var PASSWORD = 'xxxx';
var DATABASE = 'investment';
var DB_TYPE = 'mysql';
var MAXROWS = 1000;
function testConnection(){
var sql = doc.getRange('query!a2').getDisplayValue();
var options = {};
}
function runSql(query, options) {
try {
var fullConnectionString = 'jdbc:' + DB_TYPE + '://' + HOST + ':' + PORT;
var conn = Jdbc.getConnection(fullConnectionString, USERNAME, PASSWORD);
Logger.log('conn :', conn);
Logger.log('query :', query);
var stmt = conn.createStatement();
stmt.execute('USE ' + DATABASE);
var start = new Date();
var stmt = conn.createStatement();
stmt.setMaxRows(MAXROWS);
var rs = stmt.executeQuery(query);
} catch (e) {
console.log(e, e.lineNumber);
Browser.msgBox(e);
return false;
}
}
Just wondering, if I could find a way of getting my IPv4 address online (since it would be DHCP I think, so changing periodically), could I use Host such as 101.146.72.23/localhost? (not my real IP)
[Edit] I tried adding my IPv4 address as above, and maybe that took me a step closer, as now I get a different error:
{ [Exception: Failed to establish a database connection. Check connection string, username and password.] name: 'Exception' } undefined
While reading up on Google: JDBC, it states "In order to create a database connection using the JDBC service you must allow-list certain IP ranges in your database settings to allow Apps Script to access it. These are the address ranges you'll need to allow-list."
Now searching on how to do this in Windows 10.
[Edit 2] Reporting progress for anyone else who needs to do this. Following #Julian Benavides suggestions, I found a link on how to Add Port Forwarding on Telstra Smart Modem . This post pointed out that my pc would need a Static IP address (on the local network), at How to Setup a Static IP Address on a Computer.
I think I have made a successful connection, although now I have to figure out why I have error:
Exception: Table 'investment.investment_type' doesn't exist
Getting closer, but no cigar yet.
[Edit 3 - Success!] I had the wrong table name, now works!
Did you configure a port forwarding or DMZ access ?, if you are at home configure and do access to router or contact with your ISP, or if you are in the company contact with the network administrator.
With this way your ip could be resolve in internet and be accesed by jdbc connection.
A brief summary of how the issue was resolved - more info in the updates in the original post.
The code I used was closely derived from Ben Collins - How To Connect Google Sheets To A Database, Using Apps Script
#Julian Benavides pointed out that I needed to add Port Forwarding, found how to do that at Setup a Port Forward on the Telstra Smart Modem Gen 2 Router
Had to assign a Static IP on my local network for the machine running MySQL, from How to Setup a Static IP Address
Hope this may be useful to another novice like me. :)
Related
So... I have been trying to set up the connection to a Cloud SQL for MySQL database from an Apps Script function, however I am unable to figure out why it is not working. I have been following the documentation for JDBC, however no matter what I do, the connection always fails.
The following is the code I am using:
const connectionName = '<project_id>:<region>:<instance_id>';
const user = '<user>';
const userPwd = '<user_pass>';
const db = '<database>';
const dbUrl = 'jdbc:google:mysql://' + connectionName + '/' + db;
function connect() {
const conn = Jdbc.getCloudSqlConnection(dbUrl, user, userPwd);
let start = new Date();
let stmt = conn.createStatement();
stmt.setMaxRows(1000);
let results = stmt.executeQuery('SELECT * FROM entries');
let numCols = results.getMetaData().getColumnCount();
while (results.next()) {
let rowString = '';
for (let col = 0; col < numCols; col++) {
rowString += results.getString(col + 1) + '\t';
}
Logger.log(rowString);
}
results.close();
stmt.close();
let end = new Date();
Logger.log('Time elapsed: %sms', end - start);
}
When running this code I get the following error:
Every time I run the code, I can see a new line in the mysqlerr logs:
I have the Cloud SQL instance set with the public IP, but I have not whitelisted any networks. The documentation does not mention it as a required step. Also I have set the project number for the GCP project of this Apps Script project, but still I get this error.
EDIT
As requested, I am adding more screenshots about the instance:
I am able to connect to the Cloud SQL instance using the gcloud sql instances connect command, and once inside I am able to query the table I want. (Bear in mind that the table is currently empty, as we are in the early stages of development at this point)
I believe this rules out the possibility of me using the wrong user/password.
As you can see I am using the default value for the max_allowed_packet flag. To be honest I have not set any flags on this instance yet.
About the connection name, I am using the format shared in the code snippet above, and actually I have copy and pasted it from the Cloud Console.
The next screenshot is the summary of the instance's settings:
Thanks in advance! 😁
I work on the team that maintains Google Cloud SQL Connector libraries.
I was able to get your code sample working with my own project, so I don't think your code is the problem. The first thing I would try is double checking the values of user, userPwd, and connectionName. If those are all correct, then I would also ensure that the user you are trying to log in as has access to the database.
As for those errors you're seeing in the logs, this troubleshooting documentation has some suggestions regarding things you can try. Once suggestion would be to increase the max_allowed_packet flag
If you're sure that all of those values are correct, then please follow up to this comment and we can try to debug further.
My code has been working daily for 6 months and it appears it doesn't work anymore. I know Google App Script Runtime did an update to V8 https://developers.google.com/apps-script/guides/v8-runtime (message displayed when I open "Script editor"). I suspect the problem comes from this version change because nothing else has changed.
I use Jdbc to access an SQL database at the beginning of the code:
var connectionName = '';
var user = '';
var userPwd = '';
var db = '';
var dbUrl = 'jdbc:mysql://'+connectionName+'/'+db;
var conn = Jdbc.getConnection(dbUrl, user, userPwd);
The error message I get is "ReferenceError: Jdbc is not defined", and I don't know how to fix it.
Could someone have a solution please?
This is a known issue with v8 and Google has acknowledged the bug. You may follow the issue tracker for updates.
The Google issuetracker now says that the issue has been fixed
Original answer (obsolete)
The other answer is correct, here is some additional information and a possible workaround. As noted in a comment on the issue on the Google issuetracker, you can pass Jdbc from the script using the library to a function in the library to make this work.
Example in the library Lib:
function getConnection(tjdbc) {
//dbUrl = ...
//user = ...
//password = ...
return tjdbc.getCloudSqlConnection(dbUrl, user, password);
}
in the script using the library :
function doStuff() {
var connection = Lib.getConnection(Jdbc);
//...
}
As the database can be queried using the resulting JdbcConnection, this might be the only place where you need to pass Jdbc in this way. It seems however that under V8 accessing Databases using Jdbc is also much slower than under Rhino (by a factor of 800 in my tests), so be warned.
I am using codes from GOOGLE to connect to mariadb remotely with correct parameters.
// Replace the variables in this block with real values.
var address = 'database_IP_address';
var rootPwd = 'root_password';
var user = 'user_name';
var userPwd = 'user_password';
var db = 'database_name';
var root = 'root';
var instanceUrl = 'jdbc:mysql://' + address;
var dbUrl = instanceUrl + '/' + db;
// Create a new database within a Cloud SQL instance.
function createDatabase() {
var conn = Jdbc.getConnection(instanceUrl, root, rootPwd);
conn.createStatement().execute('CREATE DATABASE ' + db);
}
then I got the error: Connection URL uses an unsupported JDBC protocol.
it seems that i cannot connect to Mariadb, I don't know what's the connection problem.
Mariadb is not supported.
From documentation:
In Apps Script, the JDBC service supports Google Cloud SQL, MySQL, Microsoft SQL Server, and Oracle databases.
If you want to use Mariadb with Google Apps Script, you will need to write a REST API layer yourself, so that you can make simple UrlFetch calls from Apps Script to your db. That comment links to the postgrest GitHub repository as an example of a REST API.
Instead hostname , I have used IP-Address, google script still gives "failed to establish a connection, invalid connection string, username or password", I have cross-checked data, and mysql port..everything is ok.. but still problem remains.
function DBWrite(){
var address ='202.47.118.131:3306';
var user = "root";
var pwd="";
var db= "smsbrn";
var cform=FormApp.getActiveForm();
var formId=cform.getId();
var dbUrl='jdbc:mysql://' + address + '/' + db;
***var conn=Jdbc.getConnection(dbUrl, user, pwd);** //connection fails here.*
}
Have you whitelisted the Google IP's on your firewall ?
64.18.0.0 - 64.18.15.255
64.233.160.0 - 64.233.191.255
66.102.0.0 - 66.102.15.255
66.249.80.0 - 66.249.95.255
72.14.192.0 - 72.14.255.255
74.125.0.0 - 74.125.255.255
173.194.0.0 - 173.194.255.255
207.126.144.0 - 207.126.159.255
209.85.128.0 - 209.85.255.255
216.239.32.0 - 216.239.63.255
Also does your MySQL Server allow remote access on that given user or any other user ? You can find how to do so here.
How do I enable Remote Access on a MySQL Server ?
I am making a chat application, I wish to monitor which users are online and which have left.
When user joins on Connect it will add his IP to mysql users online table along with username etc..
When user leaves on Disconnect it will remove his IP from users online.
Just in case any unpredicted scenario happens, I want to get all IP addresses of clients that are currently connected to server and compare it to the ones that are in table and that way sort which clients are connected and which aren't.
So how can I obtain a list of ip's of connected clients?
The reason I want to use MySQL and table for this is because I want to monitor how many users are currently online from external PHP site. If there is better way I am open for suggestions.
One solution would be to keep an object around that contains all connected sockets (adding on connect and removing on close). Then you just iterate over the sockets in the object.
Or if you're feeling adventurous, you could use an undocumented method to get all of the active handles in node and filter them. Example:
var http = require('http');
var srv = http.createServer(function(req, res) {
console.dir(getIPs(srv));
// ...
});
srv.listen(8000);
function getIPs(server) {
var handles = process._getActiveHandles(),
ips = [];
for (var i = 0, handle, len = handles.length; i < len; ++i) {
handle = handles[i];
if (handle.readable
&& handle.writable
&& handle.server === server
&& handle.remoteAddress) {
ips.push(handle.remoteAddress);
}
}
return ips;
}