Vertica Function Creation issue with flywaydb - flyway

Using Vertica 7.1 with flyway 3.2.1 getting errors when creating functions even tried the example from the docs. Almost like it doesn't ignore the first ';' :
code in the .sql file
CREATE or replace FUNCTION default_to_hello(x VARCHAR) RETURN VARCHAR
AS BEGIN
-- The body of a SQL function in Vertica must be in the form 'RETURN expression'
RETURN (CASE WHEN (x IS NOT NULL) THEN x ELSE 'Hello' END);
END;
Error reported:
Current version of schema "public": 2
Migrating schema "public" to version 3 - test
ERROR: Migration of schema "public" to version 3 failed! Please restore backups and roll back database and code!
ERROR:
Migration V3__test.sql failed
-----------------------------
SQL State : 42601
Error Code : 4856
Message : [Vertica][VJDBC](4856) ERROR: Syntax error at or near "EOL"
Location : /opt/flywaydb/sql/V3__test.sql (/opt/flywaydb/sql/V3__test.sql)
Line : 1
Statement : CREATE or replace FUNCTION default_to_hello(x VARCHAR) RETURN VARCHAR
AS BEGIN
-- The body of a SQL function in Vertica must be in the form 'RETURN expression'
RETURN (CASE WHEN (x IS NOT NULL) THEN x ELSE 'Hello' END)
Has any one else had this happen or am I missing something?

Flyway's VerticaStatementBuilder does not support OR REPLACE. You can see the code here for how that parse (it leaves no room for deviation).
if (statementStart.startsWith("CREATE FUNCTION")) {
if (line.startsWith("BEGIN") || line.endsWith("BEGIN")) {
insideBeginEndBlock = true;
}
if (line.endsWith("END;")) {
insideBeginEndBlock = false;
}
}
I submitted a pull request for it and it was merged for Flyway 4.0.

Your function works, it is some hidden character or something like this.
i managed to reproduce the error while trying to execute it in DbVis.
But in vsql client on the Vertica nodes is working fine.
dbadmin=> CREATE or replace FUNCTION default_to_hello(x VARCHAR) RETURN VARCHAR
dbadmin-> AS BEGIN
dbadmin-> -- The body of a SQL function in Vertica must be in the form 'RETURN expression'
dbadmin-> RETURN (CASE WHEN (x IS NOT NULL) THEN x ELSE 'Hello' END);
dbadmin-> END;
CREATE FUNCTION
dbadmin=> select default_to_hello('Working');
default_to_hello
------------------
Working
(1 row)
dbadmin=> select default_to_hello(null);
default_to_hello
------------------
Hello
(1 row)

This looks like a parsing bug. Please file an issue in the Flyway issue tracker. Pull request also welcome.

Related

MySql mariaDB CREATE FUNCTION DELIMITER doesnt work. has error near ''

im going insane. i dont know whats wrong with this code i see nothing wrong in it. but it kept reading thee same error each time i put the $$ after the "END". please help guys...
here is my code
DELIMITER $$
CREATE FUNCTION fungsi1 (a int)
RETURNS INT
DETERMINISTIC
BEGIN
DECLARE nilaiasal INT;
DECLARE teks VARCHAR(50);
SET nilaiasal = a * a;
IF nilaiasal > 100 THEN
SET teks = 'LEBIH DARI SERATUS';
ELSEIF nilaiasal < 100 THEN
SET teks = 'KURANG DARI SERATUS';
INSERT INTO table1 (dataone,datatwo) VALUES(a,teks);
SELECT * FROM table1;
RETURN (nilaiasal);
END $$
DELIMITER ;
And the error is this
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '' at line 15
Please help me. I've looked up create functions error and there hasnt been anyone that has a problem near ''.
You might want to consider using a stored procedue instead of a function if you want to return a result set.
You are missing END IF; as Ergest Basha suggested and you are trying to return a result set from a function which is not allowed.

EOleException Error when trying to print a quick report

I have an Access database table named Receipts with the following field names: receipt number item name, buying price, selling price. I am using an Adoquery and datasource to connect to the access database. The following is the code I am using to print a report.
procedure TReceiptsform.BitBtn1Click(Sender: TObject);
var
qry :string;
begin
with ADOQuery1 do
begin
if ADOQuery1.Locate('receipt number',Edit1.Text,[]) then
open;
SQL.Clear;
qry:= 'SELECT*from Receipts WHERE (((Receipts.[receipt number])='+ edit1.Text+'))order by Receipts.[Item name]';
SQL.Add(qry);
Active:= True;
ReceiptForm.QuickRep1.Preview;
end;
end;
However when I run the program then I click BitBtn1Click at runtime, I get this error.
ProjectSales.exe raised exception class EOleException with message 'Extra ) in query expression "(((Receipt.[item name])=))". Process stopped. Use Step or Run to continue.
Which exception handling code can I use to prevent this error or is there a problem with the Query?
You problem is, that if Edit1 is Null, no value is given to filter on because the use of + eliminates the quotes:
'SELECT * from Receipts WHERE (((Receipts.[receipt number])='+ edit1.Text+'))order by Receipts.[Item name]'
=>
'SELECT * from Receipts WHERE (((Receipts.[receipt number])=)) order by Receipts.[Item name]'
So, use ampersand and some spaces:
'SELECT * from Receipts WHERE (((Receipts.[receipt number])=' & edit1.Text &')) order by Receipts.[Item name]'

How can I create a new SQLite file and table at runtime using FieldDefs?

I'm using Delphi Seattle to create a brand new table in a brand new SQLite file and using only FieldDefs and non-visual code. I can create a table using the ExecSQL ('CREATE TABLE....' ) syntax but not as shown below (I get 'No such table 'MyTable' which is raised when I execute the CreateDataSet call). I'd like some solution that allows me to work with FieldDefs. This code is modelled on the example here. I notice though, that there is note regarding CreateDataSet that it only applies to TFDMemTable. Is there a runtime way of creating an SQLite table without using ExecSQL?
procedure Test;
const
MyDBFile = 'c:\scratch\hope.db';
var
Connection : TFDConnection;
DriverLink : TFDPhysSQLiteDriverLink;
Table : TFDTable;
begin
DeleteFile( MyDBFile );
DriverLink := TFDPhysSQLiteDriverLink.Create( nil );
Connection := TFDConnection.Create( nil );
try
Connection.Params.Values['DriverID'] := 'SQLite';
Connection.Params.Values['Database'] := MyDBFile;
Connection.Connected := True;
Table := TFDTable.Create( nil );
try
Table.TableName := 'MyTable';
Table.Connection := Connection;
Table.FieldDefs.Add( 'one', ftString, 20 );
Table.FieldDefs.Add( 'two', ftString, 20 );
Table.CreateDataSet;
// I would add records here....
finally
Table.Free;
end;
finally
Connection.Free;
DriverLink.Free;
end;
end;
CreateDataSet is usually a local operation for initializing a client-side dataset into an empty state. If TClientDataSet is anything to go by, afaik it cannot be used create a server-side table.
To create an actual server table, I would expect to have to construct the DDL SQL to create the table and then execute it using ExecSQL on the (client-side) dataset, as you have already tried.
update
The following seems to satisfy your requirement to do everything in code, though using a TFDTable component, which doesn't surface FieldDefs, so I've used code-created TFields instead. Tested in D10 Seattle.
procedure TForm3.CreateDatabaseAndTable;
const
DBName = 'd:\delphi\code\sqlite\atest.sqlite';
var
AField : TField;
begin
if FileExists(DBName) then
DeleteFile(DBName);
AField := TLargeIntField.Create(Self);
AField.Name := 'IDField';
AField.FieldName := 'ID';
AField.DataSet := FDTable1;
AField := TWideStringField.Create(Self);
AField.Size := 80;
AField.Name := 'NameField';
AField.FieldName := 'Name';
AField.DataSet := FDTable1;
FDConnection1.Params.Values['database'] := DBName;
FDConnection1.Connected:= True;
FDTable1.TableName := 'MyTable';
FDTable1.CreateTable(False, [tpTable]);
FDTable1.Open();
FDTable1.InsertRecord([1, 'First']);
FDConnection1.Commit;
FDConnection1.Connected:= False;
end;
I expect that someone a bit more familiar than I am could do similar using a TFDMemTable's FieldDefs if it were correctly connected to a server-side component (FDCommand?) via an FDTableAdaptor.
Fwiw, I've used a LargeInt ID field and WideString Name field because trying to use Sqlite with D7 a while back, I had no end of trouble trying to use Integer and string fields.
Btw, you if you know the structure you require in advance of deployment, you might find that you get more predictable/robust results if you simply copy an empty database + table into place, rather than try and create the table in situ. Ymmv, of course.
I would NEVER dream of creating database tables using fielddefs because you wind up having tables without a proper primary key, indexes and referential integrity. The resulting tables are totally "dumbed down".
Whenever you have a "where" clause in a query the database would do a full table scan to find the records matching the query. So your database slows down (and CPU use increases) with size. That's just bad design.
Regards,
Arthur
You can use the app SQLite Expert Professional, create SQLite database.
And using FDConnection connect to the database. And use it.
Method to database SQLite, the same way that MartynA have said.
Begin
FDConnection1.Connected:=false;
FDConnection1.Params.Clear;
FDConnection1.Params.Database:='D:\SQLiteDatabase.db';
FDConnection1.ConnectionDefName:='SQLite_Demo';
FDConnection1.DriverName:='SQLite';
FDConnection1.Connected:=true;
FDTable1.Open;
End;

Using ExtractValue and XMLType in MAterialized view

I'm trying to create a materialized view that will present a tabular view on XML data contained in a table. I am also hoping to use the auto refresh option to ensure the MV is always up to date.
Some background:
Oracle 10.2
table def:
CREATE TABLE AGREEMENTEXTENSIONDATA (
AGREEMENTEXTENSIONDATAID NUMBER(18) NOT NULL,
EXTENSIONDATA NCLOB,
AGREEMENTID NUMBER(18) NOT NULL)
example of extensiondata:
<Extensions>
<ExtensionData id="2" name="IncludePortfolio" type="4">true</ExtensionData>
</Extensions>
I have create a log on the table:
CREATE MATERIALIZED VIEW LOG ON AGREEMENTEXTENSIONDATA
NOCACHE
LOGGING
NOPARALLEL
WITH PRIMARY KEY
INCLUDING NEW VALUES;
I am then trying to create the following MV:
CREATE MATERIALIZED VIEW MV_ExtAgreements
REFRESH FAST ON COMMIT
ENABLE QUERY REWRITE
as
select AGREEMENTEXTENSIONDATAID,
agreementid,
extractvalue(xmltype(EXTENSIONDATA), '/Extensions/ExtensionData[#id=''1'']')
from agreementextensiondata
/
But get the following message:
ORA-30373: object data types are not supported in this context
I saw another post suggesting to use a function to extract the values from XML, but this does not work either:
create or replace function extractVARCHAR2Extension(p_xml in clob, in_number in VARCHAR2)
return varchar2 deterministic
is
begin
return xmltype(p_xml).extract('/Extensions/ExtensionData[#id=''' || in_number || ''']/text()').getstringval();
end;
/
but the following statement fails:
select extractVARCHAR2Extension(extensiondata,'2')
from agreementextensiondata
where agreementid = 136
ORA-00600: internal error code, arguments: [kghsccread1], [128], [0], [], [], [], [], []
ORA-06512: at "SYS.XMLTYPE", line 254
ORA-06512: at "ALGOV5.EXTRACTVARCHAR2EXTENSION", line 5
??
Any guidance welcome, I maybe using the wrong set of tools here.
thanks
Change p_xml in clob to p_xml in Nclob.

INSERT stored procedure does not work?

I'm trying to make an insertion from one database called suspension to the table called Notification in the ANimals database. My stored procedure is this:
ALTER PROCEDURE [dbo].[spCreateNotification]
-- Add the parameters for the stored procedure here
#notRecID int,
#notName nvarchar(50),
#notRecStatus nvarchar(1),
#notAdded smalldatetime,
#notByWho int
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
INSERT INTO Animals.dbo.Notification
(
NotRecID,
NotName,
NotRecStatus,
NotAdded,
NotByWho
)
values (#notRecID, #notName, #notRecStatus, #notAdded, #notByWho);
END
The null inserting is to replenish one column that otherwise will not be filled, I've tried different ways, like using also the names for the columns after the name of the table and then only indicate in values the fields I've got. I know it is not a problem of the stored procedure because I executed it from the sql server management studio and it works introducing the parameters. Then I guess the problem must be in the repository when I call the stored procedure:
public void createNotification(Notification not)
{
try
{
DB.spCreateNotification(not.NotRecID, not.NotName, not.NotRecStatus,
(DateTime)not.NotAdded, (int)not.NotByWho);
}
catch
{
return;
}
}
And I call the method here:
public void createNotifications(IList<TemporalNotification> notifications)
{
foreach (var TNot in notifications)
{
var ts = RepositoryService._suspension.getTemporalSuspensionForNotificationID(TNot.TNotRecID);
Notification notification = new Notification();
if (ts.Count != 0)
{
notification.NotName = TNot.TNotName;
notification.NotRecID = TNot.TNotRecID;
notification.NotRecStatus = TNot.TNotRecStatus;
notification.NotAdded = TNot.TNotAdded;
notification.NotByWho = TNot.TNotByWho;
if (TNot.TNotToReplace != 0)
{
var suspensions = RepositoryService._suspension.getSuspensionsAttached((int)TNot.TNotToReplace);
foreach (var sus in suspensions)
{
sus.CtsEndDate = TNot.TNotAdded;
sus.CtsEndNotRecID = TNot.TNotRecID;
DB.spModifySuspensionWhenNotificationIsReplaced((int)TNot.TNotToReplace, (int)sus.CtsEndNotRecID, (DateTime) sus.CtsEndDate);
}
DB.spReplaceNotification((int)TNot.TNotToReplace, DateTime.Now);
createNotification(notification);
}
else
{
createNotification(notification);
}
}
}
deleteTemporalNotifications(notifications);
}
It does not record the value in the database. I've been debugging and getting mad about this, because it works when I execute it manually, but not when I automatize the proccess in my application. Does anyone see anything wrong with my code?
Thank you
EDIT: Added more code. It still doesn't work changing that, I mean, the procedure works if I execute it, so I don't know what could be the error. In fact, I don't get any error. Could it be a matter of writin in a table that is not in the database where you have your stored procedure?
I would specify your column names and DONT incude the NULL at all for that column. Just let SQL Server deal with it.
INSERT INTO Animals.dbo.Notification
(
RecID,
[Name],
RecStatus,
Added,
ByWho
)
values (#notRecID, #notName, #notRecStatus, #notAdded, #notByWho);
Run profiler when you try to run it from the application and see what values it realy is sending. That will tell you if the application is creating the correct exec statment to exec the proc.
Also it may be a permissions problem.
Specify your column names:
INSERT INTO Animals.dbo.Notification
(RecID, Name, RecStatus, Added, ByWho)
VALUES
(#notRecID, #notName, #notRecStatus, #notAdded, #notByWho);
"Could it be a matter of writin in a table that is not in the database where you have your stored procedure?"
That may be the problem. You could try adding the "WITH EXECUTE AS OWNER" clause to your stored procedure so that it executes as the owner of the stored procedure. Or grant write permissions for the executing user to the table.
http://msdn.microsoft.com/en-us/library/ms188354.aspx
ok, I finally found out what noone realized lol. It was a very stupid error but got me really mad till I found the problem. It wasn't a problem of permissions, the problem was that I was not executing the procedure from my application, so where I wrote this:
DB.spCreateNotification(not.NotRecID, not.NotName, not.NotRecStatus,
(DateTime)not.NotAdded, (int)not.NotByWho);
When I had to write:
DB.spCreateNotification(not.NotRecID, not.NotName, not.NotRecStatus,
(DateTime)not.NotAdded, (int)not.NotByWho).Execute();
so as you see I was focusing my efforts in much more complex things and I wasn't even executing it...lol.
Thank you all for your answers anyway:)

Resources