VACUUM INTO an in-memory database - sqlite

I'm trying to load a sqlite file in memory.
I use "VACUUM INTO" like here, but my in-memory database remains empty.
I don't know what's wrong. :
diskDbPath := `file:C:\test.db`
memDbPath := "file:memdb?mode=memory&cache=shared"
diskDb, _ := sql.Open("sqlite3", diskDbPath)
rowcount := 0
diskDb.QueryRow("SELECT count(*) FROM sqlite_master WHERE type = 'table'").Scan(&rowcount)
fmt.Println("disk db:", rowcount, "tables")
memDb, _ := sql.Open("sqlite3", memDbPath)
_, err := diskDb.Exec("VACUUM INTO '" + memDbPath + "'; ")
if err != nil {
panic(err)
}
memDb.QueryRow("SELECT count(*) FROM sqlite_master WHERE type = 'table'").Scan(&rowcount)
fmt.Println("mem db:", rowcount, "tables")
/*
output :
disk db: 9 tables
mem db: 0 tables
*/
driver : github.com/mattn/go-sqlite3 v1.14.7, go version : go1.16.2 windows/amd64

A few tries later...
It seems to work if you ping the memory base before the vacuum.
I guess the in-memory db is not really initialized without a first contact.
diskDbPath := `file:C:\test.db`
memDbPath := "file:memdb?mode=memory&cache=shared"
diskDb, _ := sql.Open("sqlite3", diskDbPath)
rowcount := 0
diskDb.QueryRow("SELECT count(*) FROM sqlite_master WHERE type = 'table'").Scan(&rowcount)
fmt.Println("disk db:", rowcount, "tables")
memDb, _ := sql.Open("sqlite3", memDbPath)
memDb.Ping() // <
_, err := diskDb.Exec("VACUUM INTO '" + memDbPath + "'; ")
if err != nil {
panic(err)
}
memDb.QueryRow("SELECT count(*) FROM sqlite_master WHERE type = 'table'").Scan(&rowcount)
fmt.Println("mem db:", rowcount, "tables")
/*
output :
disk db: 9 tables
mem db: 9 tables
*/

Related

How to delete row in go-sqlite3

I'm using below code for adding two rows in table
package main
import (
"database/sql"
"fmt"
"log"
"strconv"
_ "github.com/mattn/go-sqlite3"
)
func main() {
database, _ := sql.Open("sqlite3", "./nraboy.db")
statement, _ := database.Prepare("CREATE TABLE IF NOT EXISTS people (id INTEGER PRIMARY KEY, firstname TEXT, lastname TEXT)")
statement.Exec()
statement, _ = database.Prepare("INSERT INTO people (firstname, lastname) VALUES (?, ?)")
statement.Exec("Nic", "Raboy")
statement, _ = database.Prepare("INSERT INTO people (firstname, lastname) VALUES (?, ?)")
statement.Exec("Tom", "Hardy")
_, err := statement.Exec("delete from people where id = 1")
if err != nil {
log.Fatal(err)
}
rows, _ := database.Query("SELECT id, firstname, lastname FROM people")
var id int
var firstname string
var lastname string
for rows.Next() {
rows.Scan(&id, &firstname, &lastname)
fmt.Println(strconv.Itoa(id) + ": " + firstname + " " + lastname)
}
}
but when I'm adding _, err := statement.Exec("delete from people where id = 1") for removing one of row I get following error:
2021/07/09 16:21:07 sql: expected 2 arguments, got 1
exit status 1
How to delete row in table ?
It looks like you forgot to call statement, _ = database.Prepare("delete from people where id = 1") for the delete command. When you are calling statement.Exec("delete from people where id = 1") the statement that was previously prepared is still in effect, and it expects two arguments (firstname, lastname).

SQLite query results limitation

I am trying to get data from SQLite database table, but i cannot get more than 50 rows. Is there a limitation of 50 rows?
My code looks like that:
unit Unit1;
interface
uses
FireDAC.Stan.Def, FireDAC.DApt, FireDAC.Phys.SQLite, FireDAC.VCLUI.Wait, FireDAC.Comp.Client, FireDAC.Stan.Async;
type
TRaportas = record
Pradzia: TDateTime;
Pabaiga: TDateTime;
Trukme: Integer;
idPriezastis: Integer;
Priezastis: string;
idVieta: Integer;
Vieta: string;
Komentaras: string;
end;
procedure TForm1.btnRaportasClick(Sender: TObject);
var
sqlConn: TFDConnection;
query: TFDQuery;
prastovuRec: array of TRaportas;
i: Integer;
begin
dbVieta := edt2.Text;
sqlConn := TFDConnection.Create(nil);
//sqlConn.Connected := False;
sqlConn.DriverName := 'SQLITE';
sqlConn.Params.Values['DataBase'] := dbVieta;
query := TFDQuery.Create(nil);
query.Connection := sqlConn;
query.SQL.Text := 'SELECT * FROM Prastovos WHERE ID >= :_ID';
query.ParamByName('_ID').Value := StrToIntDef(edt3.Text, 656);
sqlConn.Open();
query.Open();
SetLength(prastovuRec, query.RowsAffected);
edt4.Text := IntToStr(query.RowsAffected);
for i := 0 to query.RowsAffected - 1 do
begin
with mRaportas do
begin
Pradzia := query.FieldByName('Pradzia').AsDateTime;
Pabaiga := query.FieldByName('Pabaiga').AsDateTime;
Trukme := query.FieldByName('Trukme').AsInteger;
idPriezastis := query.FieldByName('IDpriezastis').AsInteger;
Priezastis := query.FieldByName('Priezastis').AsString;
idVieta := query.FieldByName('IDvieta').AsInteger;
Vieta := query.FieldByName('Vieta').AsString;
Komentaras := query.FieldByName('Komentaras').AsString;
end;
prastovuRec[i] := mRaportas;
query.Next;
end;
query.Close;
query.DisposeOf;
sqlConn.Close;
sqlConn.Free;
end;
There is a lot of mistakes and misunderstandings inyour code. To simplify, I'm just going to fix your code to make it work. Study the differences yourself.
unit Unit1;
interface
uses
FireDAC.Stan.Def, FireDAC.DApt, FireDAC.Phys.SQLite, FireDAC.VCLUI.Wait, FireDAC.Comp.Client,
FireDAC.Stan.Async, FireDAC.Stan.Option;
type
TRaportas = record
Pradzia: TDateTime;
Pabaiga: TDateTime;
Trukme: Integer;
idPriezastis: Integer;
Priezastis: string;
idVieta: Integer;
Vieta: string;
Komentaras: string;
end;
var
prastovuRec: array of TRaportas;
procedure TForm1.Button7Click(Sender: TObject);
var
sqlConn: TFDConnection;
query: TFDQuery;
mRaportas: TRaportas;
i: Integer;
begin
sqlConn := TFDConnection.Create(nil);
query := TFDQuery.Create(nil);
try
sqlConn.DriverName := 'SQLITE';
sqlConn.Params.Values['DataBase'] := edt2.Text;
query.Connection := sqlConn;
query.FetchOptions.Mode := fmAll; // essential if you want to use RecordCount
query.SQL.Text := 'SELECT * FROM Prastovos WHERE ID >= :_ID';
query.ParamByName('_ID').Value := StrToIntDef(edt3.Text, 656);
query.Open();
edt4.Text := IntToStr(query.RecordCount);
SetLength(prastovuRec, query.RecordCount);
i := 0;
while not query.Eof do
begin
mRaportas := Default(TRaportas); // not necessary if you assign all record fields
mRaportas.Pradzia := query.FieldByName('Pradzia').AsDateTime;
mRaportas.Pabaiga := query.FieldByName('Pabaiga').AsDateTime;
mRaportas.Trukme := query.FieldByName('Trukme').AsInteger;
mRaportas.idPriezastis := query.FieldByName('IDpriezastis').AsInteger;
mRaportas.Priezastis := query.FieldByName('Priezastis').AsString;
mRaportas.idVieta := query.FieldByName('IDvieta').AsInteger;
mRaportas.Vieta := query.FieldByName('Vieta').AsString;
mRaportas.Komentaras := query.FieldByName('Komentaras').AsString;
prastovuRec[i] := mRaportas;
Inc(i);
query.Next;
end;
query.Close;
finally
query.Free;
sqlConn.Free;
end;
end;
No, there is no special limit.
But you have a WHERE clause in your query. It is likely that which limits the result set. Check the value you use.

IdCookieManager cut part of server cookie which contains quotechar

There's a problem with IdCookieManager. When server returns cookie where value contains ", it recognize first occurrence of " as end of value. You can reproduce it easily with next code:
procedure TSomeObject.Test;
var
HTTP: TIdHTTP;
Cookie: TIdCookieManager;
i: Integer;
begin
HTTP := TIdHTTP.Create(nil);
Cookie := TIdCookieManager.Create(HTTP);
HTTP.CookieManager := Cookie;
HTTP.HandleRedirects := True;
HTTP.Get('http://httpbin.org/cookies/set?test_cookie1=' +
TIdURI.ParamsEncode('{"key": 123}') + '&test_cookie2=&test_cookie3=value');
for i := 0 to Cookie.CookieCollection.Count - 1 do
Form1.Memo1.Lines.Add(Cookie.CookieCollection[i].CookieName + ' = ' +
Cookie.CookieCollection[i].Value);
HTTP.Free;
end;
Digging into Indy sources I found that problem is in TIdCookie.ParseServerCookie(). It uses IdGlobal.Fetch() to extract value between quotes and ... it does what it does.
Would you recommend me how to let it parse whole value?
There's no neat solution (at least I haven't found one) ,so I've added OnHeadersAvailable event listener to TIdHTTP which rewrites cookie value after TIdCookie.ParseServerCookie() executed and replace previously parsed cookies by adding new cookie with same name to TIdCookieManager.
Code (DO NOT USE THIS HANDLER, THERE'S ONE MORE BELOW):
procedure TSomeObject.FixCookies(Sender: TObject; AHeaders: TIdHeaderList;
var VContinue: Boolean);
const
CookieDelimiter = ';';
QuoteChar = '"';
SpaceChar = ' ';
var
RawHeader, RawCookie, RawCookieValue: string;
i, CookieDelimiterPos, CookieNamePos, CookieValuePos: Integer;
Cookie: TIdCookie;
begin
for i := 0 to AHeaders.Count - 1 do
begin
RawHeader := AHeaders[i];
if Pos('Set-Cookie', RawHeader) = 1 then // starts with "Set-Cookie"
begin
for CookieNamePos := Length('Set-Cookie') + 2 to Length(RawHeader) do
if RawHeader[CookieNamePos] <> SpaceChar then
Break;
RawCookie := Copy(RawHeader, CookieNamePos,
Length(RawHeader) - CookieNamePos + 1);
CookieDelimiterPos := Pos(CookieDelimiter, RawCookie);
CookieValuePos := Pos('=', RawCookie);
if (CookieDelimiterPos > 0) and (CookieValuePos > 0) then
begin
RawCookieValue := Copy(RawCookie, CookieValuePos + 1,
CookieDelimiterPos - CookieValuePos - 1);
if (Length(RawCookieValue) > 0) and (RawCookieValue[1] = QuoteChar) and
(RawCookieValue[Length(RawCookieValue)] = QuoteChar) then
RawCookieValue := Copy(RawCookieValue, 2, Length(RawCookieValue) - 2);
with (Sender as TIdHTTP) do
begin
Cookie := TIdCookie.Create(nil);
if Cookie.ParseServerCookie(RawCookie, URL) then
begin
Cookie.Value := RawCookieValue;
CookieManager.CookieCollection.AddCookie(Cookie, URL);
end
else
Cookie.Free;
end;
end;
end;
end;
VContinue := True;
end;
Usage:
HTTP.OnHeadersAvailable := FixCookies; // Set it after object initialization
P.S. I haven't used delphi for long time, so I'm sure that code isn't perfect and lot of improvements could be done (welcome to comments), but it works.
I have no clue how it happened but using this event handler somehow brakes TIdCookieManager and Cookie.CookieCollection.Count returns 0 while there're cookies in collection which successfully added in further requests..
I have no mood to spend more time digging into Indy sources so I changed handler to modify existing cookies instead of replacing them. It doesn't brake anything (probably):
procedure TSomeObject.FixCookies(Sender: TObject; AHeaders: TIdHeaderList;
var VContinue: Boolean);
const
CookieDelimiter = ';';
QuoteChar = '"';
SpaceChar = ' ';
var
RawHeader, RawCookie, RawCookieValue, RawCookieName: string;
i, CookieDelimiterPos, CookieNamePos, CookieValuePos, CookieIndex: Integer;
begin
for i := 0 to AHeaders.Count - 1 do
begin
RawHeader := AHeaders[i];
if Pos('Set-Cookie', RawHeader) = 1 then // starts with "Set-Cookie"
begin
for CookieNamePos := Length('Set-Cookie') + 2 to Length(RawHeader) do
if RawHeader[CookieNamePos] <> SpaceChar then
Break;
RawCookie := Copy(RawHeader, CookieNamePos,
Length(RawHeader) - CookieNamePos + 1);
CookieDelimiterPos := Pos(CookieDelimiter, RawCookie);
CookieValuePos := Pos('=', RawCookie);
if (CookieDelimiterPos > 0) and (CookieValuePos > 0) then
begin
RawCookieName := Copy(RawCookie, 1, CookieValuePos - 1);
RawCookieValue := Copy(RawCookie, CookieValuePos + 1,
CookieDelimiterPos - CookieValuePos - 1);
if (Length(RawCookieValue) > 0) and (RawCookieValue[1] = QuoteChar) and
(RawCookieValue[Length(RawCookieValue)] = QuoteChar) then
RawCookieValue := Copy(RawCookieValue, 2, Length(RawCookieValue) - 2);
with (Sender as TIdHTTP) do
begin
CookieIndex := CookieManager.CookieCollection.GetCookieIndex
(RawCookieName);
if CookieIndex >= 0 then
CookieManager.CookieCollection[CookieIndex].Value := RawCookieValue
end;
end;
end;
end;
VContinue := True;
end;
P.S. Are there any Indy developers? I just a bit confused how does first handler let CookieCollection to return zero.

decoding clob in oracle and then encoding this blob in classic asp does not give the same clob

I have two column in a table whose datatype are clob and blob . I insert a clob data in clob column and insert this data to blob data by decoding this clob in oracle by the following code :
function decode_base64(p_clob_in in clob) return blob is
v_blob blob;
v_result blob;
v_offset integer;
v_buffer_size binary_integer := 48;
v_buffer_varchar varchar2(48);
v_buffer_raw raw(48);
begin
if p_clob_in is null then
return null;
end if;
dbms_lob.createtemporary(v_blob, true);
v_offset := 1;
for i in 1 .. ceil(dbms_lob.getlength(p_clob_in) / v_buffer_size) loop
dbms_lob.read(p_clob_in, v_buffer_size, v_offset, v_buffer_varchar);
v_buffer_raw := utl_raw.cast_to_raw(v_buffer_varchar);
v_buffer_raw := utl_encode.base64_decode(v_buffer_raw);
dbms_lob.writeappend(v_blob, utl_raw.length(v_buffer_raw), v_buffer_raw);
v_offset := v_offset + v_buffer_size;
end loop;
v_result := v_blob;
dbms_lob.freetemporary(v_blob);
return v_result;
end decode_base64;
Then I get this blob data in asp.net by the following code :
strSQL ="SELECT BIO_DATA FingerData , DATA_LENGTH len_of_data , SERIAL_NO sl_no FROM FP_BIOMETRIC_DATA WHERE CUST_NO =" & trim(Request("name")) & " "
Set objExec = Conn.Execute(strSQL)
fingerData1 = objExec("FingerData")
Then I am encoding this data into base64 by the following code :
Function Base64Encode(sText)
Dim oXML, oNode
Set oXML = CreateObject("Msxml2.DOMDocument.3.0")
Set oNode = oXML.CreateElement("base64")
oNode.dataType = "bin.base64"
oNode.nodeTypedValue =sText
Base64Encode = oNode.text
Set oNode = Nothing
Set oXML = Nothing
End Function
Then I am trying to compare this data and clob data in oracle database by this website . This website tells that the two data are different . Why ? Where is the error ? How can I get blob data by decoding a clob data in oracle ?
I think the problem is at this line
dbms_lob.read(p_clob_in, v_buffer_size, v_offset, v_buffer_varchar);
v_buffer_size is fixed at 48 characters, however your BASE64 string may contain NEW_LINE characters which are ignored for decoding but they are counted for v_buffer_size.
You have to remove all NEW_LINE characters before you read your buffer or increase value of v_buffer_size by number of NEW_LINE characters in substring.
Try this one:
CREATE OR REPLACE FUNCTION DecodeBASE64(InBase64Char IN OUT NOCOPY CLOB) RETURN BLOB IS
res BLOB;
clob_trim CLOB;
dest_offset INTEGER := 1;
src_offset INTEGER := 1;
read_offset INTEGER := 1;
ClobLen INTEGER;
amount INTEGER := 1440; -- must be a whole multiple of 4
buffer RAW(1440);
stringBuffer VARCHAR2(1440);
BEGIN
IF DBMS_LOB.GETLENGTH(InBase64Char) IS NULL THEN
RETURN NULL;
END IF;
-- Remove all NEW_LINE from base64 string
ClobLen := DBMS_LOB.GETLENGTH(InBase64Char);
DBMS_LOB.CREATETEMPORARY(clob_trim, TRUE);
LOOP
EXIT WHEN read_offset > ClobLen;
stringBuffer := REPLACE(REPLACE(DBMS_LOB.SUBSTR(InBase64Char, amount, read_offset), CHR(13), NULL), CHR(10), NULL);
DBMS_LOB.WRITEAPPEND(clob_trim, LENGTH(stringBuffer), stringBuffer);
read_offset := read_offset + amount;
END LOOP;
read_offset := 1;
ClobLen := DBMS_LOB.GETLENGTH(clob_trim);
DBMS_LOB.CREATETEMPORARY(res, TRUE);
LOOP
EXIT WHEN read_offset > ClobLen;
buffer := UTL_ENCODE.BASE64_DECODE(UTL_RAW.CAST_TO_RAW(DBMS_LOB.SUBSTR(clob_trim, amount, read_offset)));
DBMS_LOB.WRITEAPPEND(res, DBMS_LOB.GETLENGTH(buffer), buffer);
read_offset := read_offset + amount;
END LOOP;
RETURN res;
END DecodeBASE64;

When loading a table from a database (SQL), how do i label the columns when i'm not sure what they are?

my problem is that the table that my user will be loading, i'm not sure what they columns will be so how do define these unknown elements (columns), and also what they will be defined as (e.g. asstring, asinteger,asreal) etc
(I use SQLlite)
So here's my code
procedure TFrmsearchpage.btnloadClick(Sender: TObject);
var
con:tfdconnection;
loadquery:tfdquery;
i:integer;
j:integer;
row:integer;
col1,col2,col3,col4, col5, col6, col7 : string;
begin
con:=tfdconnection.Create(nil);
loadquery:=tfdquery.Create(con);
loadquery.Connection:=con;
con.DriverName:='SQL';
con.Open('DriverID=SQLite;Database='+Dir+'/Stock_V5;');
loadquery.SQL.Text:='SELECT * FROM ' + edtdatabasename.Text; //' Con Column';
loadquery.Open;
if loadquery.Eof then
ShowMessage('not exists')
else
ShowMessage('exists');
for i := 0 to sgdproduct.RowCount do
for j := 0 to sgdproduct.ColCount do
sgdproduct.Cells[i,j]:='';
showmessage(loadquery.SQL.Text);
Sgdproduct.colcount:=7;
sgdproduct.fixedcols:=0;
for i := 0 to 3 do
sgdproduct.colwidths[i]:=100;
sgdproduct.cells[0,0] := 'Col1'; //?
sgdproduct.cells[1,0] := 'Col2'; //?
sgdproduct.cells[2,0] := 'Col3';
sgdproduct.cells[3,0] := 'Col4'; //?
sgdproduct.cells[4,0] := 'Col5'; //?
sgdproduct.cells[5,0] := 'Col6'; //?
sgdproduct.cells[6,0] := 'Col7'; //?
row:=1;
while not loadquery.Eof do
begin
Col1:=query.FieldByName('Col1')//.As
Col2:=query.FieldByName('Col2')//.As
Col3:=query.FieldByName('Col3')//.As
Col4:=query.FieldByName('Col4')//.As
Col5:=query.FieldByName('Col5')//.As
Col6:=query.FieldByName('Col6')//.As
col7:=query.FieldByName('Col7')//.As
sgdproduct.Cells[0,row]:=Col1;
sgdproduct.Cells[1,row]:=Col2;
sgdproduct.Cells[2,row]:=Col3;
sgdproduct.Cells[3,row]:=Col4;
sgdproduct.Cells[4,row]:=Col5;
sgdproduct.Cells[5,row]:=Col6;
sgdproduct.Cells[6,row]:=Col7;
row:=row+1;
query.Next;
end;
end;
to give label in stringgrid based on Tdataset generated by your SQL, take a look at below code :
for i := 0 to DataSet.FieldCount - 1 do
begin
sgdproduct.cells[i,0] := DataSet.Fields[i].DisplayName;
end;

Resources