Author: Michael McLaughlin

MySQL on Fedora 27

While updating my class image to Fedora 27, I noticed that it installed the Akonadi Server. The documentation on the Akonadi server lacked some straightforward documentation. It also offered a bundled set of software that limited how to approach MySQL development.
So, I removed all those packages with the following syntax:

dnf remove `rpm -qa | grep akonadi`

After removing those Akonadi packages, I installed the MySQL Community Edition from the Fedora repo with this syntax:

yum install -y community-mysql*

Having installed MySQL Community Edition, I started the service with this command:

sudo service mysql start

Then, I ran the mysql_secure_installation script to secure the installation:

mysql_secure_installation

The script set the root user’s password, remove the anonymous user, disallow remote root login, and remove the test databases. Then, I verified connecting to the MySQL database with the following syntax:

mysql -uroot -ppassword

I enabled the MySQL Service to start with each reboot of the Fedora instance. I used the following command:

systemctl enable mysqld.service

It creates the following link:

ln -s ‘/etc/systemd/system/multi-user.target.wants/mysqld.service’ ‘/usr/lib/systemd/system/mysqld.service’

Now, I need to install and configure Apache, PHP, and upgrade Oracle Database 11g XE’s APEX 4 to 5.

External Tables + Merge

This is an example of how you would upload data from a flat file, or Comma Separated Value (CSV) file. It’s important to note that in the file upload you are transferring information that doesn’t have surrogate key values by leveraing joins inside a MERGE statement.

Step #1 : Create a virtual directory
You can create a virtual directory without a physical directory but it won’t work when you try to access it. Therefore, you should create the physical directory first. Assuming you’ve created a /u01/app/oracle/upload file directory on the Windows platform, you can then create a virtual directory and grant permissions to the student user as the SYS privileged user.
The syntax for these steps is:

CREATE DIRECTORY upload AS ‘/u01/app/oracle/upload’;
GRANT READ, WRITE ON DIRECTORY upload TO student;

Step #2 : Position your CSV file in the physical directory
After creating the virtual directory, copy the following contents into a file named kingdom_import.csv in the /u01/app/oracle/upload directory or folder. If you attempt to do this in Windows, you need to disable Windows UAC before performing this step.
Place the following in the kingdom_import.csv file. The trailing commas aren’t too meaningful in Oracle but they’re very helpful if you use the file in MySQL. A key element in creating this files requires that you avoid trailing line returns at the bottom of the file because they’re inserted as null values. There should be no lines after the last row of data.

‘Narnia’,77600,’Peter the Magnificent’,’20-MAR-1272′,’19-JUN-1292′,
‘Narnia’,77600,’Edmund the Just’,’20-MAR-1272′,’19-JUN-1292′,
‘Narnia’,77600,’Susan the Gentle’,’20-MAR-1272′,’19-JUN-1292′,
‘Narnia’,77600,’Lucy the Valiant’,’20-MAR-1272′,’19-JUN-1292′,
‘Narnia’,42100,’Peter the Magnificent’,’12-APR-1531′,’31-MAY-1531′,
‘Narnia’,42100,’Edmund the Just’,’12-APR-1531′,’31-MAY-1531′,
‘Narnia’,42100,’Susan the Gentle’,’12-APR-1531′,’31-MAY-1531′,
‘Narnia’,42100,’Lucy the Valiant’,’12-APR-1531′,’31-MAY-1531′,
‘Camelot’,15200,’King Arthur’,’10-MAR-0631′,’12-DEC-0686′,
‘Camelot’,15200,’Sir Lionel’,’10-MAR-0631′,’12-DEC-0686′,
‘Camelot’,15200,’Sir Bors’,’10-MAR-0631′,’12-DEC-0635′,
‘Camelot’,15200,’Sir Bors’,’10-MAR-0640′,’12-DEC-0686′,
‘Camelot’,15200,’Sir Galahad’,’10-MAR-0631′,’12-DEC-0686′,
‘Camelot’,15200,’Sir Gawain’,’10-MAR-0631′,’12-DEC-0686′,
‘Camelot’,15200,’Sir Tristram’,’10-MAR-0631′,’12-DEC-0686′,
‘Camelot’,15200,’Sir Percival’,’10-MAR-0631′,’12-DEC-0686′,
‘Camelot’,15200,’Sir Lancelot’,’30-SEP-0670′,’12-DEC-0682′,

Step #3 : Reconnect as the student user
Disconnect and connect as the student user, or reconnect as the student user. The reconnect syntax that protects your password is:

CONNECT student@xe

Step #4 : Run the script that creates tables and sequences
Copy the following into a create_kingdom_upload.sql file within a directory of your choice. Then, run it as the student account.

— Conditionally drop tables and sequences.
BEGIN
FOR i IN (SELECT table_name
FROM user_tables
WHERE table_name IN (‘KINGDOM’,’KNIGHT’,’KINGDOM_KNIGHT_IMPORT’)) LOOP
EXECUTE IMMEDIATE ‘DROP TABLE ‘||i.table_name||’ CASCADE CONSTRAINTS’;
END LOOP;
FOR i IN (SELECT sequence_name
FROM user_sequences
WHERE sequence_name IN (‘KINGDOM_S1′,’KNIGHT_S1’)) LOOP
EXECUTE IMMEDIATE ‘DROP SEQUENCE ‘||i.sequence_name;
END LOOP;
END;
/

— Create normalized kingdom table.
CREATE TABLE kingdom
( kingdom_id NUMBER
, kingdom_name VARCHAR2(20)
, population NUMBER);

— Create a sequence for the kingdom table.
CREATE SEQUENCE kingdom_s1;

— Create normalized knight table.
CREATE TABLE knight
( knight_id NUMBER
, knight_name VARCHAR2(24)
, kingdom_allegiance_id NUMBER
, allegiance_start_date DATE
, allegiance_end_date DATE);

— Create a sequence for the knight table.
CREATE SEQUENCE knight_s1;

— Create external import table.
CREATE TABLE kingdom_knight_import
( kingdom_name VARCHAR2(20)
, population NUMBER
, knight_name VARCHAR2(24)
, allegiance_start_date DATE
, allegiance_end_date DATE)
ORGANIZATION EXTERNAL
( TYPE oracle_loader
DEFAULT DIRECTORY upload
ACCESS PARAMETERS
( RECORDS DELIMITED BY NEWLINE CHARACTERSET US7ASCII
BAFFLE ‘UPLOAD’:’kingdom_import.bad’
DISCARDFILE ‘UPLOAD’:’kingdom_import.dis’
LOGFILE ‘UPLOAD’:’kingdom_import.log’
FIELDS TERMINATED BY ‘,’
OPTIONALLY ENCLOSED BY “‘”
MISSING FIELD VALUES ARE NULL )
LOCATION (‘kingdom_import.csv’))
REJECT LIMIT UNLIMITED;

Step #5 : Test your access to the external table
There a number of things that could go wrong with setting up an external table, such as file permissions. Before moving on to the balance of the steps, you should test what you’ve done. Run the following query from the student account to check whether or not you can access the kingdom_import.csv file.

COL kingdom_name FORMAT A8 HEADING “Kingdom|Name”
COL population FORMAT 99999999 HEADING “Population”
COL knight_name FORMAT A30 HEADING “Knight Name”
SELECT kingdom_name
, population
, knight_name
, TO_CHAR(allegiance_start_date,’DD-MON-YYYY’) AS allegiance_start_date
, TO_CHAR(allegiance_end_date,’DD-MON-YYYY’) AS allegiance_end_date
FROM kingdom_knight_import;

Step #6 : Create the upload procedure
Copy the following into a create_upload_procedure.sql file within a directory of your choice. Then, run it as the student account.

— Create a procedure to wrap the transaction.
CREATE OR REPLACE PROCEDURE upload_kingdom IS
BEGIN
— Set save point for an all or nothing transaction.
SAVEPOINT starting_point;

— Insert or update the table, which makes this rerunnable when the file hasn’t been updated.
MERGE INTO kingdom target
USING (SELECT DISTINCT
k.kingdom_id
, kki.kingdom_name
, kki.population
FROM kingdom_knight_import kki LEFT JOIN kingdom k
ON kki.kingdom_name = k.kingdom_name
AND kki.population = k.population) source
ON (target.kingdom_id = source.kingdom_id)
WHEN MATCHED THEN
UPDATE SET kingdom_name = source.kingdom_name
WHEN NOT MATCHED THEN
INSERT VALUES
( kingdom_s1.nextval
, source.kingdom_name
, source.population);

— Insert or update the table, which makes this rerunnable when the file hasn’t been updated.
MERGE INTO knight target
USING (SELECT kn.knight_id
, kki.knight_name
, k.kingdom_id
, kki.allegiance_start_date AS start_date
, kki.allegiance_end_date AS end_date
FROM kingdom_knight_import kki INNER JOIN kingdom k
ON kki.kingdom_name = k.kingdom_name
AND kki.population = k.population LEFT JOIN knight kn
ON k.kingdom_id = kn.kingdom_allegiance_id
AND kki.knight_name = kn.knight_name
AND kki.allegiance_start_date = kn.allegiance_start_date
AND kki.allegiance_end_date = kn.allegiance_end_date) source
ON (target.kingdom_allegiance_id = source.kingdom_id)
WHEN MATCHED THEN
UPDATE SET allegiance_start_date = source.start_date
, allegiance_end_date = source.end_date
WHEN NOT MATCHED THEN
INSERT VALUES
( knight_s1.nextval
, source.knight_name
, source.kingdom_id
, source.start_date
, source.end_date);

— Save the changes.
COMMIT;

EXCEPTION
WHEN OTHERS THEN
ROLLBACK TO starting_point;
RETURN;
END;
/

Step #7 : Run the upload procedure
You can run the file by calling the stored procedure built by the script. The procedure ensures that records are inserted or updated into their respective tables.

EXECUTE upload_kingdom;

Step #8 : Test the results of the upload procedure
You can test whether or not it worked by running the following queries.

— Check the kingdom table.
SELECT * FROM kingdom;

— Format Oracle output.
COLUMN knight_id FORMAT 999 HEADING “Knight|ID #”
COLUMN knight_name FORMAT A23 HEADING “Knight Name”
COLUMN kingdom_allegiance_id FORMAT 999 HEADING “Kingdom|Allegiance|ID #”
COLUMN allegiance_start_date FORMAT A11 HEADING “Allegiance|Start Date”
COLUMN allegiance_end_date FORMAT A11 HEADING “Allegiance|End Date”
SET PAGESIZE 999

— Check the knight table.
SELECT knight_id
, knight_name
, kingdom_allegiance_id
, TO_CHAR(allegiance_start_date,’DD-MON-YYYY’) AS allegiance_start_date
, TO_CHAR(allegiance_end_date,’DD-MON-YYYY’) AS allegiance_end_date
FROM knight;

It should display the following information:

KINGDOM_ID KINGDOM_NAME POPULATION
———- ——————– ———-
1 Narnia 42100
2 Narnia 77600
3 Camelot 15200

Kingdom
Knight Allegiance Allegiance Allegiance
ID # Knight Name ID # Start Date End Date
—— ———————– ———- ———– ———–
1 Peter the Magnificent 2 20-MAR-1272 19-JUN-1292
2 Edmund the Just 2 20-MAR-1272 19-JUN-1292
3 Susan the Gentle 2 20-MAR-1272 19-JUN-1292
4 Lucy the Valiant 2 20-MAR-1272 19-JUN-1292
5 Peter the Magnificent 1 12-APR-1531 31-MAY-1531
6 Edmund the Just 1 12-APR-1531 31-MAY-1531
7 Susan the Gentle 1 12-APR-1531 31-MAY-1531
8 Lucy the Valiant 1 12-APR-1531 31-MAY-1531
9 King Arthur 3 10-MAR-0631 12-DEC-0686
10 Sir Lionel 3 10-MAR-0631 12-DEC-0686
11 Sir Bors 3 10-MAR-0631 12-DEC-0635
12 Sir Bors 3 10-MAR-0640 12-DEC-0686
13 Sir Galahad 3 10-MAR-0631 12-DEC-0686
14 Sir Gawain 3 10-MAR-0631 12-DEC-0686
15 Sir Tristram 3 10-MAR-0631 12-DEC-0686
16 Sir Percival 3 10-MAR-0631 12-DEC-0686
17 Sir Lancelot 3 30-SEP-0670 12-DEC-0682

You can rerun the procedure to check that it doesn’t alter any information, then you could add a new knight to test the insertion portion.

Cassandra Query Language

After installing Cassandra and reading Cassandra The Definitive Guide, it struck me that I should learn a bit more about the Cassandra Query Language (CQL). So, after I setup a single-node environment and created a .bashcassandra environment file to connect as a student user to the Cassandra instance:

# Add the Java and JRE paths to the $PATH environments.
export set PATH=$PATH:/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.45.x86_64:/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.45.x86_64/jre

# Add the $JAVA_HOME and $JRE_HOME environment variables.
export set JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.45.x86_64/
export set JRE_HOME=/usr

Having started Cassandra as the cassandra user, I connected to the Cassandra Query Language Shell (cqlsh) to learn how to write CQL. You can find the basic structure of the Cassandra Query Language (CQL) on the Apache Cassandra website. I also discovered that CQL by itself can’t let you join tables without using Apache SparkSQL. Apache SparkSQL adds the ability to perform CQL joins in Cassandra, and became available in 2015.
I also learned you can’t use a CREATE OR REPLACE command when you change certain aspects of User-Defined Functions (UDFs). You actually need to drop any UDF before you change RETURNS NULL ON NULL INPUT clause to a CALLED ON NULL INPUT clause or vice versa. You can’t embed Java that connects to database without using the cassandra-java-driver-2.0.2 driver.
You connect to the cqlsh like this:

cqlsh

Here’s my script that creates Cassandra keyspace, which is more or less a database. You use the USE command to connect to the keyspace or database, like you would in MySQL. You do not have sequences in Cassandra because they’re not a good fit for a distributed architecture. Cassandra does not support a native procedural extension like relational databases. You must create User-defined functions (UDFs) by embedding the logic in Java.
This script does the following:

Creates a keyspace

Uses the keyspace

Conditionally drops tables and functions
Creates two tables
Inserts data into the two tables
Queries data from the tables

I also included a call to a UDF inside a query in two of the examples. One of the queries demonstrates how to return a JSON structure from a query. To simplify things and provide clarification of the scripts behaviors, the details are outlined below.

The first segment of the script creates the keyspace, changes the scope to use the keyspace, conditionally drop tables, create tables, and insert values into the tables:

/* Create a keyspace in Cassandra, which is like a database
in MySQL or a schema in Oracle. */
CREATE KEYSPACE IF NOT EXISTS student
WITH REPLICATION = {
‘class’:’SimpleStrategy’
,’replication_factor’: 1 }
AND DURABLE_WRITES = true;

/* Use the keyspace or connect to the database. */
USE student;

/* Drop the member table from the student keyspace. */
DROP TABLE IF EXISTS member;

/* Create a member table in the student keyspace. */
CREATE TABLE member
( member_number VARCHAR
, member_type VARCHAR
, credit_card_number VARCHAR
, credit_card_type VARCHAR
, PRIMARY KEY ( member_number ));

/* Conditionally drop the contact table from the student keyspace. */
DROP TABLE IF EXISTS contact;

/* Create a contact table in the student keyspace. */
CREATE TABLE contact
( contact_number VARCHAR
, contact_type VARCHAR
, first_name VARCHAR
, middle_name VARCHAR
, last_name VARCHAR
, member_number VARCHAR
, PRIMARY KEY ( contact_number ));

/* Insert a row into the member table. */
INSERT INTO member
( member_number, member_type, credit_card_number, credit_card_type )
VALUES
(‘SFO-12345′,’GROUP’,’2222-4444-5555-6666′,’VISA’);

/* Insert a row into the contact table. */
INSERT INTO contact
( contact_number, contact_type, first_name, middle_name, last_name, member_number )
VALUES
(‘CUS_00001′,’FAMILY’,’Barry’, NULL,’Allen’,’SFO-12345′);

/* Insert a row into the contact table. */
INSERT INTO contact
( contact_number, contact_type, first_name, middle_name, last_name, member_number )
VALUES
(‘CUS_00002′,’FAMILY’,’Iris’, NULL,’West-Allen’,’SFO-12345′);

/* Insert a row into the member table. */
INSERT INTO member
( member_number, member_type, credit_card_number, credit_card_type )
VALUES
(‘SFO-12346′,’GROUP’,’3333-8888-9999-2222′,’VISA’);

/* Insert a row into the contact table. */
INSERT INTO contact
( contact_number, contact_type, first_name, middle_name, last_name, member_number )
VALUES
(‘CUS_00003′,’FAMILY’,’Caitlin’,’Marie’,’Snow’,’SFO-12346′);

The following queries the member table:

/* Select all columns from the member table. */
SELECT * FROM member;

It returns the following:

member_number | credit_card_number | credit_card_type | member_type
—————+———————+——————+————-
SFO-12345 | 2222-4444-5555-6666 | VISA | GROUP
SFO-12346 | 3333-8888-9999-2222 | VISA | GROUP

Create a concatenate User-defined function (UDF) for Cassandra. The first step requires you to edit the cassandra.yaml file, which you find in the /etc/cassandra/default.conf directory. There is a single parameter that you need to edit, and it is the enable_user_defined_functions parameter. By default the parameter is set to false, and you need to enable it to create UDFs.

After you make the edit, the cassandra.yaml file should look like this:

# If unset, all GC Pauses greater than gc_log_threshold_in_ms will log at
# INFO level
# UDFs (user defined functions) are disabled by default.
# As of Cassandra 3.0 there is a sandbox in place that should prevent execution of evil code.
enable_user_defined_functions: true

After you make the change, you can create your own UDF. The following UDF formats the first, middle, and last name so there’s only one whitespace between the first and last name when there middle name value is null.
This type of function must use a CALLED ON NULL INPUT clause in lieu of a RETURNS NULL ON NULL INPUT clause. The latter would force the function to return a null value if any one of the parameters were null.

/* Drop the concatenate function because a replace disallows changing a
RETURNS NULL ON NULL INPUT with a CALLED ON NULL INPUT without raising
an “89: InvalidRequest” exception. */
DROP FUNCTION concatenate;

/* Create a user-defined function to concatenate names. */
CREATE OR REPLACE FUNCTION concatenate (first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR)
CALLED ON NULL INPUT
RETURNS VARCHAR
LANGUAGE java
AS $$
/* Concatenate first and last names when middle name is null, and
first, middle, and last names when middle name is not null. */
String name;

/* Check for null middle name. */
if (middle_name == null) {
name = first_name + ” ” + last_name; }
else {
name = first_name + ” ” + middle_name + ” ” + last_name; }

return name;
$$;

Query the values from the contact table with the UDF function in the SELECT-list:

/* Query the contact information. */
SELECT member_number
, contact_number
, contact_type
, concatenate(first_name, middle_name, last_name) AS full_name
FROM contact;

It returns the following:

member_number | contact_number | contact_type | full_name
—————+—————-+————–+——————–
SFO-12345 | CUS_00001 | FAMILY | Barry Allen
SFO-12345 | CUS_00002 | FAMILY | Iris West-Allen
SFO-12346 | CUS_00003 | FAMILY | Caitlin Marie Snow

Query the values from the contact table with a JSON format:

/* Query the contact information and return in a JSON format. */
SELECT JSON
contact_number
, contact_type
, concatenate(first_name, middle_name, last_name) AS full_name
FROM contact;

It returns the following:

[json]
————————————————————————————————-
{“contact_number”: “CUS_00001”, “contact_type”: “FAMILY”, “full_name”: “Barry Allen”}
{“contact_number”: “CUS_00002”, “contact_type”: “FAMILY”, “full_name”: “Iris West-Allen”}
{“contact_number”: “CUS_00003”, “contact_type”: “FAMILY”, “full_name”: “Caitlin Marie Snow”}

You can call the script from a relative directory inside cqlsh, like this:

source ‘cstudent.cql’

At the end of the day, the concept of adding and removing nodes is attractive. Though, the lack of normal relational mechanics and narrowly supported set of CQL semantics leaves me with open questions. For example, is clustering without a coordinator really valuable enough to settle for eventual, or tunable, consistency with such a narrowly scoped query language?
As always, I hope this helps those looking for a quick how-to on Cassandra.

Install EasyGUI on Fedora

The EasyGUI library is a nice tool for developing GUI applications. It doesn’t require you to know event-driven programming to write basic GUI applications because it’s based on Python functions.
You can download and install the EasyGUI library with yum utility like this:

yum install -y python-easygui

It should generate the following list:

Loaded plugins: langpacks, refresh-packagekit
mysql-connectors-community | 2.5 kB 00:00
mysql-tools-community | 2.5 kB 00:00
mysql56-community | 2.5 kB 00:00
pgdg93 | 3.6 kB 00:00
updates/20/x86_64/metalink | 2.8 kB 00:00
Resolving Dependencies
–> Running transaction check
—> Package python-easygui.noarch 0:0.96-7.fc20 will be installed
–> Processing Dependency: tkinter for package: python-easygui-0.96-7.fc20.noarch
–> Processing Dependency: python-setuptools for package: python-easygui-0.96-7.fc20.noarch
–> Running transaction check
—> Package python-setuptools.noarch 0:1.4.2-1.fc20 will be installed
—> Package tkinter.x86_64 0:2.7.5-16.fc20 will be installed
–> Processing Dependency: libtk8.5.so()(64bit) for package: tkinter-2.7.5-16.fc20.x86_64
–> Processing Dependency: libtcl8.5.so()(64bit) for package: tkinter-2.7.5-16.fc20.x86_64
–> Processing Dependency: libTix.so()(64bit) for package: tkinter-2.7.5-16.fc20.x86_64
–> Running transaction check
—> Package tcl.x86_64 1:8.5.14-1.fc20 will be installed
—> Package tix.x86_64 1:8.4.3-11.fc20 will be installed
—> Package tk.x86_64 1:8.5.14-1.fc20 will be installed
–> Finished Dependency Resolution

Dependencies Resolved

================================================================================
Package Arch Version Repository Size
================================================================================
Installing:
python-easygui noarch 0.96-7.fc20 fedora 481 k
Installing for dependencies:
python-setuptools noarch 1.4.2-1.fc20 updates 413 k
tcl x86_64 1:8.5.14-1.fc20 fedora 1.9 M
tix x86_64 1:8.4.3-11.fc20 fedora 253 k
tk x86_64 1:8.5.14-1.fc20 fedora 1.4 M
tkinter x86_64 2.7.5-16.fc20 updates 316 k

Transaction Summary
================================================================================
Install 1 Package (+5 Dependent packages)

Total download size: 4.7 M
Installed size: 13 M
Downloading packages:
(1/6): python-setuptools-1.4.2-1.fc20.noarch.rpm | 413 kB 00:00
(2/6): python-easygui-0.96-7.fc20.noarch.rpm | 481 kB 00:00
(3/6): tkinter-2.7.5-16.fc20.x86_64.rpm | 316 kB 00:00
(4/6): tix-8.4.3-11.fc20.x86_64.rpm | 253 kB 00:01
(5/6): tcl-8.5.14-1.fc20.x86_64.rpm | 1.9 MB 00:01
(6/6): tk-8.5.14-1.fc20.x86_64.rpm | 1.4 MB 00:03
——————————————————————————–
Total 1.5 MB/s | 4.7 MB 00:03
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction (shutdown inhibited)
Installing : 1:tcl-8.5.14-1.fc20.x86_64 1/6
Installing : 1:tk-8.5.14-1.fc20.x86_64 2/6
Installing : 1:tix-8.4.3-11.fc20.x86_64 3/6
Installing : tkinter-2.7.5-16.fc20.x86_64 4/6
Installing : python-setuptools-1.4.2-1.fc20.noarch 5/6
Installing : python-easygui-0.96-7.fc20.noarch 6/6
Verifying : 1:tk-8.5.14-1.fc20.x86_64 1/6
Verifying : tkinter-2.7.5-16.fc20.x86_64 2/6
Verifying : 1:tix-8.4.3-11.fc20.x86_64 3/6
Verifying : 1:tcl-8.5.14-1.fc20.x86_64 4/6
Verifying : python-easygui-0.96-7.fc20.noarch 5/6
Verifying : python-setuptools-1.4.2-1.fc20.noarch 6/6

Installed:
python-easygui.noarch 0:0.96-7.fc20

Dependency Installed:
python-setuptools.noarch 0:1.4.2-1.fc20 tcl.x86_64 1:8.5.14-1.fc20
tix.x86_64 1:8.4.3-11.fc20 tk.x86_64 1:8.5.14-1.fc20
tkinter.x86_64 0:2.7.5-16.fc20

Complete!

You can then test the EasyGUI library with the following three lines of code inside the IDLE interpreter:

Python 2.7.5 (default, Apr 10 2015, 08:09:05)
[GCC 4.8.3 20140911 (Red Hat 4.8.3-7)] on linux2
Type “help”, “copyright”, “credits” or “license” for more information.
>>> import easygui
>>> flavor = easygui.enterbox(“What flavor of bum do you like?”)
>>> if easygui.msgbox(“You like ” + flavor + ” gum.”) == ‘OK’:
… print “OK button clicked …”

OK button clicked …

The easygui.enterbox call displays the image below. Enter “Peppermint” in the entry box and click the OK button to assign the “Peppermint” string literal to the flavor variable.

The easygui.msgbox call displays the message below:
When you click the OK button, the program returns an “OK” string to the Python code. It prints the string “OK button clicked …” string:

As always, I hope this helps those looking for instructions and a quick way to play with Python and GUI applications.

Linux User-Group Console

This post shows you how to add the menu option and GUI to set users and groups. It’s quite a bit easier than mastering all the command-line syntax. It makes setting up the required user and group accounts for an Oracle Enterprise or MySQL database solution much easier.
You add the utility by calling the yum (Yellowdog Updater, Modified) utility like this:

yum installed -y system-config_users

You should see the following:

Loaded plugins: langpacks
adobe-linux-x86_64 | 951 B 00:00
ol7_UEKR3 | 1.2 kB 00:00
ol7_latest | 1.4 kB 00:00
Resolving Dependencies
–> Running transaction check
—> Package system-config-users.noarch 0:1.3.5-2.el7 will be installed
–> Processing Dependency: system-config-users-docs for package: system-config-users-1.3.5-2.el7.noarch
–> Running transaction check
—> Package system-config-users-docs.noarch 0:1.0.9-6.el7 will be installed
–> Processing Dependency: rarian-compat for package: system-config-users-docs-1.0.9-6.el7.noarch
–> Running transaction check
—> Package rarian-compat.x86_64 0:0.8.1-11.el7 will be installed
–> Processing Dependency: rarian = 0.8.1-11.el7 for package: rarian-compat-0.8.1-11.el7.x86_64
–> Processing Dependency: rarian for package: rarian-compat-0.8.1-11.el7.x86_64
–> Processing Dependency: librarian.so.0()(64bit) for package: rarian-compat-0.8.1-11.el7.x86_64
–> Running transaction check
—> Package rarian.x86_64 0:0.8.1-11.el7 will be installed
–> Finished Dependency Resolution
 
Dependencies Resolved
 
================================================================================
Package Arch Version Repository Size
================================================================================
Installing:
system-config-users noarch 1.3.5-2.el7 ol7_latest 337 k
Installing for dependencies:
rarian x86_64 0.8.1-11.el7 ol7_latest 97 k
rarian-compat x86_64 0.8.1-11.el7 ol7_latest 65 k
system-config-users-docs noarch 1.0.9-6.el7 ol7_latest 307 k
 
Transaction Summary
================================================================================
Install 1 Package (+3 Dependent packages)
 
Total download size: 805 k
Installed size: 3.9 M
Downloading packages:
(1/4): rarian-0.8.1-11.el7.x86_64.rpm | 97 kB 00:00
(2/4): rarian-compat-0.8.1-11.el7.x86_64.rpm | 65 kB 00:00
(3/4): system-config-users-1.3.5-2.el7.noarch.rpm | 337 kB 00:00
(4/4): system-config-users-docs-1.0.9-6.el7.noarch.rpm | 307 kB 00:00
——————————————————————————–
Total 830 kB/s | 805 kB 00:00
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
Installing : rarian-0.8.1-11.el7.x86_64 1/4
Installing : rarian-compat-0.8.1-11.el7.x86_64 2/4
Installing : system-config-users-1.3.5-2.el7.noarch 3/4
Installing : system-config-users-docs-1.0.9-6.el7.noarch 4/4
Verifying : rarian-compat-0.8.1-11.el7.x86_64 1/4
Verifying : system-config-users-1.3.5-2.el7.noarch 2/4
Verifying : rarian-0.8.1-11.el7.x86_64 3/4
Verifying : system-config-users-docs-1.0.9-6.el7.noarch 4/4
 
Installed:
system-config-users.noarch 0:1.3.5-2.el7
 
Dependency Installed:
rarian.x86_64 0:0.8.1-11.el7
rarian-compat.x86_64 0:0.8.1-11.el7
system-config-users-docs.noarch 0:1.0.9-6.el7
 
Complete!

After successfully installing the radian, rarian-compat, system-config-users, and system-config-users-docs packages, you will find that there’s now a Users and Groups option when you navigate by clicking on Applications and then clicking on Sundry from the menu.
Menu Instructions

You navigate to the Applications menu, and choose Sundry from the menu list and Users and Groups from the menu item to continue.

You will be prompted for the sudoer’s password in this dialog.

At this point, you can use the GUI interface to set users and groups.

As always, I hope this helps those trying to set users and passwords without mastering the command-line syntax.

Fedora LAMP Steps

I posted earlier in the year how to configure a Fedora instance to test PHP code on a local VM. However, I’ve got a few questions on how to find those posts. Here’s a consolidation with links on those steps:

Go to this blog post and install the httpd and php libraries with the yum installer.
In the same blog post as step 1 (you can put the sample PHP code into the /var/www/html directory for testing), connect to the yum shell and remove the php-mysql library and then install the mysqlnd library.
Go to this blog post and install the php-gd libraries, which enable you to render PNG images stored as binary streams in MySQL.

As always, I hope that helps.

Create MySQL Index

Indexes are separate data structures that provide alternate pathways to finding data. They can and do generally speed up the processing of queries and other DML commands, like the INSERT, UPDATE, REPLACE INTO, and DELETE statements. Indexes are also called fast access paths.
In the scope of the InnoDB Database Engine, the MySQL database maintains the integrity of indexes after you create them. The upside of indexes is that they can improve SQL statement performance. The downside is that they impose overhead on every INSERT, UPDATE, REPLACE INTO, and DELETE statement, because the database maintains them by inserting, updating, or deleting items for each related change in the tables that the indexes support.
Indexes have two key properties—usability and visibility. Indexes are both usable and visible by default. That means they are visible to the MySQL cost-based optimizer and usable when statements run against the tables they support.
You have the ability to make any index invisible, in which case queries and DML statements won’t use the index because they won’t see it. However, the cost-based optimizer still sees the index and maintains it with any DML statement change. That means making an index invisible isn’t quite like making the index unusable or like dropping it temporarily. An invisible index becomes overhead and thus is typically a short-term solution to run a resource-intensive statement that behaves better without the index while avoiding the cost of rebuilding it after the statement runs.
It is also possible to make an index unusable, in which case it stops collecting information and becomes obsolete and the database drops its index segment. You rebuild the index when you change it back to a usable index.
Indexes work on the principal of a key. A key is typically a set of columns or expressions on which you can build an index, but it’s possible that a key can be a single column. An index based on a set of columns is a composite, or concatenated, index.
Indexes can be unique or non-unique. You create a unique index anytime you constrain a column by assigning a primary key or unique constraint, but they’re indirect indexes. You create a direct unique index on a single column with the following syntax against two non-unique columns:

1
2
CREATE INDEX common_lookup_u1
ON common_lookup (common_lookup_table) USING BTREE;

You could convert this to a non-unique index on two columns by using this syntax:

1
2
CREATE INDEX common_lookup_u1
ON common_lookup (common_lookup_table, common_lookup_column) USING BTREE;

Making the index unique is straightforward;, you only need to add a UNIQUE key wordk to the CREATE INDEX statement, like

1
2
3
4
CREATE UNIQUE INDEX common_lookup_u1
ON common_lookup ( common_lookup_table
, common_lookup_column
, common_lookup_type) USING BTREE;

Most indexes use a B-tree (balanced tree). A B-tree is composed of three types of blocks—a root branch block for searching next-level blocks, branch blocks for searching other branch blocks, or and leaf blocks that store pointers to row values. B-trees are balanced because all leaf-blocks are at the same level, which means the length of search is the same to any element in the tree. All branch blocks store the minimum key prefix required to make branching decisions through the B-tree.

TEL/電話+86 13764045638
Email service@parnassusdata.com
QQ 47079569