5

I have some create table scripts which I need to pre-validate in my application. I can think of two ways:

  1. CREATE table using that script and immediately DROP table.
  2. Use EXPLAIN command to find syntactical errors without creating it.

I found 2nd way more efficient. So, I validated CREATE TABLE DDLs using Explain command.

Working :

Teradata

Explain <CREATE TABLE DDL>

Oracle

EXPLAIN PLAN FOR <CREATE TABLE DDL>

Not working :

SQL SERVER

Could not find stored procedure 'explain'. SQLState: S00062 ErrorCode: 2812

Netezza

^ found "CREATE" (at char 18) expecting DELETE' orINSERT' or SELECT' orUPDATE' or `WITH'

DB2

Error: DB2 SQL Error: SQLCODE=-104, SQLSTATE=42601, SQLERRMC=TABLE;EXPLAIN CREATE ;JOIN, DRIVER=4.14.111 SQLState: 42601 ErrorCode: -104


  • Is there any other better way to validate Create Table DDLs?

  • Is there any generic way to handle this across popular RDBMS?

  • If explain is the only available solution, how to perform explain for SQL Server, Netezza and DB2?

Edit:

Here validate means to check syntax (storage size, precision, scale range violations, reserved keywords as table or column names, etc.)

For example, query like -

create table abc (c1 decimal(555,44))

I want to get precision overflow error beforehand.

Dev
  • 13,492
  • 19
  • 81
  • 174
  • And by "validate" you mean what exactly? – Nick Krasnov Jul 29 '16 at 10:36
  • @NicholasKrasnov validate means to find precision, scale overflows,etc. For example `create table abc (c1 decimal(555,44))` – Dev Jul 29 '16 at 10:39
  • In Oracle, there is no native way to parse a `DDL` statement to check if it's syntactically and/or semantically correct without actually executing it. The `explain plan` (though it's not its purpose) is as close as you can get to parsing a DDL statement without actually executing it. `DML` parsing(without statement execution) can be done with `dbms_sql.parse()` - DDL statement will be executed. – Nick Krasnov Jul 29 '16 at 11:12
  • 6
    "*Is there any generic way to handle this across popular RDBMS?*" - no, absolutely not. –  Jul 29 '16 at 11:12
  • @a_horse_with_no_name okay thanks...! – Dev Jul 29 '16 at 11:13
  • If you are looking for a DBMS independent way to manage your DDL, I suggest you have a look at [Liquibase](http://www.liquibase.org/) –  Jul 29 '16 at 11:16
  • Is there a reason why you can't simply execute the `CREATE TABLE` or other DDL statement(s)? – Ian Bjorhovde Jul 29 '16 at 21:38
  • @IanBjorhovde I have to pre-validate CREATE TABLE DDLs. I have 2 options- 1. create these tables and drop immediately. 2. check logical plan using explain so that syntactical errors can be found beforehand. I think 2nd one is efficient. correct me if I am wrong – Dev Aug 01 '16 at 06:01
  • You might submit the Create as a *prepared statement*, this should result in parsing only, e.g. `prepareStatement('CREATE TABLE...')` in JDBC: http://docs.oracle.com/javase/tutorial/jdbc/basics/prepared.html – dnoeth Aug 02 '16 at 15:46
  • If you want a generic way to handle multiple database platforms you are basically looking at using some kind of non-SQL programming language to create an ORM (object relational mapper). You then create your tables as code objects and your code parses and validates the object into SQL for the target database of your choice. If you are a .NET programmer I think you can do this with something like Entity Framework. I'm sure there are other ways too. However, it is probably going to be a lot of work – David Cram Aug 05 '16 at 18:32

4 Answers4

3

There is no generic/standard method that will work in all DBMS.

I expect all popular DBMS to have something similar to EXPLAIN command. Something to return the execution plan instead of running the query itself. Each server will have its own way of doing it.

http://use-the-index-luke.com/sql/explain-plan shows how to do it for few DBMS. A search for <your DBMS name> explain plan command usually gives good results.


Another approach is to start a transaction, run your statement and roll back the transaction. Of course, you need to have proper error handling, which again differs between servers. In SQL Server there is TRY ... CATCH.

It is also worth checking if DDL statements in transactions are supported in the chosen DBMS. For example, in MySQL "Some statements cannot be rolled back. In general, these include data definition language (DDL) statements, such as those that create or drop databases, those that create, drop, or alter tables or stored routines."

Vladimir Baranov
  • 31,799
  • 5
  • 53
  • 90
1

You should be able to evaluate the correctness of a query in SQL Server using the format only option SET FMTONLY ON. With this option set SQL Server will not actually attempt to create the tables. Using your example, the T-SQL will look as follow:

SET FMTONLY ON
create table abc (c1 decimal(555,44))
SET FMTONLY OFF

Executing the above T-SQL will return error message ‘Column or parameter #1: Specified column precision 555 is greater than the maximum precision of 38.’

You could also create a stored procedure that evaluates the query for you using the method that works the best on the database platform you are using. I am not familiar with Netezza, Teradata & DB2 but I am assuming that they can execute dynamic SQL. Using this method, you simply pass the query you wish to evaluate as a parameter to the stored procedure from your application layer. The following code snippet show how this can be done for SQL Server:

CREATE PROCEDURE ValidateQuerySyntax
(
    @query NVARCHAR(MAX)
)
AS
BEGIN

    SET NOCOUNT ON;

    DECLARE @validationQuery NVARCHAR(MAX) = 'SET FMTONLY ON; ' + CHAR(13) + @query + ';' +  CHAR(13) + 'SET FMTONLY OFF;';

    BEGIN TRY
        EXEC (@validationQuery);

        -- Return error code 0 if query validation was successful.
        SELECT  
             0 AS ErrorNumber  
            ,0 AS ErrorSeverity  
            ,0 AS ErrorState  
            ,0 AS ErrorLine  
            ,'Query evaluated successfully' AS ErrorMessage; 

    END TRY  
    BEGIN CATCH  

        -- Return error information if query validation failed.
        SELECT  
             ERROR_NUMBER() AS ErrorNumber  
            ,ERROR_SEVERITY() AS ErrorSeverity  
            ,ERROR_STATE() AS ErrorState  
            ,ERROR_LINE() AS ErrorLine  
            ,ERROR_MESSAGE() AS ErrorMessage; 
    END CATCH; 

END

Queries can be evaluated as follow:

DECLARE @query_1 NVARCHAR(MAX) = 
'CREATE TABLE A 
(   
     c1 INT
)';

DECLARE @query_2 NVARCHAR(MAX) = 
'CREATE TABLE B 
(   
     c1 INT
     c2 INT
)';

DECLARE @query_3 NVARCHAR(MAX) = 
'CREATE TABLE B 
(   
     c1 INT
     ,c2 DECIMAL(555,44)
)';

EXEC dbo.ValidateQuerySyntax @query = @query_1;

EXEC dbo.ValidateQuerySyntax @query = @query_2;

EXEC dbo.ValidateQuerySyntax @query = @query_3;

The output of the above validation calls is as follow:

-------------------------------------------------------------------------------------------------------------------------------------------------------------
ErrorNumber | ErrorSeverity | ErrorState    | ErrorLine | ErrorMessage
-------------------------------------------------------------------------------------------------------------------------------------------------------------
0           | 0             | 0             | 0         | Query evaluated successfully
-------------------------------------------------------------------------------------------------------------------------------------------------------------
102         | 15            | 1             | 4         | Incorrect syntax near 'c2'.
-------------------------------------------------------------------------------------------------------------------------------------------------------------
2750        | 16            | 1             | 1         | Column or parameter #2: Specified column precision 555 is greater than the maximum precision of 38.
-------------------------------------------------------------------------------------------------------------------------------------------------------------

Of course this does mean creating the stored procedure that evaluates the query for you first, but it should simplify the validation of your query across the different database platforms.

Edmond Quinton
  • 1,709
  • 9
  • 10
1

My suggestion to (at least) your first two concerns:

  • Is there any other better way to validate Create Table DDLs?
  • Is there any generic way to handle this across popular RDBMS?

would be to use Perl's parsing and database interface capabilities/features (i.e. Perl DBI module) and write a script that validates the SQL via a prepared statement call against your choice(s) of database(s).

The high-level code flow would be:

  1. Connect to your database of choice
  2. Run your SQL through Perl's prepare() call (e.g. $dbh->prepare('CREATE TABLE emp (emp_name VARCHAR2(30)')
  3. Check the output status of the prepare() call

From the A Short Guide to DBI

The prepare call prepares a query to be executed by the database. The argument is any SQL at all. On high-end databases, prepare will send the SQL to the database server, which will compile it. If prepare is successful, it returns a statement handle object which represents the statement; otherwise it returns an undefined value and we abort the program. $dbh->errstr will return the reason for failure, which might be ``Syntax error in SQL''. It gets this reason from the actual database, if possible.

Perl has some other modules that are worth a look at and may be of use, namely:

SQL::Translator

SQL::Statement

tale852150
  • 1,618
  • 3
  • 17
  • 23
0

Perhaps the SQL PREPARE statement, issued against the string that is the DDL statement; should be revealing of the SQLCODE and SQLSTATE for when the DDL CREATE TABLE statement is not valid. Something like the following REXX-like pseudo-code:

sCrtTable="create table abc (c1 decimal(555,44))" ;
prepare DDL_stmt from :sCrtTable ;
say sqlCode ":" sqlState ; /* e.g.: "-604 : 42611"  per invalid length attribute */ 
CRPence
  • 1,259
  • 7
  • 12