How to connect to specific database using JDBC and Google Apps Script - mysql

I'm trying to connect to a Google Cloud MySQL 5.7 instance using GAS and JDBC. I'm able to run the following without error:
var conn = Jdbc.getCloudSqlConnection("jdbc:google:mysql://my-instance-111111:us-central1:mydbname", user,userPwd)
But this doesn't connect to a specific database, i.e. when I run
var stmt = conn.createStatement();
var results = stmt.executeQuery('SELECT col FROM myTable;');
I get Error Exception: No database selected.
One approach to try to fix:
The GAS docs indicate that I can use advanced parameters to include the DB name, but when I run var conn = Jdbc.getCloudSqlConnection("jdbc:google:mysql://my-instance-111111:us-central1:mydbname", user,userPwd,mydbname) ,
I get Exception: The parameters (String,String,String,String) don't match the method signature for Jdbc.getCloudSqlConnection.
A collection of getCloudSqlConnection statements that I've tried based on a number of StackOverflow posts:
var conn = Jdbc.getCloudSqlConnection("jdbc:google:mysql://my-instance-111111:us-central1:mydbname/mydbname", user,userPwd)
var conn = Jdbc.getCloudSqlConnection("jdbc:google:mysql://my-instance-111111:us-central1:mydbname:3306/mydbname", user,userPwd)
var conn = Jdbc.getCloudSqlConnection("jdbc:google:mysql://my-instance-111111:us-central1:mydbname:3307/mydbname", user,userPwd)
For the above statements, I also tried replacing my-instance-111111:us-central1:mydbname with the public IP supplied on the GC overview webpage. All return Exception: Failed to establish a database connection. Check connection string, username and password.
I'm using user root and the appropriate password. I can enter the DB via the command line with the user and password that I'm supplying in GAS, so I don't think I'm supplying the wrong user and password.
Edit:
I went back to the docs like #AddonDepot mentioned and realized that I need to pass an object, but I still can't get this work....
var obj = {
connectTimeoutSeconds: 15,
database: "mydbname",
instance: "my-instance-111111:us-central1:mydbname",
password: userPwd,
queryTimeoutSeconds: 15,
user: user };
var conn = Jdbc.getCloudSqlConnection("jdbc:google:mysql://my-instance-111111:us-central1:mydbname", obj);
returns
Exception: The following connection properties are unsupported: database,instance,connectTimeoutSeconds,queryTimeoutSeconds. .
Did I do something wrong in creating the object? I'm guessing not, because GAS recognizes user and password. Why wouldn't it recognize the other advanced parameters?

We have to distinguish between database system instances (sometimes referred simply as database; I'll use instances) and databases within them. That means that you may have an instance but may not have created any database in it.
You can use Apps Script to create a new database in your instance:
const connectionName = 'connection-name:for-your:instance'
const dbName = 'database'
const username = 'user'
const password = 'password'
function createDB() {
const conn = Jdbc.getCloudSqlConnection(`jdbc:google:mysql://${connectionName}`, username, password)
conn.createStatement().execute('CREATE DATABASE ' + dbName)
}
Once you have the database created in your instance you can use it:
function useDB() {
const conn = Jdbc.getCloudSqlConnection(`jdbc:google:mysql://${connectionName}/${dbName}`, username, password)
// Use conn
}
References
JDBC (Google Apps Script guide)

Related

OpenResty / Lua - Maintain mysql database connection in worker threads

I have a simple module called "firewall.lua" that I wrote that has a function
firewall.check_ip(ip) which connects to localhost mysql and performs a query and returns the result. The function gets called from within Location / blocks in nginx sites via access_by_lua_block . The module gets initialized by init_worker_by_lua firewall.init().
Everything works as expected.
What I'd like to do however is maintain the database connection on the worker thread(s) so that I don't have to re-connect every time the function is called but instead re-use the existing connection established by the worker during initialization.
I'm not quite sure how to do this or if its actually doable in openresty/lua. I tried initializing the database connection variables outside of the function to give them scope within the module instead of function and I get various API errors that did not point me in the right direction.
Thank you!
This is possible using the OpenResty cosocket API, which gives you the ability to use a pool of non-blocking connections. There's already one MySQL driver (lua-resty-mysql) which uses the cosocket API. Since you didn't provide a code sample, I'm assuming you're not using it.
Example of a connection and query using lua-resty-mysql (untested):
access_by_lua_block {
local mysql = require "resty.mysql";
local db, err = mysql:new()
db:set_timeout(1000) -- 1 second
local ok, err, errcode, sqlstate = db:connect{
host = "127.0.0.1",
port = 3306,
database = "my_db",
user = "my_user",
password = "my_pwd",
}
if not ok then
ngx.say("Connection to MySQL failed: ", err)
return
end
result, err, errcode, sqlstate = db:query("select ...")
if not result then
ngx.say("MySQL error: ", err, ".")
return
end
db:close()
}
In case, e.g., you want to control the pool name or use other options, you can pass on additional parameters to connect:
...
local ok, err, errcode, sqlstate = db:connect{
host = "127.0.0.1",
port = 3306,
database = "my_db",
user = "my_user",
password = "my_pwd",
pool = "my_connection_pool",
}
...
You can find more information in the official docs:
lua-resty-mysql: https://github.com/openresty/lua-resty-mysql
Cosocket API: https://openresty-reference.readthedocs.io/en/latest/Lua_Nginx_API/#ngxsockettcp

System.Data.OleDb.OleDbException: Invalid path or file name

i have the following code which has been getting me data from flat files. but now all of a sudden i am getting this error
System.Data.OleDb.OleDbException: Invalid path or file name
but the code hasnt changed it worked for months,im not sure what went wrong.
System.Web.Script.Serialization.JavaScriptSerializer json = new System.Web.Script.Serialization.JavaScriptSerializer();
string jsonText;
System.Collections.Generic.List<object> objList = new List<object>();
string strConn = #"Provider=vfpoledb;Data Source=\\10.0.0.0\wwwroot\apps\assembly\FlatDatabaseDbfs\vt_Flat.dbf;Collating Sequence=machine;";
using (System.Data.OleDb.OleDbConnection conn = new System.Data.OleDb.OleDbConnection(strConn))
{
System.Data.OleDb.OleDbCommand cmddbf = new System.Data.OleDb.OleDbCommand();
cmddbf.Connection = conn;
conn.Open();
cmddbf.CommandText = "select * from vt_Flat";
var dr = cmddbf.ExecuteReader();
while (dr.Read())
{
objList.Add(new
{
Code = (dr["dp_code"].ToString().Trim()),
});
};
}
var filteredList = objList.Where(obj => ((dynamic)obj).Status == (Request.QueryString["Status"] ?? "") && ((dynamic)obj).DepCode == (Request.QueryString["Code"] ?? ""));
jsonText = json.Serialize(filteredList);
Response.Write(jsonText);
}
is there something wrong with iis permissions?
Aside from the connection having to point to the PATH as already noted by Oleg, in the C# instances of OleDbConnection I have done in the past, the connection string uses
Provider=VFPOLEDB.1
Don't know if it is case/sensitive issue and the ".1" which is also part of the provider string.
Once you have a valid connection to the PATH, then your query can query from any table within the path location. So if you had 2+ files, and needed to join them, you would do so with a standard query / join. In your case, your command text is only "select *" since you changed your original connection that included the table. Change the command text to
"select * from vt_Flat"
OTHER CONSIDERATIONS
Is this being run from some web service project? If so, THAT could be the basis. You as a developer testing are running with your permissions / access. If running as a web server, the WEB-based user account may not have permissions to the folder to process / work with the data.
Check the folder of your production data to ALLOW the web user if so running. If that doesn't work, set permissions on the folder to EVERYBODY (only for testing/confirmation purposes only). See if that is the problem.
Also, from the Provider connection, did you try with it as all upper case VFPOLEDB.1?
Use path instead of file name, e.g.:
Data Source=\\10.0.0.0\wwwroot\apps\assembly\FlatDatabaseDbfs\;

Error of update(conn,tablename,colnames,data,whereClause) by using matlab connect ODBC and mySQL server 5.6

Isn't my coding typing wrong way? I need create an update button so user can edit the information by using Matlab. After update, the button need connect to mySQL server 5.6 and ODBC connector.
This is my code:
% --- Executes on button press in update.
function update_Callback(hObject, eventdata, handles)
% hObject handle to update (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
%Display dialog box to confirm save
choice = questdlg('Confirm update to database?', ...
'', ...
'Yes','No','Yes');
% Handle dialog box response
switch choice
case 'Yes'
%Set preferences with setdbprefs.
setdbprefs('DataReturnFormat', 'cellarray');
%Make connection to database.
conn = database('animal_cbir', '', '');
%Test if database connection is valid
testConnection = isconnection(conn);
disp(testConnection);
fileID = getappdata(0,'namevalue');
imageID = fileID;
name = get(handles.edit11,'String');
commonName = get(handles.edit1,'String');
scientificName = get(handles.edit2,'String');
class = get(handles.edit3,'String');
diet = get(handles.edit4,'String');
habitat = get(handles.edit5,'String');
lifeSpan = get(handles.edit6,'String');
size = get(handles.edit7,'String');
weight = get(handles.edit8,'String');
characteristic = get(handles.edit10,'String');
tablename = 'animal';
colnames ={'imageID','name','commonName','scientificName','class','diet','habitat','lifeSpan','size','weight','characteristic'};
data = {imageID,name,commonName,scientificName,class,diet,habitat,lifeSpan,size,weight,characteristic};
disp (data);
whereClause = sprintf(['where imageID = "%s"'],fileID);
update(conn,tablename,colnames,data,whereClause);
updateSuccess = helpdlg('Existing animal species successfully updated in database.');
commit(conn);
case 'No'
end
Error I am getting:
No method 'setInt' with matching signature found for class 'sun.jdbc.odbc.JdbcOdbcPreparedStatement'.
Hope that anyone can help me solve it.

ClassNotFoundException: com.mysql.jdbc.GoogleDriver

I wonder how come this error is thrown while hosting my project in APP ENGINE, I have added lots of logging just for analysis sake. When I use the com.mysql.jdbc.Driver using ip from my local it works. Kindly help !!
String name = "Vinodh";
String url = null;
try {
Class.forName("com.mysql.jdbc.GoogleDriver");
url = "jdbc:google:mysql://xxxxxxx:xxxxxx/vinodh?user=root&password=xxxxxx";
// Statements allow to issue SQL queries to the database
log.info("Initiate Connection");
Connection conn = DriverManager.getConnection(url);
log.info("Got Connection");
Statement statement = conn.createStatement();
// Result set get the result of the SQL query
ResultSet resultSet = statement
.executeQuery("select * from Family");
log.info("Entering While");
while(resultSet.next()){
log.info("Entered While");
String test = resultSet.getString("Name");
System.out.println(test);
name = test+test+test;
}
As shwown in this tutorial, during development you should use the normal mysql driver and only appengine use the Google mysql driver
if (SystemProperty.environment.value() ==
SystemProperty.Environment.Value.Production) {
// Load the class that provides the new "jdbc:google:mysql://" prefix.
Class.forName("com.mysql.jdbc.GoogleDriver");
url = "jdbc:google:mysql://your-project-id:your-instance-name/guestbook?user=root";
} else {
// Local MySQL instance to use during development.
Class.forName("com.mysql.jdbc.Driver");
url = "jdbc:mysql://127.0.0.1:3306/guestbook?user=root";
}
Also double check that you have enabled MySQL Connector/J for your application (it's not done by default)
https://developers.google.com/appengine/docs/java/cloud-sql/#enable_connector_j
<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
...
<use-google-connector-j>true</use-google-connector-j>
</appengine-web-app>
Appearently they removed this quietly. It's not even in the docs of appengine-web.xml anymore.
Use the standard com.mysql.jdbc.Driver but update your JDBC url for:
jdbc:mysql://google/[your-db-schema]
?user=root
&password=[your-db-passord]
&socketFactory=com.google.cloud.sql.mysql.SocketFactory
&cloudSqlInstance=[your-db-project-id]:[your-db-region]:[your-db-intance]
Add also to your gradle:
dependencies {
...
implementation("mysql:mysql-connector-java:8.0.29")
implementation("com.google.cloud.sql:mysql-socket-factory-connector-j-8:1.5.0")
}
Note the "google" in the URI. There's no place in the docs saying that you need it, but you have to.
Github official page guide

ADODB Command failing Execute with parameterised SQL query

I have the following JScript code:
var conn = new ActiveXObject ("ADODB.Connection");
conn.Open("Driver={MySQL ODBC 5.1 Driver};Server=localhost;Database=blah_blah_blah;User=foo;Password=bar;");
var cmd = new ActiveXObject("ADODB.Command");
cmd.ActiveConnection = conn;
var strSQL = "SELECT id FROM tbl_info WHERE title LIKE :search ORDER BY id";
var search = "test";
try{
cmd.CommandText = strSQL;
var param = cmd.CreateParameter(':search', 200, 1, 100, search);
cmd.Parameters.Append(param);
var rs = cmd.Execute();
}
catch (ex) {
Application.Alert("Error retrieving id information from database.");
}
I've verified (by printing them) that the Connection object is set to be the Command's ActiveConnection, the parameter object has the correct value and the Command object has the correct SQL query as its CommandText. I also inserted an alert statement after each line in the try block to see where the error was occuring - it's fine after cmd.Parameters.Append but the exception gets thrown upon running the Execute statement.
I've tried displaying the actual exception but it's just a generic 'Object error' message.
The query executes fine and returns the correct result set when I just execute the SQL query (without the parameter) straight through the Connection object, but seems to fail when I use a parameterised query with the Command object.
As far as I can see all settings and properties of the Command and Connection objects are correct but for whatever reason it's throwing an exception.
Any help with this would be much appreciated.
With ODBC and ADO, generally speaking, a question mark ? is used as the placeholder for parameters. Parameters are bound in the order they are appended to the Parameters collection to the placeholders in the command. In your example, replace strSQL with:
var strSQL = "SELECT id FROM tbl_info WHERE title LIKE ? ORDER BY id";
You can still name the parameter that you create, but the only purpose it would serve is to be able to reference it by name later (e.g., with cmd.Parameters.Item(":search")).