How to do 'Generate DDL' in Sybase Central in isql on the command line? - sybase

In Sybase Central when I right click on a stored procedure and choose 'Generate DDL', then I see the definition of the stored procedure, but also the grants for example.
How do you do that on the command line with isql?

Best/recommended approach would be the ddlgen utility program; this will generate the DDL for the proc's text, sp_procxmode settings, and permissions. ddlgen is the 'go to' tool for reverse engineering Sybase ASE DDL.
Sample run:
$ ddlgen -SASE400 -Ppassword -Usa -TP -Nsybsystemprocs.dbo.sp_helptext
-----------------------------------------------------------------------------
-- DDL for Stored Procedure 'sybsystemprocs.dbo.sp_helptext'
-----------------------------------------------------------------------------
print '<<<<< CREATING Stored Procedure - "sybsystemprocs.dbo.sp_helptext" >>>>>'
go
use sybsystemprocs
go
IF EXISTS (SELECT 1 FROM sysobjects o, sysusers u WHERE o.uid=u.uid AND o.name = 'sp_helptext' AND u.name = 'dbo' AND o.type = 'P')
BEGIN
setuser 'dbo'
drop procedure sp_helptext
END
go
IF (##error != 0)
BEGIN
PRINT 'Error dropping Stored Procedure sybsystemprocs.dbo.sp_helptext'
SELECT syb_quit()
END
go
setuser 'dbo'
go
/*
** sp_helptext
**
... snip ...
*/
create or replace procedure sp_helptext(
#objname varchar(325) = NULL
, #grouping_num int = NULL
, #numlines int = NULL
, #printopts varchar(256) = NULL
, #trace int = 0
) as
... snip ...
return (0)
end
go
Grant Execute on dbo.sp_helptext to public Granted by dbo
go
sp_procxmode 'sp_helptext', anymode
go
setuser
go
Other options would include:
defncopy utility program for the text of the proc
sp_helptext for text of the proc
sp_helprotect for permissions (though you will need to parse the output to generate the necessary grant/revoke commands)

Related

SQL Server returns error with sp_trace_generateevent

I get an error from one of my databases when trying to execute this one
create or alter procedure [dbo].[test_sp]
with execute as owner
as
SELECT SUSER_SNAME()+ ' '+ USER_NAME();
begin
exec master..sp_trace_generateevent #eventid = 82 ,
#userinfo=N'test'
end
GO
exec [dbo].[test_sp]
Error:
Msg 8189, Level 14, State 10, Procedure master..sp_trace_generateevent, Line 1 [Batch Start Line 9]
You do not have permission to run 'SP_TRACE_GENERATEEVENT'.
Granted ALTER TRACE to my user (which returns in SUSER_SNAME()), but it wasn't help
The same script on the second database (same server) works without errors.
What else can it be?
You're trying to run this with EXECUTE AS OWNER, and the owner is a database-level principal and you can't operate outside the current database while impersonating a database-level principal. Switch to EXECUTE AS CALLER (the default) to have the caller's identity used to run the proc in master. eg
create or alter procedure [dbo].[test_sp]
with execute as caller
as
SELECT SUSER_SNAME()+ ' '+ USER_NAME();
begin
exec master..sp_trace_generateevent #eventid = 82, #userinfo = N'test'
end
GO
exec [dbo].[test_sp]
This can be made to work with owner-impersonation by marking the database as TRUSTWORTHY. See: Extending Database Impersonation by Using EXECUTE AS and Guidelines for using the TRUSTWORTHY database setting in SQL Server

Scope of ## variable in TSQL

In the following TSQL code I can use my local variable in first few lines and then I cannot use it again. Why am I not able to use it in the last line of my code ?
Where does its scope end?
DECLARE ##CurrentDB varchar(50);
SET ##CurrentDB = 'MyDBNAME';
-- Find Data & Log Fiel locations
SELECT DB_NAME(database_id) AS DatabaseName, name AS LogicalFileName, physical_name AS PhysicalFileName, size/(128*1024) [GB]
FROM sys.master_files AS mf
WHERE DB_NAME(database_id) = ##CurrentDB
-- Detach DB
USE
GO
ALTER DATABASE SET SINGLE_USER WITH ROLLBACK IMMEDIATE
GO
USE [master]
GO
EXEC master.dbo.sp_detach_db #dbname = ##Cur
GO
Here is the error:
Any time you pass SQL Server a GO command, that ends the context in which the variable exists and it is no longer accessible by anything after that point in the T-SQL code. "Global" variables as such do not exist in SQL Server, but there are ways around it, generally by implementing a global variable table (either temporary or permanent).
You can get the general idea from this blog post that sets up a permanent table to track global variables.
As a workaround, you can use a Global Temp Table:
Declare #CurrentDB varchar(50)
SET #CurrentDB = 'MyDBNAME'
Create Table ##CurrentDB (Name varchar(50))
Insert Into ##CurrentDB Values (#CurrentDB)
GO
-- ...
GO
Declare #CurrentDB varchar(50)
Select Top 1 #CurrentDB = Name From ##CurrentDB
Select #CurrentDB
This should work even if you are using different databases in each part of your script.
Why use a global variable or temp table at all? This cries out to me to be a user defined stored procedure.
Here are the business rules.
1 - You basically want to get the location and size of a database you want to detach.
2 - Want to set database to single user mode.
3 - You want to detach the database. Just remember the files will be hanging around afterwards.
I created it in the MSDB database but you can put it in your own toolbox database.
I did not check to see if the database is really in use only mode. - TODO list
Just check the mode in the sys.databases table. If the ALTER, fails do not try the detach. Just notify the user to find the spids and kill them.
http://technet.microsoft.com/en-us/library/ms178534.aspx
4 - I did not put any error handling in. - TODO list
Last but not least, this solution could be prone to SQL injection, do not give the world access.
In short, the stored procedure below does just what you want.
--
-- Create a user stored procedure
--
-- Start in msdb
use msdb
go
-- drop existing
if object_id('my_detach_process') > 0
drop procedure my_detach_process
go
-- create new
create procedure my_detach_process(#dbname sysname)
as
-- Show the data
SELECT
DB_NAME(mf.database_id) AS DatabaseName,
mf.name AS LogicalName,
mf.physical_name AS PhysicalName, mf.size as SizeMb
FROM sys.master_files AS mf
WHERE DB_NAME(database_id) = #dbname;
-- Set to single user
DECLARE #sqlstmt1 nvarchar(512) = '';
SET #sqlstmt1 = 'ALTER DATABASE [' + #dbname + '] SET SINGLE_USER WITH ROLLBACK IMMEDIATE';
EXEC sp_executesql #sqlstmt1;
-- Detach
DECLARE #sqlstmt2 nvarchar(512) = '';
SET #sqlstmt2 = 'USE [master]; EXEC master.dbo.sp_detach_db #dbname = ' + #dbname;
EXEC sp_executesql #sqlstmt2;
GO
--
-- Sample call
--
-- Choose master
use master
go
-- Create toy db
create database toy;
go
-- Call the sp
exec msdb.dbo.my_detach_process #dbname = 'Toy'
Sample output from sample call.

How can I get the database name from which stored procedure is called?

See comments in code.
use master
go
create database db1
create database db2
go
-------------------------------
use db2
go
create procedure proc2
as begin
-- how I can figure out that this proc2 is called
-- 1. from proc1 which is contained in the db1 (case N1)
-- 2. or from context of db1 (case N2)
select DB_NAME()
end
go
-------------------------------
use db1
go
create procedure proc1
as begin
exec db2.dbo.proc2
end
go
select DB_NAME();
-- case N1
exec dbo.proc1;
-- case N2
exec db2.dbo.proc2;
-------------------------------
use master
go
drop database db1
drop database db2
Output
db1
db2
db2
If I remember correctly, I don't think it is possible.
There is a work-around, you can add an extra input parameter in proc2 and pass the information to it.
Here's the original script, but with a quick change to proc2 based on my answer over here. (Note that sys.dm_tran_locks requires 'VIEW SERVER STATE' permissions to use.)
Output
db1
db1
db1
Script
use master
go
create database db1
create database db2
go
-------------------------------
use db2
go
create procedure proc2
as begin
DECLARE #result nvarchar(128);
SELECT TOP 1 #result = DB_NAME(resource_database_id)
FROM sys.dm_tran_locks
WHERE request_session_id = ##SPID
AND resource_type = 'DATABASE'
AND request_owner_type = 'SHARED_TRANSACTION_WORKSPACE'
ORDER BY IIF(resource_database_id != DB_ID(), 0, 1);
SELECT #result;
end
go
-------------------------------
use db1
go
create procedure proc1
as begin
exec db2.dbo.proc2
end
go
select DB_NAME();
-- case N1
exec dbo.proc1;
-- case N2
exec db2.dbo.proc2;
-------------------------------
use master
go
drop database db1
drop database db2

sys.database_principals is not executed in current database if called from sp procedure (stored in master)

I would like to print out database users of an actual database in a SP procedure (see the code of sp_PrintUsers below), however, for some reason it print out database users of master. It seems that it is a general behavior of SP procedure for all database-level views despite the fact that any database-level SQL statement is executed in the actual database. If we print out the DB_NAME that it is clearly not master, so what is wrong?
Is there any workaround?
use [master]
go
create procedure sp_PrintUsers
as
begin
SELECT DB_NAME() AS DataBaseName
select name from sys.database_principals;
end
go
use [actual_database]
go
exec sp_PrintUsers
Try executing the select dynamically as in:
EXEC('select name from sys.database_principals;');
If that does not help build the query to reference the catalog view with a three part name.
Try this :
use [master]
go
create procedure sp_PrintUsers
as
begin
declare #dbname varchar(30) = DB_NAME()
EXEC ('select name from ' + #dbname + '.sys.database_principals');
end
go
use [actual_database]
go
exec sp_PrintUsers

Permissions to set job Enable/Disable in SQL Server

The database user has been granted SQLAgentOperatorRole, but there are still error when set job enable/disable. The error message is:
SELECT permission was denied on the object 'sysjobs', database 'msdb', schema 'dbo'
We set the job enable/disable by sp_update_job.
Comments:
When executing the following statement, will get the error.
bool result = ObjectInstance.ExecuteStoreQuery<bool>("EXEC usp_prod_SetJobStatus #jobName={0}, #isEnable={1}", jobName, isEnable).FirstOrDefault();
But, while use the following statement, it will execute successful.
ObjectInstance.ExecuteStoreCommand("EXEC msdb.dbo.sp_update_job #job_name={0}, #enabled={1}", jobName, isEnable);
usp_prod_SetJobStatus SP:
CREATE PROCEDURE [dbo].[usp_prod_SetJobStatus]
#jobName VARCHAR(200),
#isEnable BIT
AS
BEGIN
DECLARE #jobId uniqueidentifier
DECLARE #result BIT
SELECT #jobId = job_id FROM msdb.dbo.sysjobs WHERE name = #jobName
IF(#jobId IS NOT NULL)
BEGIN
EXEC #result = msdb.dbo.sp_update_job #job_name=#jobName, #enabled=#isEnable
END
ELSE
BEGIN
SET #result = 1
END
SELECT #result
END
I have solved this problem. The reason is that there is no SELECT permission on sysjobs table for the user. So, we need to grant the SELECT perssion for the user.
USE msdb
GRANT SELECT ON msdb.dbo.sysjobs TO useName
You have given agent operator role its having enable and disable but SQLAgentOperatorRole members can enable or disable local jobs they do not own by using the stored procedure sp_update_job and specifying values for the #enabled and the #job_id (or #job_name) parameters. If a member of this role specifies any other parameters for this stored procedure, execution of the procedure will fail ..You have to execute permissions on sql server agnet .

Resources