Why LOAD DATA LOCAL INFILE will work from the CLI but not in application? - c++

The problem:
My C++ application connects to a MySQL server, reads the first/header line of each db export.txt, makes a create table statement to prepare for the import and executes that against the database (no problem with that, the table appears just as intended) -- but when I try and execute the LOAD DATA LOCAL INFILE to import the data into the newly created table, I get the error "The used command is not allowed with this MySQL version". But, this works on the CLI! When I execute this command on the CLI using mysql -u <user> -p<password> -e "LOAD DATA LOCAL INFILE 'myfile.txt' INTO TABLE mytable FIELDS TERMINATED BY '|' LINES TERMINATED BY '\r\n';" it works flawlessly?
The Situation:
My company gets a large quantity of database exports (160 files/10gb of .txt files that are '|' delimited) from our vendors on a monthly basis that have to replace the old vendor lists. I am working on a smallish C++ app to deal with it on my work desktop. The application is meant to set up the required tables, import the data, then execute a series of intermediate queries against multiple tables to assemble information in a series of final tables, which is then itself exported and uploaded to the production environment, for use in the companies e-commerce website.
My Setup:
Ubuntu 12.04
MySQL Server v. 5.5.29 + MySQL Command Line client
Linux GNU C++ Compiler
libmysqlcppconn is installed and I have the required mysqlconn library linked in.
I have already overcome/tried the following issues/combinations:
1.) I have already discovered (the hard way) that LOAD DATA [LOCAL] INFILE statements must be enabled in the config -- I have the "local-infile" option set in the configuration files for both client and server. (fixed by updating the /etc/mysql/my.cnf with "local-infile" statements for the client and server. NOTE: I could have used the --local-infile=1 to restart the mysql-server, but this is my local dev environment so I just wanted it turned on permanently)
2.) LOAD DATA LOCAL INFILE seems to fail to perform the import (from the CLI) if the target import file does not have execute permissions enabled (fixed with chmod +x target_file.txt)
3.) I am using the mysql root account in my application code (because its my localhost, not production and this particular program will never run on a production server.)
4.) I have tried executing my compiled binary program using the sudo command (no change, same error "The used command is not allowed with this MySQL version")
5.) I have tried changing the ownership of the binary file from my normal login to root (no change, same error "The used command is not allowed with this MySQL version")
6.) I know the libcppmysqlconn is working because I am able to connect and perform the CREATE TABLE call without a problem, and I can do other queries and execute statements
What am I missing? Any suggestions? Thanks in advance :)

After much diligent trial and error working with the /etc/mysql/my.cfg file (I know this is a permissions issue because it works on the command line, but not from the connector) and after much googling and finding some back alley tech support posts I've come to conclude that the MySQL C++ connector did not (for whatever reason) decide to implement the ability for developers to be able to allow the local-infile=1 option from the C++ connector.
Apparently some people have been able to hack/fork the MySQL C++ connector to expose the functionality, but no one posted their source code -- only said it worked. Apparently there is a workaround in the MySQL C API after you initialize the connection you would use this:
mysql_options( &mysql, MYSQL_OPT_LOCAL_INFILE, 1 );
which apparently allows the LOAD DATA LOCAL INFILE statements to work with the MySQL C API.
Here are some reference articles that lead me to this conclusion:
1.) How can I get the native C API connection structure from MySQL Connector/C++?
2.) Mysql 5.5 LOAD DATA INFILE Permissions
3.) http://osdir.com/ml/db.mysql.c++/2004-04/msg00097.html
Essentially if you want the ability to use the LOAD DATA LOCAL INFILE functionality from a programmatic Connector API -- you have to use the mysql C API or hack/fork the existing mysql C++ api to expose the connection structure. Or just stick to executing the LOAD DATA LOCAL INFILE from the command line :(

Related

Internal Error in Redmine Initialization phase

I'm trying to setup Redmine on the following products
redmine-4.0.7
Rails 5.2.4.2
Phusion Passenger 6.0.7
Apache/2.4.6
mysql Ver 14.14
I expected there will be initializing page however, I got `Internal Error' from http://mydomain/redmine/
I can see the following messages in log/prduction.log
Completed 500 Internal Server Error in 21ms (ActiveRecord: 1.5ms)
ActiveRecord::StatementInvalid (Mysql2::Error: Can't find file: './redmine/settings.frm' (errno: 13 - Permission denied): SHOW FULL FIELDS FROM `settings`):
It seems I need ./redmine/settings.frm but there isn't.
Does anyone know how to place ./redmine/settings.frm and what content should be in?
The error is thrown by your database server (i.e. MySQL). It seems that MySQL does not have the required permission to access the files where it stores the table data.
Usually, those files are handled (i.e. created, updated, and eventually deleted) entirely by MySQL which requires specific access patterns to ensure consistent data. Because of that, you should strongly avoid to manually change any files under control of MySQL. Instead, you should only use SQL commands to update table structures and table data.
o fix this issue now, you need to fix the permissions of your MySQL data files so that MySQL can properly access them. What exactly is required here is unfortunately not simply explained since there can be various causes. If you have jsut setup your MySQL server, it might be best start entirely new.

How to skip slave replication errors on Google Cloud SQL 2nd Gen

I am in the process of migrating a database from an external server to cloud sql 2nd gen. Have been following the recommended steps and the 2TB mysqlsump process was complete and replication started. However, got an error:
'Error ''Access denied for user ''skip-grants user''#''skip-grants host'' (using password: NO)'' on query. Default database: ''mondovo_db''. Query: ''LOAD DATA INFILE ''/mysql/tmp/SQL_LOAD-0a868f6d-8681-11e9-b5d3-42010a8000a8-6498057-322806.data'' IGNORE INTO TABLE seoi_volume_update_tracker FIELDS TERMINATED BY ''^#^'' ENCLOSED BY '''' ESCAPED BY ''\'' LINES TERMINATED BY ''^|^'' (keyword_search_volume_id)'''
2 questions,
1) I'm guessing the error has come about because cloud sql requires LOAD DATA LOCAL INFILE instead of LOAD DATA INFILE? However am quite sure on the master we run only LOAD DATA LOCAL INFILE so not sure how it changes to remove LOCAL while in replication, is that possible?
2) I can't stop the slave to skip the error and restart since SUPER privileges aren't available and so am not sure how to skip this error and also avoid it for the future while the the final sync happens. Suggestions?
There was no way to work around the slave replication error in Google Cloud SQL, so had to come up with another way.
Since replication wasn't going to work, I had to do a copy of all the databases. However, because of the aggregate size of all my DBs being at 2TB, it was going to take a long time.
The final strategy that took the least amount of time:
1) Pre-requisite: You need to have at least 1.5X the amount of current database size in terms of disk space remaining on your SQL drive. So my 2TB DB was on a 2.7TB SSD, I needed to eventually move everything temporarily to a 6TB SSD before I could proceed with the steps below. DO NOT proceed without sufficient disk space, you'll waste a lot of your time as I did.
2) Install cloudsql-import on your server. Without this, you can't proceed and this took a while for me to discover. This will facilitate in the quick transfer of your SQL dumps to Google.
3) I had multiple databases to migrate. So if in a similar situation, pick one at a time and for the sites that access that DB, prevent any further insertions/updates. I needed to put a "Website under Maintenance" on each site, while I executed the operations outlined below.
4) Run the commands in the steps below in a separate screen. I launched a few processes in parallel on different screens.
screen -S DB_NAME_import_process
5) Run a mysqldump using the following command and note, the output is an SQL file and not a compressed file:
mysqldump {DB_NAME} --hex-blob --default-character-set=utf8mb4 --skip-set-charset --skip-triggers --no-autocommit --single-transaction --set-gtid-purged=off > {DB_NAME}.sql
6) (Optional) For my largest DB of around 1.2TB, I also split the DB backup into individual table SQL files using the script mentioned here: https://stackoverflow.com/a/9949414/1396252
7) For each of the files dumped, I converted the INSERT commands into INSERT IGNORE because didn't want any further duplicate errors during the import process.
cat {DB_OR_TABLE_NAME}.sql | sed s/"^INSERT"/"INSERT IGNORE"/g > new_{DB_OR_TABLE_NAME}_ignore.sql
8) Create a database by the same name on Google Cloud SQL that you want to import. Also create a global user that has permission to access all the databases.
9) Now, we import the SQL files using the cloudsql-import plugin. If you split the larger DB into individual table files in Step 6, use the cat command to combine a batch of them into a single file and make as many batch files as you see appropriate.
Run the following command:
cloudsql-import --dump={DB_OR_TABLE_NAME}.sql --dsn='{DB_USER_ON_GLCOUD}:{DB_PASSWORD}#tcp({GCLOUD_SQL_PUBLIC_IP}:3306)/{DB_NAME_CREATED_ON_GOOGLE}'
10) While the process is running, you can step out of the screen session using Ctrl+a
+ Ctrl+d (or refer here) and then reconnect to the screen later to check on progress. You can create another screen session and repeat the same steps for each of the DBs/batches of tables that you need to import.
Because of the large sizes that I had to import, I believe it did take me a day or two, don't remember now since it's been a few months but I know that it's much faster than any other way. I had tried using Google's copy utility to copy the SQL files to Cloud Storage and then use Cloud SQL's built-in visual import tool but that was slow and not as fast as cloudsql-import. I would recommend this method up until Google fixes the ability to skip slave errors.

how can I use R Studio data in shinyServer

In my local machine I use RStudio + Shiny to work properly.
Now that I have Shiny-Server installed on linux, but I do not know the Data generated by RStudiom.
how can I get Shiny-Server to read it?
Do not know what keyword query?
Thanks
Importing data in the server
As I see it, there are two ways to supply data in this situation.
The first one is to upload the data to the server where your shiny-apps are hosted. This can be done via ssh (wget) or something like FileZilla. You can put your data in the same folder as the app and then access them with relative paths. For example if you have
- app-folder
- app.R
- data.rds
- more_data.csv
You can use readRDS("data.rds") or readr::read_csv2("more_data.csv") in app.R to use the data in the app.
The second option is to use fileInput inside your app. This will give you the option to upload data from your local machine in the GUI. This data will then be put onto the server temporarilly. See ?shiny::fileInput.
Exporting data from RStudio
There are numerous ways to do this. You can use save to write your whole workspace to disk. If you just want to save single objects, saveRDS is quite handy. If you want to save datasets (for example data.frames) you can also use readr::write_csv or similar functions.

Creating triggers using embedded mysql C++

I am working with the libmysqld c library in a C++ application on windows in order to interface with an embedded mysql server i.e. a mysql server that is online for the lifetime of the process that embeds it. The application that creates the database uses a mysql .ini file for creating the datadir relative to the application directory instead of in the global mysql install folder e.g.
[libmysqld_server]
basedir=./
datadir=./Database
I can programatically create a trigger with no problem e.g.
status = mysql_query(mysql,
"CREATE TRIGGER del_trigger AFTER DELETE ON table FOR EACH ROW\
INSERT INTO otherTable (col1, col2) VALUES (OLD.col1, OLD.col2)\
");
if (status == 0) {
Log(DEBUG, "Initialize(): <%p> Delete Trigger creation passed ...", this);
}
else {
Log(DEBUG, "Initialize(): <%p> Delete Trigger creation failed with error %s...", this, mysql_error(mysql));
}
The problem I run into however is that when the trigger gets called, mysql will complain that the mysql.proc table does not exist because I do not have a mysql database inside my application specific datadir. I have tried copying the mysql folder from the installation directory in C:\Program Files\MySQL... but then I run into issues where mysql reports
Error:Cannot load from mysql.proc. The table is probably corrupted
The only advice I have seen related to the above error is to run the 'mysql_upgrade' command which does not seem to work for the case of an embedded database using its own datadir. I'm at the point where all of the tables are created and their respective triggers are setup but just can't get around this mysql.proc error.
UPDATE:
I am also seeing some inconsistent behavior here. My version of MySQL is "mysql-5.5.16-win32" and it comes with a mysql_embedded.exe binary that I can use to open up a console and point to the database files generated by my application when it isn't running. When I perform operations in the mysql_embedded.exe, the triggers work without issue (no 'mysql.proc is probably corrupted' errors). So it seems like only the libmysqld c api is having an issue with the mysql system tables.
The solution was as simple as verifying that the "mysql" database was the same version as mysql version embedded in libmysqld. I verified my client version info via the following:
const char * version = mysql_get_client_info();
This returned "5.1.44" instead of the "5.5.16" that I was expecting. Downloading the mysql ZIP archive for 5.1.44 and using the mysql database in the datadir fixed the issue that I was experiencing.

How to programmatically dump Launch Services database?

How can I programmatically dump/query Launch Services database in MacOS (i.e. analog of command lsregister -dump)?
EDIT: I want to get set of associations UTI -> Bundle_IDs. Using LSCopyAllRoleHandlersForContentType - does not always work, here a similar trouble, therefore concluded that the best working method - parsing the output of "lsregister -dump", but the location of lsregister changes from version to version.