I have a Delphi/C++ builder app that uses Firedac to connect to a Sybase ASE database using the ODBC connection. When connection to the database, if I use the database's system admin (SA) user id/password, everything works fine and GetTableNames comes back with the list of tables in the database. But if I use a regular user to connect to database, GetTableNames comes back with an empty list. My question is, what permissions should I give the regular user for this to work.And as a side question, does anyone know what kind of command Firedac sends to database to get the table names?My code in Delphi looks like:
DBConnection.GetTableNames('', '', '', tableNameList, [TFDPhysObjectScope.osMy], [TFDPhysTableKind.tkTable]);
and in C++ Builder it looks like:
DBConnection->GetTableNames(L"", L"", L"", tableNameList, TFDPhysObjectScopes() << TFDPhysObjectScope::osMy, TFDPhysTableKinds() << TFDPhysTableKind::tkTable);
Thank youSam
For generic ODBC drivers it's the SQLTables function that FireDAC calls. Unfortunately, for the SAP Adaptive Server Enterprise driver I haven't found any information about the implementation of this function. It is the implementation detail, so it's not the issue.
The only note I found is this (for different products), for example:
sp_tables
This function corresponds to the ODBC function SQLTables.
So it's possible that the ODBC driver calls the sp_tables stored procedure in its SQLTables function implementation for that product, but no one explicitly said that (only that it corresponds).
What's more, for SAP Adaptive Server Enterprise, there is no such note by its sp_tables procedure. But you can give it a try. Or better yet, if you have some kind of command monitoring tool, use it to track what your driver calls from its SQLTables function implementation.
In any case, it is an implementation detail you should not care about, nor rely on.
The problem was NOT permissions, it was the 5th parameter of GetTableNames. The 5th parameter is the Scope which determines what kind of tables would be reported back. osMy means tables/objects owned by the logged-in user. But normally all tables in a database, are owned by SA/dbo. Adding osOther to the parameter will fix the problem. So the correct way of calling the function in Delphi would be:
DBConnection.GetTableNames('', '', '', tableNameList, [TFDPhysObjectScope.osMy, TFDPhysObjectScope.osOther], [TFDPhysTableKind.tkTable]);
and in C++ Builder it should look like:
DBConnection->GetTableNames(L"", L"", L"", tableNameList, TFDPhysObjectScopes() << TFDPhysObjectScope::osMy << TFDPhysObjectScope::osOther, TFDPhysTableKinds() << TFDPhysTableKind::tkTable);
Which will return the name of all tables that are not system tables.I must mention that I blame Embarcadero for poor documentation of TFDPhysObjectScope. The documentation does NOT explain what any of these values means. Way too often (as in this case) we see this:
Embarcadero Technologies does not currently have any additional
information. Please help us document this topic by using the
Discussion page!
And we are forced to guess and/or try-fail.
Related
I have an exam using SQLPlus and sometimes I don't remember the exact syntax of SQL statements, so I was wondering if there is any way to get some nice inline help from inside SQLPlus.
For instance, say I forgot how to use INSERT INTO, and I want some reminder like this:
INSERT INTO table-name (column-names)
VALUES (values)
Is this possible?
I tried HELP command but none of that seems to suits my needs.
I Googled it with no success.
No. SQL is a standardized language (at least ANSI SQL) and SQLPlus "just" uses that syntax, so it's not covered by internal help. Internal help lists only SQLPlus specific commands (ex. SET, CONNECT, SPOOL).
It is possible to workaround that in some way, but very limited. You can call dbms_metadata.get_ddl function for some existing object. Some of those DDLs could have statements you are intrested in. For example - you'd like to see select statement - then you could call dbms_metadata.get_ddl for some existing view:
select dbms_metadata.get_ddl('VIEW', 'USER_TABLES', 'SYS')
from dual;
Be aware - it works only for Oracle 11G and lower, in the newest one SYS objects are not accessible in that way (I'm not sure about Oracle 12.1).
The more interesting are tiggers, procedures, functions, and packages. You cannot use dbms_metadata to get DDLs of packages owned by SYS, but maybe you can connect to some sample schemas like HR (Human Resources), AD (Academic), SH (Sales History).
In HR schema there is stored procedure ADD_JOB_HISTORY, which has inside insert statement, so it looks like that:
select dbms_metadata.get_ddl('PROCEDURE', 'ADD_JOB_HISTORY')
from dual;
CREATE OR REPLACE EDITIONABLE PROCEDURE "HR"."ADD_JOB_HISTORY"
( p_emp_id job_history.employee_id%type
, p_start_date job_history.start_date%type
, p_end_date job_history.end_date%type
, p_job_id job_history.job_id%type
, p_department_id job_history.department_id%type
)
IS
BEGIN
INSERT INTO job_history (employee_id, start_date, end_date,
job_id, department_id)
VALUES(p_emp_id, p_start_date, p_end_date, p_job_id, p_department_id);
END add_job_history;
There are better ways and better tools to achieve your goal - see below.
Are you allowed to use SQL Developer instead of SQLPlus? SQL Developer has nice feature to drag-and-drop table icon into worksheet, then you will be nicely prompted to choose what kind of example statement you are looking for (SELECT, INSERT, UPDATE etc.) - after choosing one you will get sample statement.
But the best way is just open in browser Database SQL Language Reference:
https://docs.oracle.com/database/121/SQLRF/toc.htm
Windows 10, Access 2016
I am moving a very small database (14 tables and 40-50 stored procedures) from SQL Server to Access. I have tried to recreate the stored procedures from code using an OLEDB command object. This is a sample of a CommandText…
CREATE PROCEDURE DeleteOrderDetailByOrderID
([#ID] int)
AS
DELETE FROM OrderDetails
WHERE (OrderID = #ID);
I get an error message that the Data Type of #ID is incorrect. It is not. When I remove the brackets from #ID all is forgiven and the code runs. However, Access strips the # from #ID in the parameter section (not in the Where clause). I have had to go into Access and manually correct this. I do not like the idea of going through almost 5000 lines of code to correct parameter names in my program. I thought I could use the direct approach by pasting the SQL directly into Access but I get an error with this route saying syntax error in CREATE TABLE and it highlights the word PROCEDURE. This leads me to believe that you cannot use CREATE PROCEDURE directly in Access. Is this true? Is there another approach that I am missing?
You are missing, that T-SQL of SQL Server is not Access SQL.
Access has UDFs - user defined functions - that can be used in queries also, but that is VBA code.
If you just need a single-user file based database to hold your data, you may get away with the SQL Server Compact Edition which supports a subset of T-SQL.
I would like to be able to get the number of installed user licenses for an Advantage Database Server instance in code using Delphi. I have found a function that lets me get the installed version, ie. ACE.AdsMgGetInstallInfo(dm.AdsConnection1.handle,#stInstallInfo,#usSize);, but not anything that lets me check the license count.
The ACE.AdsMgGetInstallInfo API call you mentioned should be the correct call.
After the call the appropriate info is in the ADS_MGMT_INSTALL_INFO structure (#stInstallInfo in your example). The field you're looking for is an UNSIGNED32 called ulMaxStatefulUsers.
easiest to use SQL:
EXECUTE PROCEDURE sp_mgGetInstallInfo()
lets you read out the installation information,
EXECUTE PROCEDURE sp_mgGetUsageInfo()
the values displayed in the Consfiguration Utiltiy (configured/inUse/maxUsed/rejected).
I am trying to use Macros in FireDAC to Preprocess my SQL Queries. I have a TADQuery object on a Data Module with the SQL set to something like:
Select * from MyTable
join OtherTable on MyTable.Key = OtherTable.Key
&Where
Then in my code I do this:
WhereClause = 'stuff based on my form';
Query.MacroByName('Where').AsRaw := WhereClause;
Query.Open;
This has worked great for complicated queries because it lets me make sure my fields and join conditions are correct using the SQL Property editor.
My problem is when the SQL statements ends up invalid because of my where clause. Is there any way to see the SQL after pre-processing that is going to be executed? Right now I am catching the FireDac errors and showing the SQL that is on EADDBEngineException object. However that is still showing my original SQL with the macros. If I can't get to it after the error happens is there anyway to force the Macro replacement to take place so I can look at the SQL in the debugger to help me see what is wrong.
If it matters I am connecting to a MS Access database with the goal of moving to SQL Server in the near future.
Apart from using Text property, to monitor what SQL is actually going to the database engine, consider using the "FDMonitor" FireDAC utility. According to the DokWiki pages (below):
drop a TFDMoniRemoteClientLink component on your form,
Set its Tracing property to True,
Add the MonitorBy=Xxx connection definition parameter to your existing FDConnection component. You can do this in the IDE object inspector, by selecting your FDConnection component, expanding the Params property, and setting MonitorBy to mbRemote.
Note that the TFDMoniXxxxClientLink should come before TFDConnection in the data module or form creation order, so adjust this by right clicking on the form or data module, then Creation Order, and moving the TFDMoni.. component above the FDConnection.
Also, it's helpful in the options of the TFDMoniXxxxClientLink, to disable most of the events being recorded, otherwise all the data returned is also shown in the FireDAC monitor. Expand the EventKinds property, and turn all the event kinds off, except for perhaps ekConnConnect, ekConnPrepare, and ekCmdExecute.
Then open the FireDAC Monitor from the IDE, (Tools > FireDAC Monitor). Start your app only once the monitor is running. Double click on a trace event (in the Trace Output tab), and you will see the actual SQL sent to the database in the bottom pane.
It also seems likely that adding the EventType of ekConnPrepare as mentioned above, would show you when the query's Prepare is called, but I haven't played enough with it say for sure.
Please see the following pages on the DocWiki for more information:
Overview: FDMonitor
How to: Tracing and Monitoring (FireDAC)
Other FireDAC utilities: Utilities (FireDAC)
(Just to remove this question from list of unanswered questions)
From comments:
Well, I've roughly checked what's happening there and I'm still not
sure if calling Prepare (which is useless for you as I get) is the
minimal requirement to trigger that preprocessing. Though, the
preprocessed SQL, the one which is sent to the DBMS you can access
through the Text property (quite uncommon name for such property). – TLama Feb
21 '14 at 8:18
We ran the Fortify scan and had some Access Control: Database issues. The code is getting the textbox value and setting it to a string variable. In this case, it's passing the value from the TextBox to the stored procedure in a database. Any ideas on how I can get around this Access Control: Database issue?
Without proper access control, the method ExecuteNonQuery() in DataBase.cs
can execute a SQL statement on line 320 that contains an attacker-controlled primary
key, thereby allowing the attacker to access unauthorized records.
Source: Tool.ascx.cs:591 System.Web.UI.WebControls.TextBox.get_Text()
rptItem.FindControl("lblClmInvalidEntry").Visible = false;
ToolDataAccess.UpdateToolData(strSDN, strSSNum, strRANC, strAdvRecDate, strAdvSubDate, strClmRecDate, strClmAuth, strClmSubDate, strAdvAuth, txtNoteEntry.Text);
Sink: DataBase.cs:278
System.Data.SqlClient.SqlParameterCollection.Add()
// Add parameters
foreach (SqlParameter parameter in parameters)
cmd.Parameters.Add(parameter);
The point of "Access Control: Database" is where it isn't being specific enough in the query and so could potentially allow a user to see information that they're not supposed to.
An easy example of this vulnerability would be a payroll database where there is a textbox that says the ID of the employee and gives their salary, this could potentially allow the user to change the ID and see the salary of other employees.
Another example where this is often intended functionality is in a website URL where the product ID is used in a parameter, meaning a user could go through every product you have on your site. But as this only allows users to see information they're supposed to be able to, it's not particularly a security issue.
For instance:
"SELECT account_balance FROM accounts WHERE account_number = " + $input_from_attacker + ";"
// even if we safely build the query above, preventing change to the query structure,
// the attacker can still send someone else's account number, and read Grandma's balance!
As this is pretty context based, it's difficult to determine statically so there are lots of examples where Fortify may catch this but it's actually intended functionality. That's not to say the tool is broken, it's just one of the limitations of static analysis and depending on what your program is supposed to be doing it may or may not be intended.
If this is intended to work like this, then I would suggest auditing it as not an issue or suppressing the issue.
If you can see that this is definitely an issue and users can see information that they shouldn't be able to, then the stored procedure needs to be more specific so that users can only see information they should be able to. However SCA will likely still pick this up in a latter scan so you would still then need to audit it as fixed and no longer an issue.