How to use prepared statements in lua-dbi? - database

I want to use prepared statements in my lua scripts. As mentioned in my previous post, people recommend using lua-dbi. Unfortunately there is little documentation available. I just need a basic script that connects to the database with credentials, and use prepared statements (prefered with a bind function to names in the query). Anyone experienced with this?

You can find it on the project's wiki pages:
Establishing connection: https://code.google.com/p/luadbi/wiki/DBDDriverConnection
require('DBI')
-- Create a connection
local dbh = assert(DBI.Connect('Driver', db, username, password, host, port))
-- set the autocommit flag
-- this is turned off by default
dbh:autocommit(true)
-- check status of the connection
local alive = dbh:ping()
-- prepare a connection
local sth = assert(dbh:prepare(sql_string))
-- commit the transaction
dbh:commit()
-- finish up
local ok = dbh:close()
where, you'd update the part dbh:prepare as per your needs.

Related

What is the difference between user postgres and a superuser?

I created a new superuser just so that this user can run COPY command.
Note that a non-superuser cannot run a copy command.
I need this user due to a backup application, and that application requires to run COPY command
But all the restrictions that I specified does not take effect (see below).
What is the difference between user postgres and a superuser?
And is there a better way to achieve what I want? I looked into a function with security definer as postgres ... that seems a lot of work for multiple tables.
DROP ROLE IF EXISTS mynewuser;
CREATE ROLE mynewuser PASSWORD 'somepassword' SUPERUSER NOCREATEDB NOCREATEROLE NOINHERIT LOGIN;
-- ISSUE: the user can still CREATEDB, CREATEROLE
REVOKE UPDATE,DELETE,TRUNCATE ON ALL TABLES IN SCHEMA public, schema1, schema2, schema3 FROM mynewuser;
-- ISSUE: the user can still UPDATE, DELETE, TRUNCATE
REVOKE CREATE ON DATABASE ip2_sync_master FROM mynewuser;
-- ISSUE: the user can still create table;
You are describing a situation where a user can write files to the server where the database runs but is not a superuser. While not impossible, it's definitely abnormal. I would be very selective about who I allow to access my DB server.
That said, if this is the situation, I'd create a function to load the table (using copy), owned by the postgres user and grant the user rights to execute the function. You can pass the filename as a parameter.
If you want to get fancy, you can create a table of users and tables to define what users can upload to what tables and have the table name as a parameter also.
It's pretty outside of the norm, but it's an idea.
Here's a basic example:
CREATE OR REPLACE FUNCTION load_table(TABLENAME text, FILENAME text)
RETURNS character varying AS
$BODY$
DECLARE
can_upload integer;
BEGIN
select count (*)
into can_upload
from upload_permissions p
where p.user_name = current_user and p.table_name = TABLENAME;
if can_upload = 0 then
return 'Permission denied';
end if;
execute 'copy ' || TABLENAME ||
' from ''' || FILENAME || '''' ||
' csv';
return '';
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
COPY with option other than writing to STDOUT and reading from STDIN is only allowed for database superusers role since it allows reading or writing any file that the server has privileges to access.
\copy is a psql client command which serves the same functionality as COPY but is not server-sided, so only local files can be processed - meaning it invokes COPY but ... FROM STDIN / ... TO STDOUT, so that files on a server are not "touched".
You can not revoke specific rights from a superuser. I'm quoting docs on this one:
Docs: Access DB
Being a superuser means that you are not subject to access controls.
Docs: CREATE ROLE
"superuser", who can override all access restrictions within the database. Superuser status is dangerous and should be used only when really needed.

Amazon RDS SQL Server: how to detect if it is RDS?

I am trying to port my database to RDS. Need to do some changes because of restrictions.
Is it possible to detect inside script (stored procedure etc) that current database is in RDS?
Upd.
I use for the testing this way in my function:
if CHARINDEX(N'EC2AMAZ',(cast(serverproperty('ServerName') as nvarchar(256))))>0
return 1
else
return 0
I liked #xiani's approach, and decided to enhance it slightly (in the event a "normal" instance of SQL Server has an [rdsadmin] database).
DECLARE #IsAmazonRDS BIT = 0;
--1st test: does the [rdsadmin] database exist?
IF DB_ID('rdsadmin') IS NOT NULL
BEGIN
BEGIN TRY
--2nd test: If this is an Amazon RDS instance, we should not able to access the database "model" under the current security context.
DECLARE #FileCount INT;
SELECT #FileCount = COUNT(*) FROM model.sys.database_files;
END TRY
BEGIN CATCH
SET #IsAmazonRDS = 1;
--Comment/uncomment to verify the flag is set.
--SELECT 'Inside Catch';
END CATCH
END
This could be supplemented with 3rd, 4th, etc. additional checks based on whatever criteria you determine. Decide for yourself how far you want to take it.
It's not foolproof, and depends on the rdsadmin database (that AWS always seems to create) existing, but I use this:
SELECT CASE WHEN db_id('rdsadmin') IS NULL THEN 0 ELSE 1 END AS RDS_DATABASE;
I use this way in my function:
if CHARINDEX(N'EC2AMAZ',(cast(serverproperty('ServerName') as nvarchar(256))))>0
return 1
else
return 0
For now it works.

How to start a transaction in ODBC?

How do you start a transaction in ODBC? Specifically i happen to be dealing with SQL Server, but the question can work for any data source.
In native T-SQL, you issue the command:
BEGIN TRANSACTION
--...
COMMIT TRANSACTION
--or ROLLBACK TRANSACTION
In ADO.net, you call:
DbConnection conn = new SqlConnection();
DbTransaction tx = conn.BeginTransaction();
//...
tx.Commit();
//or tx.Rollback();
In OLE DB you call:
IDBInitialize init = new MSDASQL();
IDBCreateSession session = (init as IDBCreateSession).CreateSession();
(session as ITransactionLocal).StartTransaction(ISOLATIONLEVEL_READCOMMITTED, 0, null, null);
//...
(session as ITransactionLocal).Commit();
//or (session as ITransactionLocal).Rollback();
In ADO you call:
Connection conn = new Connection();
conn.BeginTrans();
//...
conn.CommitTrans();
//or conn.RollbackTrans();
What about ODBC?
For ODBC, Microsoft gives a hint on their page Transactions in ODBC:
An application calls SQLSetConnectAttr to switch between the two ODBC modes of managing transactions:
Manual-commit mode
All executed statements are included in the same transaction until it is specifically stopped by calling SQLEndTran.
Which means i just need to know what parameters to pass to SQLSetConnectAttr:
HENV environment;
SQLAllocEnv(&environment);
HDBC conn;
SQLAllocConnect(henv, &conn);
SQLSetConnectAttr(conn, {attribute}, {value}, {stringLength});
//...
SQLEndTran(SQL_HANDLE_ENV, environment, SQL_COMMIT);
//or SQLEndTran(SQL_HANDLE_ENV, environment, SQL_ROLLBACK);
But the page doesn't really give any hint about which parameter will start a transaction. It might be:
SQL_COPT_SS_ENLIST_IN_XA
To begin an XA transaction with an XA-compliant Transaction Processor (TP), the client calls the Open Group tx_begin function. The application then calls SQLSetConnectAttr with a SQL_COPT_SS_ENLIST_IN_XA parameter of TRUE to associate the XA transaction with the ODBC connection. All related database activity will be performed under the protection of the XA transaction. To end an XA association with an ODBC connection, the client must call SQLSetConnectAttr with a SQL_COPT_SS_ENLIST_IN_XA parameter of FALSE. For more information, see the Microsoft Distributed Transaction Coordinator documentation.
But since i've never heard of XA, nor do i need MSDTC to be running, i don't think that's it.
maruo answered it. But to clarify:
HENV environment;
SQLAllocEnv(&environment);
HDBC conn;
SQLAllocConnect(henv, &conn);
SQLSetConnectAttr(conn, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF, SQL_IS_UINTEGER);
//...
SQLEndTran(SQL_HANDLE_ENV, environment, SQL_COMMIT);
//or SQLEndTran(SQL_HANDLE_ENV, environment, SQL_ROLLBACK);
SQLSetConnectAttr(conn, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_ON, SQL_IS_UINTEGER);
ODBC can operate in two modes: AUTOCOMMIT_ON and AUTOCOMMIT_OFF. Default is AUTOCOMMIT_ON. When Autocommit is ON each command you start using a Session Handle associated with that Connection will be Auto-Committed.
Let's see how "manual commit" (alias AUTOCOMMIT_OFF) works.
First you switch AUTOCOMMIT OFF Using something like this:
if (!SQL_SUCCEEDED(Or=SQLSetConnectAttr(Oc, SQL_ATTR_AUTOCOMMIT,
(SQLPOINTER)SQL_AUTOCOMMIT_OFF,
SQL_IS_UINTEGER))) {
// error handling here
}
Where "Oc" is the connection handle.
Second You run all commands as usual: Prepare / Execute statements, Bind Parameters, etc.... There's NO specific command to "START" a transaction. All commands after you switched Autocommit OFF are part of the transaction.
Third You commit:
if (!SQL_SUCCEEDED(Or=SQLEndTran(SQL_HANDLE_DBC, Oc, SQL_COMMIT))) {
// Error handling
}
And - again - all new commands from now on are automatically part of a new transaction that you will have to commit using another SQLEndTran command as show here above.
Finally... to switch AUTOCOMMIT_ON Again:
if (!SQL_SUCCEEDED(Or=SQLSetConnectAttr(Oc, SQL_ATTR_AUTOCOMMIT,
(SQLPOINTER)SQL_AUTOCOMMIT_ON, SQL_IS_UINTEGER))) {
// Error Handling
}

Optionally including scripts in SQL Server Projects 2012

I am building a SQL Publish Script that will be used to generate a database to our internal servers, and then used externally by our client.
The problem I have is that our internal script will automate quite a few things for us, in which the actual production environment will require these completed manually.
For example, internally we would use the following script
-- Global variables
:setvar EnvironmentName 'Local'
-- Script.PostDeployment.sql
:r .\PopulateDefaultValues.sql
IF ($(EnvironmentName) = 'Test')
BEGIN
:r .\GivePermissionsToDevelopmentTeam.sql
:r .\PopulateTestData.sql
:r .\RunETL.sql
END
ELSE IF ($(EnvironmentName) = 'Client_Dev')
BEGIN
:r .\GivePermissionsToDevWebsite.sql
END
This would generate a script like this:
-- (Ignore syntax correctness, its just the process I'm after)
IF($(EnvironmentName) = 'Test')
BEGIN
CREATE LOGIN [Developer1] AS USER [MyDomain\Developer1] WITH DEFAULT SCHEMA=[dbo];
CREATE LOGIN [Developer2] AS USER [MyDomain\Developer2] WITH DEFAULT SCHEMA=[dbo];
CREATE LOGIN [Developer3] AS USER [MyDomain\Developer3] WITH DEFAULT SCHEMA=[dbo];
-- Populate entire database (10000's of rows over 100 tables)
INSERT INTO Products ( Name, Description, Price ) VALUES
( 'Cheese Balls', 'Cheesy Balls ... mm mm mmmm', 1.00),
( 'Cheese Balls +', 'Cheesy Balls with a caffeine kick', 2.00),
( 'Cheese Squares', 'Cheesy squares with a hint of ginger', 2.50);
EXEC spRunETL 'AUTO-DEPLOY';
END
ELSE IF($(EnvironmentName) = 'Client_Dev')
BEGIN
CREATE LOGIN [WebLogin] AS USER [FABRIKAM\AppPoolUser];
END
END IF
This works fine, for us. When this script is taken on site, the script fails because it cannot authenticate the users of our internal environment.
One item I thought about permissions was to just give our internal team sysadmin privileges, but the test data just fills the script up. When going on site, having all of this test data just bloats the published script and isn't used anyway.
Is there any way to exclude a section entirely from a published file, so that all of the test data and extraeous inserts are removed, without any manual intervention of the published file?
Unfortunately, there is currently no way to remove the contents of a referenced script from the generated file entirely.
The only way to achieve this is to post-process the generated script (Powershell/Ruby/scripting language of choice) to find and remove the parts you care about using some form of string and file manipulation.
Based on: My experience with doing this exact same thing to remove a development-environment-only script which was sizable and bloated the Production deployment script with a lot of 'noise', making it harder for DBA's to review the script sensibly.

How to check the defined error class of a connection?

How to check the defined error class of a connection (DSI) of Sybase Replication Server?
I use alter connection to change the error class associated to the DSI but I want a command that list its information in order to confirm that the error class was correctly associated.
How can I do that?
You can see it by calling rs_getconn in the RSSD database.
I don't see any rs_getconn stored proc in an RSSD database for a 15.7.1 repserver.
I do see a ral_connection_details proc which seems to do the job (example output connecting with sqsh):
> ral_connection_details "MY_ASE_SERVER", "MyDB"; -mvert
dsname: MY_ASE_SERVER
dbname: MyDB
error class: rs_sqlserver_error_class
function string class: rs_sqlserver_function_class
username: mylogin
password: NULL -- Note, the password *isn't* null, whatever
dbid: 123
Not sure where rs_getconn and ral_connection_details came from (3rd party app? custom proc? one of a slew of fly-by-night SRS management tools Sybase provided over the years?), but the simplest (and guaranteed to be in any RSSD going back eons - unless someone dropped it) is the rs_helpdb stored proc.
rs_helpdb generates a result set showing dsname, dbname, did, prs, error and function classes; for RS 15.7+ you'll also get connid (associated with multipath rep / alternate connections) and the repserver error class.

Resources