
-- --- src/include/pg_config_manual.h.orig 2004-07-24 22:13:53.000000000 +0200
-- +++ src/include/pg_config_manual.h      2004-07-24 22:14:02.000000000 +0200
-- @@ -53,7 +53,7 @@
--   *
--   * Changing these requires an initdb.
--   */
-- -#define INDEX_MAX_KEYS         32
-- +#define INDEX_MAX_KEYS         64
--  #define FUNC_MAX_ARGS          INDEX_MAX_KEYS
-- 
--  /*

drop function check_update_canlink(ContentType.ContentTypeID%type);

create or replace function check_update_canlink(ContentType.ContentTypeID%type) returns bool as '
declare
	p_ContentTypeID	alias for $1;
	r_ContentType	ContentType%rowtype;
Begin
	-- Check ContentType.CanLink is updated XXX
	select * into r_ContentType from ContentType where ContentTypeID=p_ContentTypeID and CanLink=''f'';
	if found then
		update ContentType set CanLink=''t'' where ContentTypeID=p_ContentTypeID;
		RAISE NOTICE ''CanLink to: %'', r_ContentType.ContentType;
	end if;
        return ''f'';
end;
' language 'PLpgSQL';


\set AUTOCOMMIT off
BEGIN;

drop function addhit( text,text,text,text,inet,text,timestamp,text,text,text,text,text,int4,int4,int4,char(1),text,text,text,text,text,text,text,text,text,text,text,text,text,text,text,text);

drop sequence sessionid_seq;
create sequence sessionid_seq;

drop table timing; -- TIMING
create table timing(diff interval, label text); -- TIMING

drop table addhit;
create table addhit(
	use_timing	bool default 'f', -- TIMING
	track_on_cookie	bool default 't',
	check_duplicate	bool default 't',
	check_canlink	bool default 't'
);
insert into addhit(check_duplicate) values('t');

create or replace function addhit(
text,     text,text,text,inet, --  1...5
text,timestamp,text,text,text, --  6..10
text,     text,int4,int4,int4, -- 11..15
char(1),  text,text,text,text, -- 16..20
text,     text,text,text,text, -- 21..25
text,     text,text,text,text, -- 26..30
text,     text                 -- 31..32
) returns int4 as '
declare
	FormatVersion		alias for $1;
	p_CustomerText		alias for $2; -- pi.dk
	p_ServerName		alias for $3; -- pi.dk
	p_Host			alias for $4; -- www.pi.dk
	p_RemoteIP		alias for $5; -- 12.34.56.78
	p_AuthUser		alias for $6; -- joe
	p_hitDateTime		alias for $7; -- 2002-01-21 14:54:33 +02:00
	p_Method		alias for $8; -- GET
	p_Path			alias for $9; -- /index.php
	p_Query			alias for $10; -- ?q=linux
	p_Protocol		alias for $11; -- HTTP/1.1
	p_FileServed		alias for $12; -- /var/www/htdocs/index.php
	p_Status		alias for $13; -- 200
	p_TransSize		alias for $14; -- 123
	p_TimeToServe		alias for $15; -- 1
	p_Connection		alias for $16; -- +
	p_Referer		alias for $17; -- http://www.google.com/index.php?q=linux
	p_RefererHost		alias for $18; -- www.google.com
	p_RefererPath		alias for $19; -- /index.php
	p_RefererQuery		alias for $20; -- ?q=linux
	p_UserAgent		alias for $21; -- Mozilla/5.....
	p_AcceptLanguage	alias for $22; -- da-dk
	p_Accept		alias for $23; -- text/html...
	p_AcceptEncoding	alias for $24; -- gzip,deflate
	p_AcceptCharset		alias for $25; -- ISO-8859-1....
	p_Via			alias for $26; -- Nokia WAP gateway
	p_Cookie		alias for $27; -- PHPSESSION=ea6bd9....; Test=yes
	p_SetCookie		alias for $28; -- PHPSESSION=ea6bd9....
	p_UserTrack		alias for $29; -- 12.34.5..42423.afd
	p_ContentType		alias for $30; -- text/html
	p_FeedHost		alias for $31; -- rack07.isp.com 192.168.1.7 192.168.1.8
	p_SplitPart		alias for $32; -- below sep with ^A - Limit to PostgreSQL ver. 7.4.3
	--	p_Connection	alias for $32; -- Keep-alive
	--	p_TransferEncoding	alias for $33; -- chunked
	--	p_KeepAlive	alias for $34; -- 300
	--	p_SearchEngine	alias for $35; -- Google
	--	p_SearchWords	alias for $36; -- "Laptop linux"

	v_RefererRec	Referer%rowtype; -- RefererID, Referer, HostNameID, PathID, QueryID
	h		httpLog%rowtype; -- Very short name for the httpLog record
	session_latest	httpLog%rowtype;
	v_addhit		addhit%rowtype;
	v_latestTimeSpent	interval;
	v_ContentTypeTextHtmlID	int4;
	v_RunRef	bool; -- Run Referer Check

	t1 timestamp; -- TIMING
	t2 timestamp; -- TIMING
begin
	h.ReturnCode := 0;
	v_RunRef := ''t''; -- Default: Run tracking with referer
	h.SessionID := null;

	-- Read global variables
	select * into v_addhit from addhit;
	if not found then
		insert into addhit(check_duplicate) values(''f'');
		select * into v_addhit from addhit;
	end if;

	h.StatusID := p_Status;
	h.TransSize := p_TransSize;
	h.TimeToServe := p_TimeToServe;
	h.Connection := p_Connection;

	h.CountryID := -1; -- XXX fix me
	h.CountryIdent := -1; -- XXX fix me

	if v_addhit.use_timing then t1 := timeofday(); end if; -- TIMING
	h.FeedHostID := cg_HostNameID(split_part(p_FeedHost, '' '', 1));
	if v_addhit.use_timing then t2 := timeofday(); insert into timing values(t2-t1, ''Init var h.FeedHostID''); t1 := timeofday(); end if; -- TIMING
	h.ServerNameID	:= cg_HostNameID(p_ServerName);
	if v_addhit.use_timing then t2 := timeofday(); insert into timing values(t2-t1, ''Init var h.ServerNameID''); t1 := timeofday(); end if; -- TIMING
	h.RemoteIPID	:= cg_RemoteIPID(p_RemoteIP);
	if v_addhit.use_timing then t2 := timeofday(); insert into timing values(t2-t1, ''Init var h.RemoteIPID''); t1 := timeofday(); end if; -- TIMING
	h.UserAgentID	:= cg_UserAgentID(p_UserAgent);
	if v_addhit.use_timing then t2 := timeofday(); insert into timing values(t2-t1, ''Init var h.UserAgentID''); t1 := timeofday(); end if; -- TIMING
	h.HostID	:= cg_HostNameID(p_Host);
	if v_addhit.use_timing then t2 := timeofday(); insert into timing values(t2-t1, ''Init var h.HostID''); t1 := timeofday(); end if; -- TIMING
	h.PathID	:= cg_PathID(p_Path);
	if v_addhit.use_timing then t2 := timeofday(); insert into timing values(t2-t1, ''Init var h.PathID''); t1 := timeofday(); end if; -- TIMING
	h.QueryID	:= cg_QueryID(p_Query);
	if v_addhit.use_timing then t2 := timeofday(); insert into timing values(t2-t1, ''Init var h.QueryID''); t1 := timeofday(); end if; -- TIMING

	h.AuthUserID	:= cg_AuthUserID(p_AuthUser);
	h.MethodID	:= cg_MethodID(p_Method);
	h.ProtocolID	:= cg_ProtocolID(p_Protocol);
	h.FileServedID	:= cg_FileServedID(p_FileServed);
	h.AcceptID	:= cg_AcceptID(p_Accept);
	h.AcceptLanguageID	:= cg_AcceptLanguageID(p_AcceptLanguage);
	h.AcceptEncodingID	:= cg_AcceptEncodingID(p_AcceptEncoding);
	h.AcceptCharsetID	:= cg_AcceptCharsetID(p_AcceptCharset);
	h.ViaID		:= cg_ViaID(p_Via);
	h.CookieID	:= cg_CookieID(p_Cookie);
	h.SetCookieID	:= cg_SetCookieID(p_SetCookie);
	if v_addhit.use_timing then t2 := timeofday(); insert into timing values(t2-t1, ''Init var h.10*bulk''); t1 := timeofday(); end if; -- TIMING

	h.ContentTypeID	:= cg_ContentTypeID(p_ContentType);
	if v_addhit.use_timing then t2 := timeofday(); insert into timing values(t2-t1, ''Init var h.ContentTypeID''); t1 := timeofday(); end if; -- TIMING
	v_ContentTypeTextHtmlID := cg_ContentTypeID(''text/html'');
	if v_addhit.use_timing then t2 := timeofday(); insert into timing values(t2-t1, ''Init var v_ContentTypeTextHtmlID''); t1 := timeofday(); end if; -- TIMING
	select * into v_RefererRec from cg_RefererRecord(p_Referer,p_RefererHost,p_RefererPath,p_RefererQuery) as (a int4,b timestamp with time zone,c text,d int4,e int4,f int4);
	if v_addhit.use_timing then t2 := timeofday(); insert into timing values(t2-t1, ''Init var v_RefererRec''); t1 := timeofday(); end if; -- TIMING
	h.RefererID := v_RefererRec.RefererID;
	h.UserTrackID := cg_UserTrackID(p_UserTrack);
	if v_addhit.use_timing then t2 := timeofday(); insert into timing values(t2-t1, ''Init var h.UserTrackID''); end if; -- TIMING

	if v_addhit.check_duplicate then
		if v_addhit.use_timing then t1 := timeofday(); end if; -- TIMING
		-- Check if this hit is already in database
		select * into session_latest from httpLog where
			hitDateTime=p_hitDateTime
			and ServerNameID=h.ServerNameID
			and PathID=h.PathID
			and HostID=h.HostID
			and RemoteIPID=h.RemoteIPID
			and MethodID=h.MethodID
			and PathID=h.PathID
			and QueryID=h.QueryID
			and FileServedID=h.FileServedID
			and StatusID=h.StatusID
			and TransSize=h.TransSize
			and TimeToServe=h.TimeToServe
			and Connection=h.Connection -- spot dubble clickers
			and RefererID=h.RefererID
			and UserAgentID=h.UserAgentID
			and AcceptLanguageID=h.AcceptLanguageID
			and AcceptID=h.AcceptID
			and AcceptEncodingID=h.AcceptEncodingID
			and AcceptCharsetID=h.AcceptCharsetID
			and ViaID=h.ViaID
			and CookieID=h.CookieID
			and SetCookieID=h.SetCookieID
			and ContentTypeID=h.ContentTypeID
			and UserTrackID=h.UserTrackID
			;
		if v_addhit.use_timing then t2 := timeofday(); end if; -- TIMING
		if found then
			if v_addhit.use_timing then insert into timing values(t2-t1, ''Already in db, found''); end if; -- TIMING
			-- We got this hit already, exit.
			--RAISE NOTICE ''Got this already: egrep "%.*%.*%" tou'', p_Host, p_hitDateTime, p_RemoteIP;
			h.ReturnCode := 7;
		else -- TIMING
			if v_addhit.use_timing then insert into timing values(t2-t1, ''Already in db, NOT found''); end if; -- TIMING
		end if;
	end if;

	if h.ReturnCode = 0 then
		-- A new hit which is not in the database.
		-- Check for incoming cookie.
		if length(p_Cookie)>0 then
			-- Incoming valid UserTrack found because incoming cookie
			if v_addhit.use_timing then t1 := timeofday(); end if; -- TIMING
			select * into session_latest from httpLog where
				UserTrackID=h.UserTrackID
				--and RemoteIPID=h.RemoteIPID
 				and hitDateTime > p_hitDateTime-''30 min''::interval
 				and hitDateTime <= p_hitDateTime
				and ContentTypeID=v_ContentTypeTextHtmlID
				and HostID=h.HostID
				order by hitDateTime desc;
			if v_addhit.use_timing then t2 := timeofday(); end if; -- TIMING
			if found then
				if v_addhit.use_timing then insert into timing values(t2-t1, ''Incoming usertrack, found''); end if; -- TIMING
				v_RunRef := ''f'';
				if p_hitDateTime-''30 min''::interval < session_latest.hitDateTime then
					-- Use existing session by usertrack
					h.SessionID := session_latest.SessionID;
					h.TimeSpent := p_hitDateTime - session_latest.hitDateTime;
					h.ReturnCode := 2;
					--RAISE NOTICE ''UserTrack SessionID'';
				end if;
			else -- TIMING
				if v_addhit.use_timing then insert into timing values(t2-t1, ''Incoming usertrack, NOT found''); end if; -- TIMING
			end if;
		end if; -- if length(p_Cookie)>0
		if h.ReturnCode = 0 and length(p_Referer) = 0 then
			v_RunRef := ''f'';
			h.ReturnCode := 4; -- No Cookie and no Referer
			--RAISE NOTICE ''New SessionID, no cookie and no referer'';
		end if;
		if v_RunRef then
			-- No incoming cookie or it was not reliable
			-- Do not run if UserAgent is a robot
			if h.HostID = v_RefererRec.HostNameID then
				-- Requested host is equal to referer host
				if v_addhit.use_timing then t1 := timeofday(); end if; -- TIMING
 				select * into session_latest from httpLog where 
 					RemoteIPID=h.RemoteIPID
 					and HostID=v_RefererRec.HostNameID
 					and PathID=v_RefererRec.PathID
 					and QueryID=v_RefererRec.QueryID
 					and hitDateTime > p_hitDateTime-''30 min''::interval
 					and hitDateTime <= p_hitDateTime
 					and ContentTypeID=v_ContentTypeTextHtmlID
 					and UserAgentID=h.UserAgentID
 					order by hitDateTime desc;
				if found then 		--and p_hitDateTime-''30 min''::interval < session_latest.hitDateTime then
					h.SessionID := session_latest.SessionID;
					h.TimeSpent := p_hitDateTime - session_latest.hitDateTime;
					h.ReturnCode := 3; -- Session created by referer
					--RAISE NOTICE ''SessionID created by referer'';
					if v_addhit.check_canlink then
						perform check_update_canlink(session_latest.ContentTypeID);
					end if;
				else
					h.ReturnCode := 6; -- New session. Referer from same site, but not found
					--RAISE NOTICE ''New SessionID, referer was the same site but not found within given interval'';
				end if;
				if v_addhit.use_timing then t2 := timeofday(); end if; -- TIMING
				if v_addhit.use_timing then insert into timing values(t2-t1, ''Run referer''); end if; -- TIMING
			else
				h.ReturnCode := 5; -- New session. Referer from external site
				--RAISE NOTICE ''New SessionID, referer from external site'';
			end if;
		end if;
		if h.SessionID is null then
			h.SessionID := nextval(''sessionid_seq'');
			if h.ReturnCode = 0 then
				h.ReturnCode := 1;
				--RAISE NOTICE ''New SessionID'';
			end if;
			--if h.SessionID % 10 = 0 then
			--	RAISE NOTICE ''SessionID: %'', h.SessionID;
			--end if;
		end if;

        	-- All set, add new hit
		insert into httpLog(
				ReturnCode, FeedHostID, SessionID, ServerNameID, HostID, RemoteIPID, AuthUserID, 
				hitDateTime, MethodID, PathID, QueryID, ProtocolID, 
				FileServedID, StatusID, TransSize, TimeToServe, TimeSpent, Connection, 
				RefererID, UserAgentID, UserAgentType, AcceptLanguageID, AcceptID, 
				AcceptEncodingID, AcceptCharsetID, ViaID, CookieID, 
				SetCookieID, UserTrackID, ContentTypeID, CountryID, CountryIdent
			)
			values(
				h.ReturnCode, h.FeedHostID, h.SessionID, h.ServerNameID, h.HostID, h.RemoteIPID, h.AuthUserID, 
				p_hitDateTime, h.MethodID, h.PathID, h.QueryID, h.ProtocolID, 
				h.FileServedID, h.StatusID, h.TransSize, h.TimeToServe, h.TimeSpent, h.Connection, 
				h.RefererID, h.UserAgentID, h.UserAgentType, h.AcceptLanguageID, h.AcceptID, 
				h.AcceptEncodingID, h.AcceptCharsetID, h.ViaID, h.CookieID, 
				h.SetCookieID, h.UserTrackID, h.ContentTypeID, h.CountryID, h.CountryIdent
			);
	end if;

	return h.ReturnCode;
  end;
' language 'PLpgSQL';

COMMIT;

comment on function addhit (text,text,text,text,inet,text,timestamp,text,text,text,text,text,int4,int4,int4,char(1),text,text,text,text,text,text,text,text,text,text,text,text,text,text,text,text)
is 'Add one record of log-data to toughlog.
Return codes:
2: UserTrack SessionID
3: Session created by referer
4: No Cookie and no Referer
6: New session. Referer from same site, but not found
5: New session. Referer from external site
7: Dublicate entry. 
';

--drop function test();
create or replace function test()
returns int4 as '
declare

	-- Find what session this is in
	select hitID,SessionID into referer from hit
	 where IPID		= h.IPID
	   and CustomerID	= h.CustomerID
	   and URLID	= h.RefererURLID
	   and hitDateTime	<= p_hitDateTime::timestamp
	   and hitDateTime  > (p_hitDateTime::timestamp 
			  - ''1 hour''::interval)
	 order by HitDateTime desc limit 1;
	if found then
	  -- Refered from a page less than 1 hour ago
	  h.SessionID = referer.SessionID;
	  if p_find_referer = ''1'' then
	    -- This is an HTML-page: Calculate time spent
	-- Find the latest HTML-page in this session
	-- DEBUG
	insert into timing values(timeofday(), p_IPtext, ''find ses'');
	select hitID,SessionID,hitdatetime into session_latest
	  from hit H, MimeType M
	 where SessionID		= h.SessionID
	   and H.MimeTypeID = M.MimeTypeID
	   and MimeTypeText = ''text/html''
	 order by HitDateTime desc limit 1;
	if found then
	  v_latestTimeSpent	:= age(p_hitDateTime,
				   session_latest.hitDateTime);
	      update hit set TimeSpent = v_latestTimeSpent
	   where hitid=session_latest.hitid and TimeSpent = null;
	else
	  -- This should not happen as there is a 
	  insert into debug values(p_IPtext||p_URLText);
	end if; -- if found 
	  end if; -- if p_find_referer = ''1''
	else -- if found then
	  -- No referer: New sessionID
	  h.SessionID = nextval(''Hit_SessionID_seq'');
	end if; -- if found

	-- DEBUG
	insert into timing values(timeofday(), p_IPtext,''preinsert'');

	insert into hit(SessionID,CustomerID,IPID,AuthUser,hitDatetime,
	   HostID,URLID,Status,Size,RefererHostID,RefererURLID,BrowserID,
	   XferTime, MimeTypeID)
	values(
	  h.SessionID,
	  h.CustomerID,
	  h.IPID,
	  p_AuthUser,
	  p_hitDatetime,
	  h.HostID,
	  h.URLID,
	  p_Status,
	  p_Size,
	  v_RefererRec.HostNameID,
	  h.RefererURLID,
	  h.BrowserID,
	  p_XferTime,
	  h.MimeTypeID
	);
	return h.ReturnCode;
  end;
' language 'PLpgSQL';

-- For debugging:
-- create table timing (tim timestamp, why text);
-- insert into timing values(timeofday(), ''got mimIDs''||p_IPtext);
-- select date_part('second',tim),why from timing order by tim desc limit 100

-- create table timing (tim timestamp, which text, why text);
-- insert into timing values(timeofday(), p_IPText, ''got mimIDs'');
-- select date_part('second',tim),which,why from timing order by tim desc limit 100;
