I am trying to insert the values from my text file to a record using app engine.
I know this could be done using file layout but my requirement suggests not to use file layout but needs to insert into record using app engine people code.
I am writing the following PeopleCode in my appengine
(here i am trying to add only one field value to my record in this example)
Local File &MYFILE;
Local Record &REC_ERN;
&MYFILE = GetFile("c:\sample.csv", "R", %FilePath_Absolute);
If &MYFILE.IsOpen Then
While &MYFILE.ReadLine(&STRING);
MessageBox(0, "", 0, 0, &STRING);
&source_type_id = Substring(&STRING, 1, 3);
&Stmt= "INSERT INTO KGS_TEST (ID) VALUES ( &source_type_id)";
SQLExec(&Stmt);
REM MessageBox(0, "", 0, 0, &source_type_id);
End-While;
End-If;
&MYFILE.Close();
The problem I am facing is &source_type_id = Substring(&STRING, 1, 3);
the variable &source_type_id has the value but i need to insert this into a record which I have created which has fields (ID,NAME,AGE,department).
The issue you are having is that your variable &source_type_id is inside a string and therefore is interpreted literally as part of the string instead of the value of the variable as you want.
What you need to do is put a bind variable in the string for the value and then pass the value as a parameter to SqlExec.
Local File &MYFILE;
&MYFILE = GetFile("c:\sample.csv", "R", %FilePath_Absolute);
If &MYFILE.IsOpen Then
While &MYFILE.ReadLine(&STRING);
MessageBox(0, "", 0, 0, &STRING);
&source_type_id = Substring(&STRING, 1, 3);
&Stmt= "INSERT INTO KGS_TEST (ID) VALUES ( :1)";
SQLExec(&Stmt,&source_type_id);
REM MessageBox(0, "", 0, 0, &source_type_id);
End-While;
End-If;
&MYFILE.Close();
Related
Have set up Always Encrypted for my table columns at server side.
From a C++ client, I use the below connection string to connect to the database:
CString connString = L"Driver={ODBC Driver 17 for SQL Server};Server=192.122.200.200,1433;Encrypt=no;Trusted_Connection=no;ColumnEncryption=Enabled;DATABASE=AlwaysEncrypted;UID=sa;PWD=;";
From the same client I invoke below command to insert data:
CString csQStrInsert = L"declare #val1 int = 3; declare #val2 int = 3; insert into [dbo].[Table_AlwaysEncrypted] ([col1], [col2]) values (#val1, #val2);";
pDatabase->ExecuteSQL(csQStrInsert);
Unfortunately the query fails with below error:
pEX->m_strError = L"Encryption scheme mismatch for columns/variables '#val1'. The encryption scheme for the columns/variables is (encryption_type = 'PLAINTEXT') and the expression near line '1' expects it to be DETERMINISTIC, or PLAIN TEXT.
What am I doing wrong?
You cannot use local variables for Always Encrypted columns, they must come from client-side parameters. In SSMS it works because SSMS parses your script and pulls out the variables into parameters, but in C++ or other clients you must parameterize it yourself.
For example, the below code is used as an example on Microsoft's website, see there for more info on how to use Always Encrypted:
SQL_DATE_STRUCT date;
SQLLEN cbdate; // size of date structure
SQLCHAR SSN[12];
strcpy_s((char*)SSN, _countof(SSN), "795-73-9838");
SQLWCHAR* firstName = L"Catherine";
SQLWCHAR* lastName = L"Abel";
SQLINTEGER cbSSN = SQL_NTS, cbFirstName = SQL_NTS, cbLastName = SQL_NTS;
// Initialize the date structure
date.day = 10;
date.month = 9;
date.year = 1996;
// Size of structures
cbdate = sizeof(SQL_DATE_STRUCT);
SQLRETURN rc = 0;
string queryText = "INSERT INTO [dbo].[Patients] ([SSN], [FirstName], [LastName], [BirthDate]) VALUES (?, ?, ?, ?) ";
rc = SQLPrepare(hstmt, (SQLCHAR *)queryText.c_str(), SQL_NTS);
//SSN
rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 11, 0, (SQLPOINTER)SSN, 0, &cbSSN);
//FirstName
rc = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_WCHAR, SQL_WCHAR, 50, 0, (SQLPOINTER)firstName, 0, &cbFirstName);
//LastName
rc = SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_WCHAR, SQL_WCHAR, 50, 0, (SQLPOINTER)lastName, 0, &cbLastName);
//BirthDate
rc = SQLBindParameter(hstmt, 4, SQL_PARAM_INPUT, SQL_C_TYPE_DATE, SQL_TYPE_DATE, 10, 0, (SQLPOINTER)&date, 0, &cbdate);
rc = SQLExecute(hstmt);
As you can see, SQLBindParameter is used to add parameters to the query. You cannot use either literals or SQL local variables to insert or compare with encrypted columns, as the server has no access to the decrypted data.
The client driver needs to have access to the relevant certificate.
sqlite3_stmt *stmt;
sqlite3_prepare_v2(db, "INSERT INTO links(NAME, LINK, SIZE, STARRED) VALUES ('?' , '?', ? , 0);", 41, &stmt, NULL);
if(stmt != NULL) {
sqlite3_bind_text(stmt, 1, name, 0, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 2, link, 0, SQLITE_TRANSIENT);
sqlite3_bind_int(stmt, 3, size);
sqlite3_step(stmt);
sqlite3_finalize(stmt);
}else{
printf("%sError during insertion in the database%s\n", RED, RST);
}
sqlite3_close(db);
I always get on the output Error during insertion in the database but can't understand why, maybe something related to sqlite3_prepare_v2 but doesn't know what, I tried to execute the query 'manually' with random data and it works.
The size of the zSql statement is 69 characters. It is is better to us -1 for length as by default it will be null-terminated string and size is automatically computed :
sqlite3_prepare_v2(db, "INSERT INTO links(NAME, LINK, SIZE, STARRED) VALUES (?, ?, ? , 0);", -1, &stmt, NULL);
Do not forget the 3rd '?' in the statement for the 3rd argument.
Edit : write it as ? in the statement
You bind twice item 2 of the statement and ? is missing for item 3.
Just solved by changing the third parameter of sqlite3_prepare_v2() that is the maximum length of zSql in bytes, and 47 is to small.
My code is like this...
char dis[20];
int tc,tac,trc;
puts("Enter the data:\n");
puts("District : ");
while((getchar())!='\n');
fgets(dis,20,stdin);
puts("Total Cases : ");
scanf("%d",&tc);
puts("Total Active Cases : ");
scanf("%d",&tac);
puts("Total Recovered Cases : ");
scanf("%d",&trc);
sql = "INSERT INTO COV VALUES (dis,tc,tac,trc);"; //won't work
sql = "INSERT INTO COV VALUES ('abc',1,1,0);"; //works
database = sqlite3_exec(db, sql,0,0,0);
I want to save the values obtained from user in sqlite database but I can't do it as shown below.
It works if I just pass the exact value (i.e. during compile time).
How can I send values computed during runtime execution to sqlite database?
Have a look to the Sqlite C interface documentation.
Assuming you have a table defined like this:
CREATE TABLE COV (id PRIMARY KEY, dis VARCHAR, tc INTEGER, tac INTEGER, trc INTEGER);
You need to bind your parameters with specific bind API to prevent SQL injection.
Prepare your INSERT string using ?N template:
char sql[512];
snprintf(sql, sizeof(sql), "INSERT INTO COV(dis, tc, tac, trc) VALUES (?1,?2,?3,?4);");
Then bind your program variables with the corresponding parameter:
sqlite3_stmt *stmt;
sqlite3_prepare_v2(db, sql, sizeof(sql), &stmt, NULL);
sqlite3_bind_text(stmt, 1, dis, 20, NULL);
sqlite3_bind_int(stmt, 2, tc);
sqlite3_bind_int(stmt, 3, tac);
sqlite3_bind_int(stmt, 4, trc);
ret = sqlite3_step(stmt);
if (ret == SQLITE_DONE)
printf("record inserted!\n");
else
printf("Error: %s\n", sqlite3_errmsg(db));
sqlite3_finalize(stmt);
You need to put the actual values in using sprintf
char sqlscript[128];
Then, since you are using sql to send to the DB, assign sqlscript to sql first
sql = sqlscript;
sprintf(sql, "INSERT INTO COV VALUES('%s', %d, %d, %d);", dis, tc, tac, trc);
I was just wondering what is this?
EXEC %%System().FireTrigger(ID = 225, ID = 102, ID = 0, ID = 0, Value = #server,
ID = -1, ID = 0, ID = 0, Value = NULL,
ID = 7, Value = #server, Value = #srvproduct2, Value = #provider, Value = #datasrc, Value = #location, Value = NULL, Value = #catalog)
I have been trying to look for it in mssql but I cant find it, what does it mean? I know EXEC is used to execute stored procedure, but what is %%System()?
and what is FireTrigger? is it an embedded command in the system? external dll? been trying to Google it but it seems to be vague at the moment.
This is an internal mechanism that is sometimes exposed but you can't call it yourself and it is undocumented.
Is it possible to iterate over a result set and if a condition is met, delete the current row?
i.e. something like
int rc;
sqlite3_stmt* statement;
sqlite3_exec(db, "BEGIN", 0, 0, 0);
sqlite3_prepare_v2(_db, "SELECT id,status,filename,del FROM mytable", -1, &statement, NULL);
rc = sqlite3_step(statement);
while (rc == SQLITE_ROW){
int id = sqlite3_column_int(statement, 1);
int status = sqlite3_column_int(statement, 2);
const unsigned char* filename = sqlite3_column_int(statement, 3);
int del = sqlite3_column_int(statement, 4);
if (status == 0 || del > 0){
int rc = unlink(filename);
if (rc == 0)
// Now delete the current row
else
// unlink failed, find out why, try again or ... ?
}
rc = sqlite3_step(statement);
}
sqlite3_finalize(statement);
sqlite3_exec(db, "COMMIT", 0, 0, 0);
I could just call a single sql statement to delete all rows that match the criteria, but I don't want to do that if for some reason the unlink fails.
Can I call an operation to delete the current row?
EDIT:
So there is a special column called rowid. Do I just add that that as a column in the
previous statement and create another statement like "delete from table where rowid=?" and pass in the current rowid?
That should work right? Is this the best way of going about it?
In terms of efficiency, it's probably not the most efficient. If you're doing this for something on the level of thousands or greater number of rows, you should consider doing one (or a combination) of the following:
Change your query to only consider rows whose del is > 0 (SELECT id,status,filename,del FROM mytable WHERE del > 0). You're performing a table scan with your current method, which you should always try to avoid. Also make sure you have an index on the del column.
Build up an intermediary array of row ids, and then perform a query of the following form: DELETE FROM table WHERE id IN (?), and the parameterized value is your collected row ids joined into a comma separated string. Based on the number of rows you're dealing with, you could set this delete to be performed in batches (delete in batch sizes of 1000, 5000, etc.); since it's SQLite, tune to the device you're running with.
Register a custom SQLite function at connection creation time using the form:
void deleteFileFunc(sqlite3_context * context, int argc, sqlite3_value ** argv) {
assert(argc == 1);
const char * fileName = sqlite3_value_text(argv[0]);
int rc = unlink(fileName);
sqlite3_result_int(context, rc);
}
sqlite3_create_function(db, "delete_file", 1, SQLITE3_UTF8, NULL, &deleteFileFunc, NULL, NULL);
and then change your database query to the form DELETE FROM mytable WHERE del > 0 AND delete_file(filename) == 0. The row will only be deleted if the delete succeeds, and you don't need to iterate over the result set. SQLite 3 create function page: http://www.sqlite.org/c3ref/create_function.html
it's OK to delete the row directly.
the doc says it doesn't interfere the running SELECT to delete a row which has already been read.
but the result is undefined if a future row that is expected to be read later is deleted.
https://www.sqlite.org/isolation.html